gitifact 0.6.0 → 0.6.2

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 (68) hide show
  1. package/dist/browser/assets/{BottomSheet-BFoM6syr.js → BottomSheet-7C5eiOji.js} +1 -1
  2. package/dist/browser/assets/Grid-D6Cs5W3k.js +1 -0
  3. package/dist/browser/assets/{Icon-DPaLmsmh.js → Icon-EsJf4C7A.js} +3 -3
  4. package/dist/browser/assets/{IconButton-Br-4XhQr.js → IconButton-CgOx1Jog.js} +1 -1
  5. package/dist/browser/assets/{Markdown-Bc6pMi97.js → Markdown-B-gnkr0l.js} +4 -4
  6. package/dist/browser/assets/{MenuBottomSheet-Dgz4h1S7.js → MenuBottomSheet-BOGxMa05.js} +1 -1
  7. package/dist/browser/assets/{MetadataListItem-BjA4nmg3.js → MetadataListItem-CUyEFaPI.js} +1 -1
  8. package/dist/browser/assets/ProgressBarMarkTooltip-C5Moep_o.js +1 -0
  9. package/dist/browser/assets/{Section-Z2PuhE6c.js → Section-BEbhTpxd.js} +1 -1
  10. package/dist/browser/assets/Table-OoWAxVgg.js +3 -0
  11. package/dist/browser/assets/{TimestampHoverCard-BJShn6bb.js → TimestampHoverCard-_VKbn1Py.js} +1 -1
  12. package/dist/browser/assets/{Tooltip-MoU3alsv.js → Tooltip-QZg2pB5o.js} +1 -1
  13. package/dist/browser/assets/about-Jsk-9EI-.js +3 -0
  14. package/dist/browser/assets/activity-gA1jJdpp.js +1 -0
  15. package/dist/browser/assets/appearance-CDQ4fLdE.js +1 -0
  16. package/dist/browser/assets/changelog-CiWFK5pK.js +2 -0
  17. package/dist/browser/assets/{container.stylex-rwI38dw9.js → container.stylex-6OsSOpKw.js} +1 -1
  18. package/dist/browser/assets/{contributors._email-C99eiup4.js → contributors._email-DHQfeuSG.js} +1 -1
  19. package/dist/browser/assets/contributors.index-Bd2NXXUX.js +1 -0
  20. package/dist/browser/assets/document-C8DLwdPF.js +11 -0
  21. package/dist/browser/assets/document-ChObsStB.css +1 -0
  22. package/dist/browser/assets/{features._featureId-BVMBUbIc.js → features._featureId-D69yHwjx.js} +1 -1
  23. package/dist/browser/assets/features.index-Ct7YPi11.js +1 -0
  24. package/dist/browser/assets/git-CStwM7mH.js +1 -0
  25. package/dist/browser/assets/index-DJrBgKkG.css +1 -0
  26. package/dist/browser/assets/index-jPjBDJh1.js +48 -0
  27. package/dist/browser/assets/page-header-Bn6J9gVJ.js +147 -0
  28. package/dist/browser/assets/page-header-ClRsIf4A.css +1 -0
  29. package/dist/browser/assets/product-BSEt07YP.css +1 -0
  30. package/dist/browser/assets/product-Beikpygp.js +10 -0
  31. package/dist/browser/assets/product.index-CMOZsrSy.js +1 -0
  32. package/dist/browser/assets/request-state-DkerHkm2.js +1 -0
  33. package/dist/browser/assets/requirements-D5-_AEko.js +1 -0
  34. package/dist/browser/assets/settings-rKkznd6Q.js +1 -0
  35. package/dist/browser/assets/{themeProps-CkLe5zXY.js → themeProps-CfjLB1h4.js} +1 -1
  36. package/dist/browser/assets/{useClipboard-Cqx6Upy7.js → useClipboard-CTfBnLlg.js} +1 -1
  37. package/dist/browser/assets/useDevWarning-gW8_bNZ_.js +1 -0
  38. package/dist/browser/assets/{useIsomorphicLayoutEffect-BiEJxDg_.js → useIsomorphicLayoutEffect-DByj3svz.js} +1 -1
  39. package/dist/browser/assets/{useMediaQuery-twbHF0pO.js → useMediaQuery-CqJr5z44.js} +1 -1
  40. package/dist/browser/assets/{useScrollLock-D-Y-zHSV.js → useScrollLock-CmZKJxOo.js} +1 -1
  41. package/dist/browser/assets/{wiki-k4dXogJF.js → wiki-Dh9TPhWY.js} +1 -1
  42. package/dist/browser/index.html +25 -25
  43. package/dist/i18n/ko/changelog.md +165 -134
  44. package/dist/main.js +1327 -696
  45. package/package.json +3 -3
  46. package/dist/browser/assets/Grid-C9rNT-fL.js +0 -1
  47. package/dist/browser/assets/ProgressBarMarkTooltip-BxGSd9KS.js +0 -1
  48. package/dist/browser/assets/Table-DodMTw3P.js +0 -3
  49. package/dist/browser/assets/about-CmwTK0Rl.js +0 -3
  50. package/dist/browser/assets/activity-BF4_xkCU.js +0 -1
  51. package/dist/browser/assets/appearance-pAOSjMU4.js +0 -1
  52. package/dist/browser/assets/changelog-Dm-wCZt4.js +0 -2
  53. package/dist/browser/assets/contributors.index-BzPuT_XG.js +0 -1
  54. package/dist/browser/assets/document-CaUvlKcm.css +0 -1
  55. package/dist/browser/assets/document-DcPjYojg.js +0 -11
  56. package/dist/browser/assets/features.index-DAF_MoVe.js +0 -1
  57. package/dist/browser/assets/git-CuBxy8Rl.js +0 -1
  58. package/dist/browser/assets/index-CiEgP5lo.css +0 -1
  59. package/dist/browser/assets/index-w5oyNndb.js +0 -48
  60. package/dist/browser/assets/page-header-DPWfThZo.js +0 -124
  61. package/dist/browser/assets/page-header-DZvVAckA.css +0 -1
  62. package/dist/browser/assets/product-BR5KVGuJ.css +0 -1
  63. package/dist/browser/assets/product-BmoIKtGm.js +0 -8
  64. package/dist/browser/assets/product.index-Fb5sQw1w.js +0 -1
  65. package/dist/browser/assets/request-state-B7pKmdbJ.js +0 -1
  66. package/dist/browser/assets/requirements-DGx4_rNJ.js +0 -1
  67. package/dist/browser/assets/settings-5JQQOYMj.js +0 -1
  68. package/dist/browser/assets/useDevWarning-Dudfg3qF.js +0 -1
package/dist/main.js CHANGED
@@ -4205,11 +4205,11 @@ function parseChangelog(text2) {
4205
4205
  let previous;
4206
4206
  let entry2;
4207
4207
  let section;
4208
- const fail8 = (line, key, values = {}) => new InitError("INVALID_CHANGELOG", t("changelog.atLine", { line, reason: t(key, values) }));
4208
+ const fail9 = (line, key, values = {}) => new InitError("INVALID_CHANGELOG", t("changelog.atLine", { line, reason: t(key, values) }));
4209
4209
  const lines = text2.replace(/\r\n/g, "\n").split("\n");
4210
4210
  const close = (line) => {
4211
4211
  if (entry2 && changelogSections.every((name) => entry2[name].length === 0))
4212
- throw fail8(line, "changelog.emptyVersion", { version: entry2.version });
4212
+ throw fail9(line, "changelog.emptyVersion", { version: entry2.version });
4213
4213
  };
4214
4214
  lines.forEach((raw, index) => {
4215
4215
  const line = index + 1;
@@ -4220,9 +4220,9 @@ function parseChangelog(text2) {
4220
4220
  close(line);
4221
4221
  const core = [Number(version2[1]), Number(version2[2]), Number(version2[3])];
4222
4222
  if (!realDate(Number(version2[4]), Number(version2[5]), Number(version2[6])))
4223
- throw fail8(line, "changelog.invalidDate", { text: raw });
4223
+ throw fail9(line, "changelog.invalidDate", { text: raw });
4224
4224
  if (previous && !(core[0] < previous[0] || core[0] === previous[0] && (core[1] < previous[1] || core[1] === previous[1] && core[2] < previous[2]))) {
4225
- throw fail8(line, "changelog.order", { version: core.join(".") });
4225
+ throw fail9(line, "changelog.order", { version: core.join(".") });
4226
4226
  }
4227
4227
  previous = core;
4228
4228
  section = void 0;
@@ -4233,25 +4233,25 @@ function parseChangelog(text2) {
4233
4233
  const heading = sectionLine.exec(raw);
4234
4234
  if (heading) {
4235
4235
  if (!entry2)
4236
- throw fail8(line, "changelog.sectionBeforeVersion");
4236
+ throw fail9(line, "changelog.sectionBeforeVersion");
4237
4237
  const name = heading[1].toLowerCase();
4238
4238
  if (entry2[name].length > 0)
4239
- throw fail8(line, "changelog.duplicateSection", { section: heading[1] });
4239
+ throw fail9(line, "changelog.duplicateSection", { section: heading[1] });
4240
4240
  section = name;
4241
4241
  return;
4242
4242
  }
4243
4243
  const item = itemLine.exec(raw);
4244
4244
  if (item) {
4245
4245
  if (!entry2 || !section)
4246
- throw fail8(line, "changelog.itemOutsideSection");
4246
+ throw fail9(line, "changelog.itemOutsideSection");
4247
4247
  entry2[section].push(item[1].trimEnd());
4248
4248
  return;
4249
4249
  }
4250
- throw fail8(line, "changelog.unknownLine", { text: raw });
4250
+ throw fail9(line, "changelog.unknownLine", { text: raw });
4251
4251
  });
4252
4252
  close(lines.length);
4253
4253
  if (entries.length === 0)
4254
- throw fail8(1, "changelog.noVersions");
4254
+ throw fail9(1, "changelog.noVersions");
4255
4255
  return entries;
4256
4256
  }
4257
4257
 
@@ -4591,10 +4591,10 @@ function decodeGitLine(buffer) {
4591
4591
  if (!value || value.includes("\0")) return invalid();
4592
4592
  return value;
4593
4593
  }
4594
- function fieldsAndPath(record3, count) {
4594
+ function fieldsAndPath(record3, count2) {
4595
4595
  const fields2 = [];
4596
4596
  let start = 0;
4597
- for (let index = 0; index < count; index++) {
4597
+ for (let index = 0; index < count2; index++) {
4598
4598
  const end = record3.indexOf(" ", start);
4599
4599
  if (end <= start) return invalid();
4600
4600
  fields2.push(record3.slice(start, end));
@@ -4645,7 +4645,7 @@ function parsePorcelain(buffer, format) {
4645
4645
  const modes = fields2.slice(3, conflict ? 7 : 6);
4646
4646
  if (modes.some((mode) => !/^(000000|100644|100755|120000|160000)$/.test(mode))) return invalid();
4647
4647
  const oids = fields2.slice(conflict ? 7 : 6);
4648
- if (oids.some((oid2) => !oidPattern.test(oid2))) return invalid();
4648
+ if (oids.some((oid3) => !oidPattern.test(oid3))) return invalid();
4649
4649
  change2 = { kind: conflict ? "unmerged" : "tracked", path: path3, xy, submodule: submodule(fields2[2]) };
4650
4650
  } else return invalid();
4651
4651
  if (seen.has(change2.path)) return invalid();
@@ -6023,14 +6023,14 @@ function codePointLength(str) {
6023
6023
  const units = str.length;
6024
6024
  if (!highSurrogate.test(str))
6025
6025
  return units;
6026
- let count = units;
6026
+ let count2 = units;
6027
6027
  for (let i = 0; i < units - 1; i++) {
6028
6028
  if ((str.charCodeAt(i) & 64512) === 55296 && (str.charCodeAt(i + 1) & 64512) === 56320) {
6029
- count--;
6029
+ count2--;
6030
6030
  i++;
6031
6031
  }
6032
6032
  }
6033
- return count;
6033
+ return count2;
6034
6034
  }
6035
6035
  function getLengthableOrigin(input2) {
6036
6036
  if (Array.isArray(input2))
@@ -8571,16 +8571,16 @@ var $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => {
8571
8571
  };
8572
8572
  });
8573
8573
  function handleExclusiveUnionResults(results, final, inst, ctx) {
8574
- const matches = [];
8574
+ const matches2 = [];
8575
8575
  for (let i = 0; i < results.length; i++) {
8576
8576
  if (results[i].issues.length === 0)
8577
- matches.push(i);
8577
+ matches2.push(i);
8578
8578
  }
8579
- if (matches.length === 1) {
8580
- final.value = results[matches[0]].value;
8579
+ if (matches2.length === 1) {
8580
+ final.value = results[matches2[0]].value;
8581
8581
  return final;
8582
8582
  }
8583
- if (matches.length === 0) {
8583
+ if (matches2.length === 0) {
8584
8584
  final.issues.push({
8585
8585
  code: "invalid_union",
8586
8586
  input: final.value,
@@ -8594,7 +8594,7 @@ function handleExclusiveUnionResults(results, final, inst, ctx) {
8594
8594
  inst,
8595
8595
  errors: [],
8596
8596
  inclusive: false,
8597
- matches
8597
+ matches: matches2
8598
8598
  });
8599
8599
  }
8600
8600
  return final;
@@ -10385,8 +10385,8 @@ function az_default() {
10385
10385
  }
10386
10386
 
10387
10387
  // ../../node_modules/.pnpm/zod@4.6.4/node_modules/zod/v4/locales/be.js
10388
- function getBelarusianPlural(count, one, few, many) {
10389
- const absCount = Math.abs(count);
10388
+ function getBelarusianPlural(count2, one, few, many) {
10389
+ const absCount = Math.abs(count2);
10390
10390
  const lastDigit = absCount % 10;
10391
10391
  const lastTwoDigits = absCount % 100;
10392
10392
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -13033,8 +13033,8 @@ function hu_default() {
13033
13033
  }
13034
13034
 
13035
13035
  // ../../node_modules/.pnpm/zod@4.6.4/node_modules/zod/v4/locales/hy.js
13036
- function getArmenianPlural(count, one, many) {
13037
- return Math.abs(count) === 1 ? one : many;
13036
+ function getArmenianPlural(count2, one, many) {
13037
+ return Math.abs(count2) === 1 ? one : many;
13038
13038
  }
13039
13039
  function withDefiniteArticle(word) {
13040
13040
  if (!word)
@@ -15772,8 +15772,8 @@ function ro_default() {
15772
15772
  }
15773
15773
 
15774
15774
  // ../../node_modules/.pnpm/zod@4.6.4/node_modules/zod/v4/locales/ru.js
15775
- function getRussianPlural(count, one, few, many) {
15776
- const absCount = Math.abs(count);
15775
+ function getRussianPlural(count2, one, few, many) {
15776
+ const absCount = Math.abs(count2);
15777
15777
  const lastDigit = absCount % 10;
15778
15778
  const lastTwoDigits = absCount % 100;
15779
15779
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -20407,13 +20407,13 @@ function initializeContext(params) {
20407
20407
  external: params?.external ?? void 0
20408
20408
  };
20409
20409
  }
20410
- function handleUnrepresentable(schema, ctx, json2, params, message) {
20410
+ function handleUnrepresentable(schema, ctx, json3, params, message) {
20411
20411
  const result = typeof ctx.unrepresentable === "function" ? ctx.unrepresentable({ zodSchema: schema, path: params.path, message }) : ctx.unrepresentable;
20412
20412
  if (result === "any")
20413
20413
  return false;
20414
20414
  if (result === void 0 || result === "throw")
20415
20415
  throw new Error(message);
20416
- Object.assign(json2, result);
20416
+ Object.assign(json3, result);
20417
20417
  return true;
20418
20418
  }
20419
20419
  function processSchema(schema, ctx, _params = { path: [], schemaPath: [] }) {
@@ -20649,12 +20649,12 @@ function foldObjects(members2) {
20649
20649
  }
20650
20650
  return folded;
20651
20651
  }
20652
- function foldIntersection(json2) {
20653
- const allOf = json2.allOf;
20652
+ function foldIntersection(json3) {
20653
+ const allOf = json3.allOf;
20654
20654
  if (!Array.isArray(allOf) || allOf.length < 2)
20655
20655
  return;
20656
20656
  for (const key of FOLDABLE_KEYS)
20657
- if (key in json2)
20657
+ if (key in json3)
20658
20658
  return;
20659
20659
  const unions = allOf.filter((m) => UNION_KEYS.some((k) => Array.isArray(m[k])));
20660
20660
  let folded = null;
@@ -20673,8 +20673,8 @@ function foldIntersection(json2) {
20673
20673
  }
20674
20674
  if (!folded)
20675
20675
  return;
20676
- delete json2.allOf;
20677
- assignProps(json2, folded);
20676
+ delete json3.allOf;
20677
+ assignProps(json3, folded);
20678
20678
  }
20679
20679
  function finalize(ctx, schema) {
20680
20680
  const root = ctx.seen.get(schema);
@@ -20756,20 +20756,20 @@ function finalize(ctx, schema) {
20756
20756
  if (ctx.intersections.length) {
20757
20757
  const carriers = /* @__PURE__ */ new Map();
20758
20758
  for (const seen of ctx.seen.values()) {
20759
- for (const json2 of [seen.schema, seen.def]) {
20760
- const allOf = json2?.allOf;
20759
+ for (const json3 of [seen.schema, seen.def]) {
20760
+ const allOf = json3?.allOf;
20761
20761
  if (!Array.isArray(allOf))
20762
20762
  continue;
20763
20763
  const existing = carriers.get(allOf);
20764
20764
  if (existing)
20765
- existing.push(json2);
20765
+ existing.push(json3);
20766
20766
  else
20767
- carriers.set(allOf, [json2]);
20767
+ carriers.set(allOf, [json3]);
20768
20768
  }
20769
20769
  }
20770
20770
  for (const allOf of ctx.intersections) {
20771
- for (const json2 of carriers.get(allOf) ?? [])
20772
- foldIntersection(json2);
20771
+ for (const json3 of carriers.get(allOf) ?? [])
20772
+ foldIntersection(json3);
20773
20773
  }
20774
20774
  }
20775
20775
  }
@@ -21004,29 +21004,29 @@ var exactPatterns = /* @__PURE__ */ new Map([
21004
21004
  ]);
21005
21005
  var exactPattern = (p) => exactPatterns.get(p) ?? p;
21006
21006
  var stringProcessor = (schema, ctx, _json, _params) => {
21007
- const json2 = _json;
21008
- json2.type = "string";
21007
+ const json3 = _json;
21008
+ json3.type = "string";
21009
21009
  const { minimum, maximum, format, patterns, contentEncoding, laxFormat } = aggregateChecks(schema);
21010
21010
  if (typeof minimum === "number")
21011
- json2.minLength = minimum;
21011
+ json3.minLength = minimum;
21012
21012
  if (typeof maximum === "number")
21013
- json2.maxLength = maximum;
21013
+ json3.maxLength = maximum;
21014
21014
  if (format) {
21015
- json2.format = formatMap[format] ?? format;
21016
- if (json2.format === "")
21017
- delete json2.format;
21015
+ json3.format = formatMap[format] ?? format;
21016
+ if (json3.format === "")
21017
+ delete json3.format;
21018
21018
  if (format === "time" || laxFormat) {
21019
- delete json2.format;
21019
+ delete json3.format;
21020
21020
  }
21021
21021
  }
21022
21022
  if (contentEncoding)
21023
- json2.contentEncoding = contentEncoding;
21023
+ json3.contentEncoding = contentEncoding;
21024
21024
  if (patterns && patterns.size > 0) {
21025
21025
  const patternList = [...patterns].map(exactPattern);
21026
21026
  if (patternList.length === 1)
21027
- json2.pattern = patternList[0].source;
21027
+ json3.pattern = patternList[0].source;
21028
21028
  else if (patternList.length > 1) {
21029
- json2.allOf = [
21029
+ json3.allOf = [
21030
21030
  ...patternList.map((regex) => ({
21031
21031
  ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {},
21032
21032
  pattern: regex.source
@@ -21036,31 +21036,31 @@ var stringProcessor = (schema, ctx, _json, _params) => {
21036
21036
  }
21037
21037
  };
21038
21038
  var numberProcessor = (schema, ctx, _json, params) => {
21039
- const json2 = _json;
21039
+ const json3 = _json;
21040
21040
  const { minimum, maximum, multipleOf, exclusiveMaximum, exclusiveMinimum, isInt } = aggregateChecks(schema);
21041
- json2.type = isInt ? "integer" : "number";
21041
+ json3.type = isInt ? "integer" : "number";
21042
21042
  const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
21043
21043
  const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
21044
21044
  const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
21045
21045
  if (exMin) {
21046
21046
  if (legacy) {
21047
- json2.minimum = exclusiveMinimum;
21048
- json2.exclusiveMinimum = true;
21047
+ json3.minimum = exclusiveMinimum;
21048
+ json3.exclusiveMinimum = true;
21049
21049
  } else {
21050
- json2.exclusiveMinimum = exclusiveMinimum;
21050
+ json3.exclusiveMinimum = exclusiveMinimum;
21051
21051
  }
21052
21052
  } else if (typeof minimum === "number") {
21053
- json2.minimum = minimum;
21053
+ json3.minimum = minimum;
21054
21054
  }
21055
21055
  if (exMax) {
21056
21056
  if (legacy) {
21057
- json2.maximum = exclusiveMaximum;
21058
- json2.exclusiveMaximum = true;
21057
+ json3.maximum = exclusiveMaximum;
21058
+ json3.exclusiveMaximum = true;
21059
21059
  } else {
21060
- json2.exclusiveMaximum = exclusiveMaximum;
21060
+ json3.exclusiveMaximum = exclusiveMaximum;
21061
21061
  }
21062
21062
  } else if (typeof maximum === "number") {
21063
- json2.maximum = maximum;
21063
+ json3.maximum = maximum;
21064
21064
  }
21065
21065
  if (multipleOf) {
21066
21066
  const divisors = /* @__PURE__ */ new Set();
@@ -21068,75 +21068,75 @@ var numberProcessor = (schema, ctx, _json, params) => {
21068
21068
  if (Number.isFinite(divisor) && divisor !== 0)
21069
21069
  divisors.add(Math.abs(divisor));
21070
21070
  else
21071
- handleUnrepresentable(schema, ctx, json2, params, `A multipleOf divisor of ${divisor} cannot be represented in JSON Schema`);
21071
+ handleUnrepresentable(schema, ctx, json3, params, `A multipleOf divisor of ${divisor} cannot be represented in JSON Schema`);
21072
21072
  }
21073
21073
  const [first, ...rest] = divisors;
21074
21074
  if (first !== void 0)
21075
- json2.multipleOf = first;
21075
+ json3.multipleOf = first;
21076
21076
  if (rest.length)
21077
- json2.allOf = [...json2.allOf ?? [], ...rest.map((m) => ({ multipleOf: m }))];
21077
+ json3.allOf = [...json3.allOf ?? [], ...rest.map((m) => ({ multipleOf: m }))];
21078
21078
  }
21079
21079
  };
21080
- var booleanProcessor = (_schema, _ctx, json2, _params) => {
21081
- json2.type = "boolean";
21080
+ var booleanProcessor = (_schema, _ctx, json3, _params) => {
21081
+ json3.type = "boolean";
21082
21082
  };
21083
- var bigintProcessor = (schema, ctx, json2, params) => {
21084
- handleUnrepresentable(schema, ctx, json2, params, "BigInt cannot be represented in JSON Schema");
21083
+ var bigintProcessor = (schema, ctx, json3, params) => {
21084
+ handleUnrepresentable(schema, ctx, json3, params, "BigInt cannot be represented in JSON Schema");
21085
21085
  };
21086
- var symbolProcessor = (schema, ctx, json2, params) => {
21087
- handleUnrepresentable(schema, ctx, json2, params, "Symbols cannot be represented in JSON Schema");
21086
+ var symbolProcessor = (schema, ctx, json3, params) => {
21087
+ handleUnrepresentable(schema, ctx, json3, params, "Symbols cannot be represented in JSON Schema");
21088
21088
  };
21089
- var nullProcessor = (_schema, ctx, json2, _params) => {
21089
+ var nullProcessor = (_schema, ctx, json3, _params) => {
21090
21090
  if (ctx.target === "openapi-3.0") {
21091
- json2.type = "string";
21092
- json2.nullable = true;
21093
- json2.enum = [null];
21091
+ json3.type = "string";
21092
+ json3.nullable = true;
21093
+ json3.enum = [null];
21094
21094
  } else {
21095
- json2.type = "null";
21095
+ json3.type = "null";
21096
21096
  }
21097
21097
  };
21098
- var undefinedProcessor = (schema, ctx, json2, params) => {
21099
- handleUnrepresentable(schema, ctx, json2, params, "Undefined cannot be represented in JSON Schema");
21098
+ var undefinedProcessor = (schema, ctx, json3, params) => {
21099
+ handleUnrepresentable(schema, ctx, json3, params, "Undefined cannot be represented in JSON Schema");
21100
21100
  };
21101
- var voidProcessor = (schema, ctx, json2, params) => {
21102
- handleUnrepresentable(schema, ctx, json2, params, "Void cannot be represented in JSON Schema");
21101
+ var voidProcessor = (schema, ctx, json3, params) => {
21102
+ handleUnrepresentable(schema, ctx, json3, params, "Void cannot be represented in JSON Schema");
21103
21103
  };
21104
- var neverProcessor = (_schema, _ctx, json2, _params) => {
21105
- json2.not = {};
21104
+ var neverProcessor = (_schema, _ctx, json3, _params) => {
21105
+ json3.not = {};
21106
21106
  };
21107
21107
  var anyProcessor = (_schema, _ctx, _json, _params) => {
21108
21108
  };
21109
21109
  var unknownProcessor = (_schema, _ctx, _json, _params) => {
21110
21110
  };
21111
- var dateProcessor = (schema, ctx, json2, params) => {
21112
- handleUnrepresentable(schema, ctx, json2, params, "Date cannot be represented in JSON Schema");
21111
+ var dateProcessor = (schema, ctx, json3, params) => {
21112
+ handleUnrepresentable(schema, ctx, json3, params, "Date cannot be represented in JSON Schema");
21113
21113
  };
21114
- var enumProcessor = (schema, _ctx, json2, _params) => {
21114
+ var enumProcessor = (schema, _ctx, json3, _params) => {
21115
21115
  const def = schema._zod.def;
21116
21116
  const values = getEnumValues(def.entries);
21117
21117
  if (values.length === 0) {
21118
- json2.not = {};
21118
+ json3.not = {};
21119
21119
  return;
21120
21120
  }
21121
21121
  if (values.every((v) => typeof v === "number"))
21122
- json2.type = "number";
21122
+ json3.type = "number";
21123
21123
  if (values.every((v) => typeof v === "string"))
21124
- json2.type = "string";
21125
- json2.enum = values;
21124
+ json3.type = "string";
21125
+ json3.enum = values;
21126
21126
  };
21127
- var literalProcessor = (schema, ctx, json2, params) => {
21127
+ var literalProcessor = (schema, ctx, json3, params) => {
21128
21128
  const def = schema._zod.def;
21129
21129
  if (def.values.length === 0) {
21130
- json2.not = {};
21130
+ json3.not = {};
21131
21131
  return;
21132
21132
  }
21133
21133
  const vals = [];
21134
21134
  for (const val of def.values) {
21135
21135
  if (val === void 0) {
21136
- if (handleUnrepresentable(schema, ctx, json2, params, "Literal `undefined` cannot be represented in JSON Schema"))
21136
+ if (handleUnrepresentable(schema, ctx, json3, params, "Literal `undefined` cannot be represented in JSON Schema"))
21137
21137
  return;
21138
21138
  } else if (typeof val === "bigint") {
21139
- if (handleUnrepresentable(schema, ctx, json2, params, "BigInt literals cannot be represented in JSON Schema"))
21139
+ if (handleUnrepresentable(schema, ctx, json3, params, "BigInt literals cannot be represented in JSON Schema"))
21140
21140
  return;
21141
21141
  vals.push(Number(val));
21142
21142
  } else {
@@ -21146,37 +21146,37 @@ var literalProcessor = (schema, ctx, json2, params) => {
21146
21146
  if (vals.length === 0) {
21147
21147
  } else if (vals.length === 1) {
21148
21148
  const val = vals[0];
21149
- json2.type = val === null ? "null" : typeof val;
21149
+ json3.type = val === null ? "null" : typeof val;
21150
21150
  if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
21151
- json2.enum = [val];
21151
+ json3.enum = [val];
21152
21152
  } else {
21153
- json2.const = val;
21153
+ json3.const = val;
21154
21154
  }
21155
21155
  } else {
21156
21156
  if (vals.every((v) => typeof v === "number"))
21157
- json2.type = "number";
21157
+ json3.type = "number";
21158
21158
  if (vals.every((v) => typeof v === "string"))
21159
- json2.type = "string";
21159
+ json3.type = "string";
21160
21160
  if (vals.every((v) => typeof v === "boolean"))
21161
- json2.type = "boolean";
21161
+ json3.type = "boolean";
21162
21162
  if (vals.every((v) => v === null))
21163
- json2.type = "null";
21164
- json2.enum = vals;
21163
+ json3.type = "null";
21164
+ json3.enum = vals;
21165
21165
  }
21166
21166
  };
21167
- var nanProcessor = (schema, ctx, json2, params) => {
21168
- handleUnrepresentable(schema, ctx, json2, params, "NaN cannot be represented in JSON Schema");
21167
+ var nanProcessor = (schema, ctx, json3, params) => {
21168
+ handleUnrepresentable(schema, ctx, json3, params, "NaN cannot be represented in JSON Schema");
21169
21169
  };
21170
- var templateLiteralProcessor = (schema, _ctx, json2, _params) => {
21171
- const _json = json2;
21170
+ var templateLiteralProcessor = (schema, _ctx, json3, _params) => {
21171
+ const _json = json3;
21172
21172
  const pattern = schema._zod.pattern;
21173
21173
  if (!pattern)
21174
21174
  throw new Error("Pattern not found in template literal");
21175
21175
  _json.type = "string";
21176
21176
  _json.pattern = pattern.source;
21177
21177
  };
21178
- var fileProcessor = (schema, _ctx, json2, _params) => {
21179
- const _json = json2;
21178
+ var fileProcessor = (schema, _ctx, json3, _params) => {
21179
+ const _json = json3;
21180
21180
  _json.type = "string";
21181
21181
  _json.format = "binary";
21182
21182
  _json.contentEncoding = "binary";
@@ -21194,34 +21194,34 @@ var fileProcessor = (schema, _ctx, json2, _params) => {
21194
21194
  else
21195
21195
  _json.anyOf = mime.map((m) => ({ contentMediaType: m }));
21196
21196
  };
21197
- var successProcessor = (_schema, _ctx, json2, _params) => {
21198
- json2.type = "boolean";
21197
+ var successProcessor = (_schema, _ctx, json3, _params) => {
21198
+ json3.type = "boolean";
21199
21199
  };
21200
- var customProcessor = (schema, ctx, json2, params) => {
21201
- handleUnrepresentable(schema, ctx, json2, params, "Custom types cannot be represented in JSON Schema");
21200
+ var customProcessor = (schema, ctx, json3, params) => {
21201
+ handleUnrepresentable(schema, ctx, json3, params, "Custom types cannot be represented in JSON Schema");
21202
21202
  };
21203
- var functionProcessor = (schema, ctx, json2, params) => {
21204
- handleUnrepresentable(schema, ctx, json2, params, "Function types cannot be represented in JSON Schema");
21203
+ var functionProcessor = (schema, ctx, json3, params) => {
21204
+ handleUnrepresentable(schema, ctx, json3, params, "Function types cannot be represented in JSON Schema");
21205
21205
  };
21206
- var transformProcessor = (schema, ctx, json2, params) => {
21207
- handleUnrepresentable(schema, ctx, json2, params, "Transforms cannot be represented in JSON Schema");
21206
+ var transformProcessor = (schema, ctx, json3, params) => {
21207
+ handleUnrepresentable(schema, ctx, json3, params, "Transforms cannot be represented in JSON Schema");
21208
21208
  };
21209
- var mapProcessor = (schema, ctx, json2, params) => {
21210
- handleUnrepresentable(schema, ctx, json2, params, "Map cannot be represented in JSON Schema");
21209
+ var mapProcessor = (schema, ctx, json3, params) => {
21210
+ handleUnrepresentable(schema, ctx, json3, params, "Map cannot be represented in JSON Schema");
21211
21211
  };
21212
- var setProcessor = (schema, ctx, json2, params) => {
21213
- handleUnrepresentable(schema, ctx, json2, params, "Set cannot be represented in JSON Schema");
21212
+ var setProcessor = (schema, ctx, json3, params) => {
21213
+ handleUnrepresentable(schema, ctx, json3, params, "Set cannot be represented in JSON Schema");
21214
21214
  };
21215
21215
  var arrayProcessor = (schema, ctx, _json, params) => {
21216
- const json2 = _json;
21216
+ const json3 = _json;
21217
21217
  const def = schema._zod.def;
21218
21218
  const { minimum, maximum } = aggregateChecks(schema);
21219
21219
  if (typeof minimum === "number")
21220
- json2.minItems = minimum;
21220
+ json3.minItems = minimum;
21221
21221
  if (typeof maximum === "number")
21222
- json2.maxItems = maximum;
21223
- json2.type = "array";
21224
- json2.items = processSchema(def.element, ctx, {
21222
+ json3.maxItems = maximum;
21223
+ json3.type = "array";
21224
+ json3.items = processSchema(def.element, ctx, {
21225
21225
  ...params,
21226
21226
  path: [...params.path, "items"]
21227
21227
  });
@@ -21237,17 +21237,17 @@ function inputOptin(schema) {
21237
21237
  return schema._zod.optin;
21238
21238
  }
21239
21239
  var objectProcessor = (schema, ctx, _json, params) => {
21240
- const json2 = _json;
21240
+ const json3 = _json;
21241
21241
  const def = schema._zod.def;
21242
21242
  const shape = def.shape;
21243
21243
  const symbolKeys = Object.getOwnPropertySymbols(shape);
21244
- if (symbolKeys.length && handleUnrepresentable(schema, ctx, json2, params, "Symbol keys cannot be represented in JSON Schema")) {
21244
+ if (symbolKeys.length && handleUnrepresentable(schema, ctx, json3, params, "Symbol keys cannot be represented in JSON Schema")) {
21245
21245
  return;
21246
21246
  }
21247
- json2.type = "object";
21248
- json2.properties = {};
21247
+ json3.type = "object";
21248
+ json3.properties = {};
21249
21249
  for (const key in shape) {
21250
- assignProp(json2.properties, key, processSchema(shape[key], ctx, {
21250
+ assignProp(json3.properties, key, processSchema(shape[key], ctx, {
21251
21251
  ...params,
21252
21252
  path: [...params.path, "properties", key]
21253
21253
  }));
@@ -21260,21 +21260,21 @@ var objectProcessor = (schema, ctx, _json, params) => {
21260
21260
  }
21261
21261
  }
21262
21262
  if (requiredKeys.length > 0) {
21263
- json2.required = requiredKeys;
21263
+ json3.required = requiredKeys;
21264
21264
  }
21265
21265
  if (def.catchall?._zod.def.type === "never") {
21266
- json2.additionalProperties = false;
21266
+ json3.additionalProperties = false;
21267
21267
  } else if (!def.catchall) {
21268
21268
  if (ctx.io === "output")
21269
- json2.additionalProperties = false;
21269
+ json3.additionalProperties = false;
21270
21270
  } else if (def.catchall) {
21271
- json2.additionalProperties = processSchema(def.catchall, ctx, {
21271
+ json3.additionalProperties = processSchema(def.catchall, ctx, {
21272
21272
  ...params,
21273
21273
  path: [...params.path, "additionalProperties"]
21274
21274
  });
21275
21275
  }
21276
21276
  };
21277
- var unionProcessor = (schema, ctx, json2, params) => {
21277
+ var unionProcessor = (schema, ctx, json3, params) => {
21278
21278
  const def = schema._zod.def;
21279
21279
  const isExclusive = def.inclusive === false;
21280
21280
  const options = def.options.map((x, i) => processSchema(x, ctx, {
@@ -21282,12 +21282,12 @@ var unionProcessor = (schema, ctx, json2, params) => {
21282
21282
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
21283
21283
  }));
21284
21284
  if (isExclusive) {
21285
- json2.oneOf = options;
21285
+ json3.oneOf = options;
21286
21286
  } else {
21287
- json2.anyOf = options;
21287
+ json3.anyOf = options;
21288
21288
  }
21289
21289
  };
21290
- var intersectionProcessor = (schema, ctx, json2, params) => {
21290
+ var intersectionProcessor = (schema, ctx, json3, params) => {
21291
21291
  const def = schema._zod.def;
21292
21292
  const a = processSchema(def.left, ctx, {
21293
21293
  ...params,
@@ -21302,13 +21302,13 @@ var intersectionProcessor = (schema, ctx, json2, params) => {
21302
21302
  ...isSimpleIntersection(a) ? a.allOf : [a],
21303
21303
  ...isSimpleIntersection(b) ? b.allOf : [b]
21304
21304
  ];
21305
- json2.allOf = allOf;
21305
+ json3.allOf = allOf;
21306
21306
  ctx.intersections.push(allOf);
21307
21307
  };
21308
21308
  var tupleProcessor = (schema, ctx, _json, params) => {
21309
- const json2 = _json;
21309
+ const json3 = _json;
21310
21310
  const def = schema._zod.def;
21311
- json2.type = "array";
21311
+ json3.type = "array";
21312
21312
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
21313
21313
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
21314
21314
  const prefixItems = def.items.map((x, i) => processSchema(x, ctx, {
@@ -21330,70 +21330,70 @@ var tupleProcessor = (schema, ctx, _json, params) => {
21330
21330
  const maxItems = def.items.length;
21331
21331
  const isClosed = !def.rest;
21332
21332
  if (ctx.target === "draft-2020-12") {
21333
- json2.prefixItems = prefixItems;
21333
+ json3.prefixItems = prefixItems;
21334
21334
  if (isClosed) {
21335
- json2.items = false;
21335
+ json3.items = false;
21336
21336
  } else if (rest) {
21337
- json2.items = rest;
21337
+ json3.items = rest;
21338
21338
  }
21339
21339
  if (minItems > 0)
21340
- json2.minItems = minItems;
21340
+ json3.minItems = minItems;
21341
21341
  if (isClosed)
21342
- json2.maxItems = maxItems;
21342
+ json3.maxItems = maxItems;
21343
21343
  } else if (ctx.target === "openapi-3.0") {
21344
- json2.items = {
21344
+ json3.items = {
21345
21345
  anyOf: prefixItems
21346
21346
  };
21347
21347
  if (rest) {
21348
- json2.items.anyOf.push(rest);
21348
+ json3.items.anyOf.push(rest);
21349
21349
  }
21350
21350
  if (minItems > 0)
21351
- json2.minItems = minItems;
21351
+ json3.minItems = minItems;
21352
21352
  if (isClosed)
21353
- json2.maxItems = maxItems;
21353
+ json3.maxItems = maxItems;
21354
21354
  } else {
21355
- json2.items = prefixItems;
21355
+ json3.items = prefixItems;
21356
21356
  if (isClosed) {
21357
- json2.additionalItems = false;
21357
+ json3.additionalItems = false;
21358
21358
  } else if (rest) {
21359
- json2.additionalItems = rest;
21359
+ json3.additionalItems = rest;
21360
21360
  }
21361
21361
  if (minItems > 0)
21362
- json2.minItems = minItems;
21362
+ json3.minItems = minItems;
21363
21363
  if (isClosed)
21364
- json2.maxItems = maxItems;
21364
+ json3.maxItems = maxItems;
21365
21365
  }
21366
21366
  const { minimum, maximum } = aggregateChecks(schema);
21367
21367
  if (typeof minimum === "number")
21368
- json2.minItems = minimum;
21368
+ json3.minItems = minimum;
21369
21369
  if (typeof maximum === "number")
21370
- json2.maxItems = maximum;
21370
+ json3.maxItems = maximum;
21371
21371
  };
21372
- function stringifyKeyNames(bySchema, json2, visited) {
21373
- if (json2.$ref) {
21374
- if (visited.has(json2))
21375
- return json2;
21376
- visited.add(json2);
21377
- const def = bySchema.get(json2)?.def;
21372
+ function stringifyKeyNames(bySchema, json3, visited) {
21373
+ if (json3.$ref) {
21374
+ if (visited.has(json3))
21375
+ return json3;
21376
+ visited.add(json3);
21377
+ const def = bySchema.get(json3)?.def;
21378
21378
  if (!def)
21379
- return json2;
21379
+ return json3;
21380
21380
  const inlined = stringifyKeyNames(bySchema, def, visited);
21381
- return inlined === def ? json2 : inlined;
21381
+ return inlined === def ? json3 : inlined;
21382
21382
  }
21383
21383
  for (const keyword of ["anyOf", "oneOf"]) {
21384
- const branches = json2[keyword];
21384
+ const branches = json3[keyword];
21385
21385
  if (!Array.isArray(branches))
21386
21386
  continue;
21387
21387
  const mapped = branches.map((branch) => stringifyKeyNames(bySchema, branch, visited));
21388
21388
  if (mapped.some((branch, i) => branch !== branches[i]))
21389
- json2 = { ...json2, [keyword]: mapped };
21389
+ json3 = { ...json3, [keyword]: mapped };
21390
21390
  }
21391
- const types = Array.isArray(json2.type) ? json2.type : [json2.type];
21391
+ const types = Array.isArray(json3.type) ? json3.type : [json3.type];
21392
21392
  const numericType = !types.includes("string") && types.some((t3) => t3 === "number" || t3 === "integer");
21393
- const values = json2.enum ?? (json2.const !== void 0 ? [json2.const] : void 0);
21393
+ const values = json3.enum ?? (json3.const !== void 0 ? [json3.const] : void 0);
21394
21394
  if (!numericType && !values?.some((v) => typeof v === "number"))
21395
- return json2;
21396
- const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, format, id, ...rest } = json2;
21395
+ return json3;
21396
+ const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, format, id, ...rest } = json3;
21397
21397
  if (rest.enum)
21398
21398
  rest.enum = rest.enum.map((v) => typeof v === "number" ? String(v) : v);
21399
21399
  else if (typeof rest.const === "number")
@@ -21433,9 +21433,9 @@ function rewriteKeyNames(ctx) {
21433
21433
  }
21434
21434
  }
21435
21435
  var recordProcessor = (schema, ctx, _json, params) => {
21436
- const json2 = _json;
21436
+ const json3 = _json;
21437
21437
  const def = schema._zod.def;
21438
- json2.type = "object";
21438
+ json3.type = "object";
21439
21439
  const keyType = def.keyType;
21440
21440
  const patterns = aggregateChecks(keyType).patterns;
21441
21441
  if (def.mode === "loose" && patterns && patterns.size > 0) {
@@ -21443,13 +21443,13 @@ var recordProcessor = (schema, ctx, _json, params) => {
21443
21443
  ...params,
21444
21444
  path: [...params.path, "patternProperties", "*"]
21445
21445
  });
21446
- json2.patternProperties = {};
21446
+ json3.patternProperties = {};
21447
21447
  for (const pattern of patterns) {
21448
- assignProp(json2.patternProperties, exactPattern(pattern).source, valueSchema);
21448
+ assignProp(json3.patternProperties, exactPattern(pattern).source, valueSchema);
21449
21449
  }
21450
21450
  } else {
21451
21451
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
21452
- json2.propertyNames = processSchema(def.keyType, ctx, {
21452
+ json3.propertyNames = processSchema(def.keyType, ctx, {
21453
21453
  ...params,
21454
21454
  path: [...params.path, "propertyNames"]
21455
21455
  });
@@ -21461,7 +21461,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
21461
21461
  }
21462
21462
  pending.push(schema);
21463
21463
  }
21464
- json2.additionalProperties = processSchema(def.valueType, ctx, {
21464
+ json3.additionalProperties = processSchema(def.valueType, ctx, {
21465
21465
  ...params,
21466
21466
  path: [...params.path, "additionalProperties"]
21467
21467
  });
@@ -21471,19 +21471,19 @@ var recordProcessor = (schema, ctx, _json, params) => {
21471
21471
  if (keyValues && !def.partial && !omittableOnInput) {
21472
21472
  const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
21473
21473
  if (validKeyValues.length > 0) {
21474
- json2.required = validKeyValues.map(String);
21474
+ json3.required = validKeyValues.map(String);
21475
21475
  }
21476
21476
  }
21477
21477
  };
21478
- var nullableProcessor = (schema, ctx, json2, params) => {
21478
+ var nullableProcessor = (schema, ctx, json3, params) => {
21479
21479
  const def = schema._zod.def;
21480
21480
  const inner = processSchema(def.innerType, ctx, params);
21481
21481
  const seen = ctx.seen.get(schema);
21482
21482
  if (ctx.target === "openapi-3.0") {
21483
21483
  seen.ref = def.innerType;
21484
- json2.nullable = true;
21484
+ json3.nullable = true;
21485
21485
  } else {
21486
- json2.anyOf = [inner, { type: "null" }];
21486
+ json3.anyOf = [inner, { type: "null" }];
21487
21487
  }
21488
21488
  };
21489
21489
  var nonoptionalProcessor = (schema, ctx, _json, params) => {
@@ -21493,7 +21493,7 @@ var nonoptionalProcessor = (schema, ctx, _json, params) => {
21493
21493
  seen.ref = def.innerType;
21494
21494
  };
21495
21495
  var UNREPRESENTABLE_DEFAULT = /* @__PURE__ */ Symbol();
21496
- function serializeDefaultValue(value, schema, ctx, json2, params) {
21496
+ function serializeDefaultValue(value, schema, ctx, json3, params) {
21497
21497
  let unrepresentable = false;
21498
21498
  const serialized = JSON.stringify(value, (_, val) => {
21499
21499
  if (typeof val !== "bigint")
@@ -21503,30 +21503,30 @@ function serializeDefaultValue(value, schema, ctx, json2, params) {
21503
21503
  });
21504
21504
  if (!unrepresentable)
21505
21505
  return JSON.parse(serialized);
21506
- handleUnrepresentable(schema, ctx, json2, params, "BigInt defaults cannot be represented in JSON Schema");
21506
+ handleUnrepresentable(schema, ctx, json3, params, "BigInt defaults cannot be represented in JSON Schema");
21507
21507
  return UNREPRESENTABLE_DEFAULT;
21508
21508
  }
21509
- var defaultProcessor = (schema, ctx, json2, params) => {
21509
+ var defaultProcessor = (schema, ctx, json3, params) => {
21510
21510
  const def = schema._zod.def;
21511
21511
  processSchema(def.innerType, ctx, params);
21512
21512
  const seen = ctx.seen.get(schema);
21513
21513
  seen.ref = def.innerType;
21514
- const value = serializeDefaultValue(def.defaultValue, schema, ctx, json2, params);
21514
+ const value = serializeDefaultValue(def.defaultValue, schema, ctx, json3, params);
21515
21515
  if (value !== UNREPRESENTABLE_DEFAULT)
21516
- json2.default = value;
21516
+ json3.default = value;
21517
21517
  };
21518
- var prefaultProcessor = (schema, ctx, json2, params) => {
21518
+ var prefaultProcessor = (schema, ctx, json3, params) => {
21519
21519
  const def = schema._zod.def;
21520
21520
  processSchema(def.innerType, ctx, params);
21521
21521
  const seen = ctx.seen.get(schema);
21522
21522
  seen.ref = def.innerType;
21523
21523
  if (ctx.io !== "input")
21524
21524
  return;
21525
- const value = serializeDefaultValue(def.defaultValue, schema, ctx, json2, params);
21525
+ const value = serializeDefaultValue(def.defaultValue, schema, ctx, json3, params);
21526
21526
  if (value !== UNREPRESENTABLE_DEFAULT)
21527
- json2._prefault = value;
21527
+ json3._prefault = value;
21528
21528
  };
21529
- var catchProcessor = (schema, ctx, json2, params) => {
21529
+ var catchProcessor = (schema, ctx, json3, params) => {
21530
21530
  const def = schema._zod.def;
21531
21531
  processSchema(def.innerType, ctx, params);
21532
21532
  const seen = ctx.seen.get(schema);
@@ -21535,10 +21535,10 @@ var catchProcessor = (schema, ctx, json2, params) => {
21535
21535
  try {
21536
21536
  catchValue = def.catchValue(void 0);
21537
21537
  } catch {
21538
- handleUnrepresentable(schema, ctx, json2, params, "Dynamic catch values are not supported in JSON Schema");
21538
+ handleUnrepresentable(schema, ctx, json3, params, "Dynamic catch values are not supported in JSON Schema");
21539
21539
  return;
21540
21540
  }
21541
- json2.default = catchValue;
21541
+ json3.default = catchValue;
21542
21542
  };
21543
21543
  var pipeProcessor = (schema, ctx, _json, params) => {
21544
21544
  const def = schema._zod.def;
@@ -21548,12 +21548,12 @@ var pipeProcessor = (schema, ctx, _json, params) => {
21548
21548
  const seen = ctx.seen.get(schema);
21549
21549
  seen.ref = innerType;
21550
21550
  };
21551
- var readonlyProcessor = (schema, ctx, json2, params) => {
21551
+ var readonlyProcessor = (schema, ctx, json3, params) => {
21552
21552
  const def = schema._zod.def;
21553
21553
  processSchema(def.innerType, ctx, params);
21554
21554
  const seen = ctx.seen.get(schema);
21555
21555
  seen.ref = def.innerType;
21556
- json2.readOnly = true;
21556
+ json3.readOnly = true;
21557
21557
  };
21558
21558
  var promiseProcessor = (schema, ctx, _json, params) => {
21559
21559
  const def = schema._zod.def;
@@ -22195,7 +22195,7 @@ var _ZodString = /* @__PURE__ */ $constructor(
22195
22195
  (inst, def) => {
22196
22196
  $ZodString.init(inst, def);
22197
22197
  ZodType.init(inst, def);
22198
- inst._zod.processJSONSchema = (ctx, json2, params) => stringProcessor(inst, ctx, json2, params);
22198
+ inst._zod.processJSONSchema = (ctx, json3, params) => stringProcessor(inst, ctx, json3, params);
22199
22199
  },
22200
22200
  /* @__PURE__ */ util_exports.derived({
22201
22201
  format: (inst) => aggregateChecks(inst).format ?? null,
@@ -22554,7 +22554,7 @@ var ZodNumber = /* @__PURE__ */ $constructor(
22554
22554
  (inst, def) => {
22555
22555
  $ZodNumber.init(inst, def);
22556
22556
  ZodType.init(inst, def);
22557
- inst._zod.processJSONSchema = (ctx, json2, params) => numberProcessor(inst, ctx, json2, params);
22557
+ inst._zod.processJSONSchema = (ctx, json3, params) => numberProcessor(inst, ctx, json3, params);
22558
22558
  inst.isFinite = true;
22559
22559
  },
22560
22560
  /* @__PURE__ */ util_exports.derived({
@@ -22644,7 +22644,7 @@ function uint32(params) {
22644
22644
  var ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
22645
22645
  $ZodBoolean.init(inst, def);
22646
22646
  ZodType.init(inst, def);
22647
- inst._zod.processJSONSchema = (ctx, json2, params) => booleanProcessor(inst, ctx, json2, params);
22647
+ inst._zod.processJSONSchema = (ctx, json3, params) => booleanProcessor(inst, ctx, json3, params);
22648
22648
  });
22649
22649
  function boolean2(params) {
22650
22650
  return _boolean(ZodBoolean, params);
@@ -22654,7 +22654,7 @@ var ZodBigInt = /* @__PURE__ */ $constructor(
22654
22654
  (inst, def) => {
22655
22655
  $ZodBigInt.init(inst, def);
22656
22656
  ZodType.init(inst, def);
22657
- inst._zod.processJSONSchema = (ctx, json2, params) => bigintProcessor(inst, ctx, json2, params);
22657
+ inst._zod.processJSONSchema = (ctx, json3, params) => bigintProcessor(inst, ctx, json3, params);
22658
22658
  },
22659
22659
  /* @__PURE__ */ util_exports.derived({
22660
22660
  minValue: (inst) => aggregateChecks(inst).minimum ?? null,
@@ -22712,7 +22712,7 @@ function uint64(params) {
22712
22712
  var ZodSymbol = /* @__PURE__ */ $constructor("ZodSymbol", (inst, def) => {
22713
22713
  $ZodSymbol.init(inst, def);
22714
22714
  ZodType.init(inst, def);
22715
- inst._zod.processJSONSchema = (ctx, json2, params) => symbolProcessor(inst, ctx, json2, params);
22715
+ inst._zod.processJSONSchema = (ctx, json3, params) => symbolProcessor(inst, ctx, json3, params);
22716
22716
  });
22717
22717
  function symbol(params) {
22718
22718
  return _symbol(ZodSymbol, params);
@@ -22720,7 +22720,7 @@ function symbol(params) {
22720
22720
  var ZodUndefined = /* @__PURE__ */ $constructor("ZodUndefined", (inst, def) => {
22721
22721
  $ZodUndefined.init(inst, def);
22722
22722
  ZodType.init(inst, def);
22723
- inst._zod.processJSONSchema = (ctx, json2, params) => undefinedProcessor(inst, ctx, json2, params);
22723
+ inst._zod.processJSONSchema = (ctx, json3, params) => undefinedProcessor(inst, ctx, json3, params);
22724
22724
  });
22725
22725
  function _undefined3(params) {
22726
22726
  return _undefined2(ZodUndefined, params);
@@ -22728,7 +22728,7 @@ function _undefined3(params) {
22728
22728
  var ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
22729
22729
  $ZodNull.init(inst, def);
22730
22730
  ZodType.init(inst, def);
22731
- inst._zod.processJSONSchema = (ctx, json2, params) => nullProcessor(inst, ctx, json2, params);
22731
+ inst._zod.processJSONSchema = (ctx, json3, params) => nullProcessor(inst, ctx, json3, params);
22732
22732
  });
22733
22733
  function _null3(params) {
22734
22734
  return _null2(ZodNull, params);
@@ -22736,7 +22736,7 @@ function _null3(params) {
22736
22736
  var ZodAny = /* @__PURE__ */ $constructor("ZodAny", (inst, def) => {
22737
22737
  $ZodAny.init(inst, def);
22738
22738
  ZodType.init(inst, def);
22739
- inst._zod.processJSONSchema = (ctx, json2, params) => anyProcessor(inst, ctx, json2, params);
22739
+ inst._zod.processJSONSchema = (ctx, json3, params) => anyProcessor(inst, ctx, json3, params);
22740
22740
  });
22741
22741
  function any() {
22742
22742
  return _any(ZodAny);
@@ -22744,7 +22744,7 @@ function any() {
22744
22744
  var ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
22745
22745
  $ZodUnknown.init(inst, def);
22746
22746
  ZodType.init(inst, def);
22747
- inst._zod.processJSONSchema = (ctx, json2, params) => unknownProcessor(inst, ctx, json2, params);
22747
+ inst._zod.processJSONSchema = (ctx, json3, params) => unknownProcessor(inst, ctx, json3, params);
22748
22748
  });
22749
22749
  function unknown() {
22750
22750
  return _unknown(ZodUnknown);
@@ -22752,7 +22752,7 @@ function unknown() {
22752
22752
  var ZodNever = /* @__PURE__ */ $constructor("ZodNever", (inst, def) => {
22753
22753
  $ZodNever.init(inst, def);
22754
22754
  ZodType.init(inst, def);
22755
- inst._zod.processJSONSchema = (ctx, json2, params) => neverProcessor(inst, ctx, json2, params);
22755
+ inst._zod.processJSONSchema = (ctx, json3, params) => neverProcessor(inst, ctx, json3, params);
22756
22756
  });
22757
22757
  function never(params) {
22758
22758
  return _never(ZodNever, params);
@@ -22760,7 +22760,7 @@ function never(params) {
22760
22760
  var ZodVoid = /* @__PURE__ */ $constructor("ZodVoid", (inst, def) => {
22761
22761
  $ZodVoid.init(inst, def);
22762
22762
  ZodType.init(inst, def);
22763
- inst._zod.processJSONSchema = (ctx, json2, params) => voidProcessor(inst, ctx, json2, params);
22763
+ inst._zod.processJSONSchema = (ctx, json3, params) => voidProcessor(inst, ctx, json3, params);
22764
22764
  });
22765
22765
  function _void2(params) {
22766
22766
  return _void(ZodVoid, params);
@@ -22770,7 +22770,7 @@ var ZodDate = /* @__PURE__ */ $constructor(
22770
22770
  (inst, def) => {
22771
22771
  $ZodDate.init(inst, def);
22772
22772
  ZodType.init(inst, def);
22773
- inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params);
22773
+ inst._zod.processJSONSchema = (ctx, json3, params) => dateProcessor(inst, ctx, json3, params);
22774
22774
  inst.min = (value, params) => inst.check(_gte(value, params));
22775
22775
  inst.max = (value, params) => inst.check(_lte(value, params));
22776
22776
  },
@@ -22792,7 +22792,7 @@ var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
22792
22792
  _ensureDefaultMemoizer();
22793
22793
  $ZodArray.init(inst, def);
22794
22794
  ZodType.init(inst, def);
22795
- inst._zod.processJSONSchema = (ctx, json2, params) => arrayProcessor(inst, ctx, json2, params);
22795
+ inst._zod.processJSONSchema = (ctx, json3, params) => arrayProcessor(inst, ctx, json3, params);
22796
22796
  inst.element = def.element;
22797
22797
  }, {
22798
22798
  min(n, params) {
@@ -22822,7 +22822,7 @@ var ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
22822
22822
  _ensureDefaultMemoizer();
22823
22823
  $ZodObjectJIT.init(inst, def);
22824
22824
  ZodType.init(inst, def);
22825
- inst._zod.processJSONSchema = (ctx, json2, params) => objectProcessor(inst, ctx, json2, params);
22825
+ inst._zod.processJSONSchema = (ctx, json3, params) => objectProcessor(inst, ctx, json3, params);
22826
22826
  util_exports.installLazyProp(inst, "shape", (self) => self._zod.def.shape, false);
22827
22827
  }, {
22828
22828
  keyof() {
@@ -22895,7 +22895,7 @@ function looseObject(shape, params) {
22895
22895
  var ZodUnion = /* @__PURE__ */ $constructor("ZodUnion", (inst, def) => {
22896
22896
  $ZodUnion.init(inst, def);
22897
22897
  ZodType.init(inst, def);
22898
- inst._zod.processJSONSchema = (ctx, json2, params) => unionProcessor(inst, ctx, json2, params);
22898
+ inst._zod.processJSONSchema = (ctx, json3, params) => unionProcessor(inst, ctx, json3, params);
22899
22899
  inst.options = def.options;
22900
22900
  });
22901
22901
  function union(options, params) {
@@ -22908,7 +22908,7 @@ function union(options, params) {
22908
22908
  var ZodXor = /* @__PURE__ */ $constructor("ZodXor", (inst, def) => {
22909
22909
  ZodUnion.init(inst, def);
22910
22910
  $ZodXor.init(inst, def);
22911
- inst._zod.processJSONSchema = (ctx, json2, params) => unionProcessor(inst, ctx, json2, params);
22911
+ inst._zod.processJSONSchema = (ctx, json3, params) => unionProcessor(inst, ctx, json3, params);
22912
22912
  inst.options = def.options;
22913
22913
  });
22914
22914
  function xor(options, params) {
@@ -22934,7 +22934,7 @@ function discriminatedUnion(discriminator, options, params) {
22934
22934
  var ZodIntersection = /* @__PURE__ */ $constructor("ZodIntersection", (inst, def) => {
22935
22935
  $ZodIntersection.init(inst, def);
22936
22936
  ZodType.init(inst, def);
22937
- inst._zod.processJSONSchema = (ctx, json2, params) => intersectionProcessor(inst, ctx, json2, params);
22937
+ inst._zod.processJSONSchema = (ctx, json3, params) => intersectionProcessor(inst, ctx, json3, params);
22938
22938
  });
22939
22939
  function intersection(left, right) {
22940
22940
  return new ZodIntersection({
@@ -22947,7 +22947,7 @@ var ZodTuple = /* @__PURE__ */ $constructor("ZodTuple", (inst, def) => {
22947
22947
  _ensureDefaultMemoizer();
22948
22948
  $ZodTuple.init(inst, def);
22949
22949
  ZodType.init(inst, def);
22950
- inst._zod.processJSONSchema = (ctx, json2, params) => tupleProcessor(inst, ctx, json2, params);
22950
+ inst._zod.processJSONSchema = (ctx, json3, params) => tupleProcessor(inst, ctx, json3, params);
22951
22951
  }, {
22952
22952
  rest(rest) {
22953
22953
  return this.clone({
@@ -22980,7 +22980,7 @@ var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
22980
22980
  _ensureDefaultMemoizer();
22981
22981
  $ZodRecord.init(inst, def);
22982
22982
  ZodType.init(inst, def);
22983
- inst._zod.processJSONSchema = (ctx, json2, params) => recordProcessor(inst, ctx, json2, params);
22983
+ inst._zod.processJSONSchema = (ctx, json3, params) => recordProcessor(inst, ctx, json3, params);
22984
22984
  inst.keyType = def.keyType;
22985
22985
  inst.valueType = def.valueType;
22986
22986
  });
@@ -23022,7 +23022,7 @@ var ZodMap = /* @__PURE__ */ $constructor("ZodMap", (inst, def) => {
23022
23022
  _ensureDefaultMemoizer();
23023
23023
  $ZodMap.init(inst, def);
23024
23024
  ZodType.init(inst, def);
23025
- inst._zod.processJSONSchema = (ctx, json2, params) => mapProcessor(inst, ctx, json2, params);
23025
+ inst._zod.processJSONSchema = (ctx, json3, params) => mapProcessor(inst, ctx, json3, params);
23026
23026
  inst.keyType = def.keyType;
23027
23027
  inst.valueType = def.valueType;
23028
23028
  inst.min = (...args) => inst.check(_minSize(...args));
@@ -23042,7 +23042,7 @@ var ZodSet = /* @__PURE__ */ $constructor("ZodSet", (inst, def) => {
23042
23042
  _ensureDefaultMemoizer();
23043
23043
  $ZodSet.init(inst, def);
23044
23044
  ZodType.init(inst, def);
23045
- inst._zod.processJSONSchema = (ctx, json2, params) => setProcessor(inst, ctx, json2, params);
23045
+ inst._zod.processJSONSchema = (ctx, json3, params) => setProcessor(inst, ctx, json3, params);
23046
23046
  inst.min = (...args) => inst.check(_minSize(...args));
23047
23047
  inst.nonempty = (params) => inst.check(_minSize(1, params));
23048
23048
  inst.max = (...args) => inst.check(_maxSize(...args));
@@ -23058,7 +23058,7 @@ function set(valueType, params) {
23058
23058
  var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
23059
23059
  $ZodEnum.init(inst, def);
23060
23060
  ZodType.init(inst, def);
23061
- inst._zod.processJSONSchema = (ctx, json2, params) => enumProcessor(inst, ctx, json2, params);
23061
+ inst._zod.processJSONSchema = (ctx, json3, params) => enumProcessor(inst, ctx, json3, params);
23062
23062
  inst.enum = def.entries;
23063
23063
  inst.options = [...inst._zod.values];
23064
23064
  const keys2 = new Set(Object.keys(def.entries));
@@ -23111,7 +23111,7 @@ function nativeEnum(entries, params) {
23111
23111
  var ZodLiteral = /* @__PURE__ */ $constructor("ZodLiteral", (inst, def) => {
23112
23112
  $ZodLiteral.init(inst, def);
23113
23113
  ZodType.init(inst, def);
23114
- inst._zod.processJSONSchema = (ctx, json2, params) => literalProcessor(inst, ctx, json2, params);
23114
+ inst._zod.processJSONSchema = (ctx, json3, params) => literalProcessor(inst, ctx, json3, params);
23115
23115
  inst.values = new Set(def.values);
23116
23116
  Object.defineProperty(inst, "value", {
23117
23117
  get() {
@@ -23132,7 +23132,7 @@ function literal(value, params) {
23132
23132
  var ZodFile = /* @__PURE__ */ $constructor("ZodFile", (inst, def) => {
23133
23133
  $ZodFile.init(inst, def);
23134
23134
  ZodType.init(inst, def);
23135
- inst._zod.processJSONSchema = (ctx, json2, params) => fileProcessor(inst, ctx, json2, params);
23135
+ inst._zod.processJSONSchema = (ctx, json3, params) => fileProcessor(inst, ctx, json3, params);
23136
23136
  inst.min = (size, params) => inst.check(_minSize(size, params));
23137
23137
  inst.max = (size, params) => inst.check(_maxSize(size, params));
23138
23138
  inst.mime = (types, params) => inst.check(_mime(Array.isArray(types) ? types : [types], params));
@@ -23144,7 +23144,7 @@ var ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => {
23144
23144
  _ensureDefaultMemoizer();
23145
23145
  $ZodTransform.init(inst, def);
23146
23146
  ZodType.init(inst, def);
23147
- inst._zod.processJSONSchema = (ctx, json2, params) => transformProcessor(inst, ctx, json2, params);
23147
+ inst._zod.processJSONSchema = (ctx, json3, params) => transformProcessor(inst, ctx, json3, params);
23148
23148
  inst._zod.parse = (payload, _ctx) => {
23149
23149
  if (_ctx.direction === "backward") {
23150
23150
  throw new $ZodEncodeError(inst.constructor.name);
@@ -23183,7 +23183,7 @@ function transform(fn) {
23183
23183
  var ZodOptional = /* @__PURE__ */ $constructor("ZodOptional", (inst, def) => {
23184
23184
  $ZodOptional.init(inst, def);
23185
23185
  ZodType.init(inst, def);
23186
- inst._zod.processJSONSchema = (ctx, json2, params) => optionalProcessor(inst, ctx, json2, params);
23186
+ inst._zod.processJSONSchema = (ctx, json3, params) => optionalProcessor(inst, ctx, json3, params);
23187
23187
  inst.unwrap = () => inst._zod.def.innerType;
23188
23188
  });
23189
23189
  function optional(innerType) {
@@ -23195,7 +23195,7 @@ function optional(innerType) {
23195
23195
  var ZodExactOptional = /* @__PURE__ */ $constructor("ZodExactOptional", (inst, def) => {
23196
23196
  $ZodExactOptional.init(inst, def);
23197
23197
  ZodType.init(inst, def);
23198
- inst._zod.processJSONSchema = (ctx, json2, params) => optionalProcessor(inst, ctx, json2, params);
23198
+ inst._zod.processJSONSchema = (ctx, json3, params) => optionalProcessor(inst, ctx, json3, params);
23199
23199
  inst.unwrap = () => inst._zod.def.innerType;
23200
23200
  });
23201
23201
  function exactOptional(innerType) {
@@ -23207,7 +23207,7 @@ function exactOptional(innerType) {
23207
23207
  var ZodNullable = /* @__PURE__ */ $constructor("ZodNullable", (inst, def) => {
23208
23208
  $ZodNullable.init(inst, def);
23209
23209
  ZodType.init(inst, def);
23210
- inst._zod.processJSONSchema = (ctx, json2, params) => nullableProcessor(inst, ctx, json2, params);
23210
+ inst._zod.processJSONSchema = (ctx, json3, params) => nullableProcessor(inst, ctx, json3, params);
23211
23211
  inst.unwrap = () => inst._zod.def.innerType;
23212
23212
  });
23213
23213
  function nullable(innerType) {
@@ -23222,7 +23222,7 @@ function nullish2(innerType) {
23222
23222
  var ZodDefault = /* @__PURE__ */ $constructor("ZodDefault", (inst, def) => {
23223
23223
  $ZodDefault.init(inst, def);
23224
23224
  ZodType.init(inst, def);
23225
- inst._zod.processJSONSchema = (ctx, json2, params) => defaultProcessor(inst, ctx, json2, params);
23225
+ inst._zod.processJSONSchema = (ctx, json3, params) => defaultProcessor(inst, ctx, json3, params);
23226
23226
  inst.unwrap = () => inst._zod.def.innerType;
23227
23227
  inst.removeDefault = inst.unwrap;
23228
23228
  });
@@ -23238,7 +23238,7 @@ function _default2(innerType, defaultValue) {
23238
23238
  var ZodPrefault = /* @__PURE__ */ $constructor("ZodPrefault", (inst, def) => {
23239
23239
  $ZodPrefault.init(inst, def);
23240
23240
  ZodType.init(inst, def);
23241
- inst._zod.processJSONSchema = (ctx, json2, params) => prefaultProcessor(inst, ctx, json2, params);
23241
+ inst._zod.processJSONSchema = (ctx, json3, params) => prefaultProcessor(inst, ctx, json3, params);
23242
23242
  inst.unwrap = () => inst._zod.def.innerType;
23243
23243
  });
23244
23244
  function prefault(innerType, defaultValue) {
@@ -23253,7 +23253,7 @@ function prefault(innerType, defaultValue) {
23253
23253
  var ZodNonOptional = /* @__PURE__ */ $constructor("ZodNonOptional", (inst, def) => {
23254
23254
  $ZodNonOptional.init(inst, def);
23255
23255
  ZodType.init(inst, def);
23256
- inst._zod.processJSONSchema = (ctx, json2, params) => nonoptionalProcessor(inst, ctx, json2, params);
23256
+ inst._zod.processJSONSchema = (ctx, json3, params) => nonoptionalProcessor(inst, ctx, json3, params);
23257
23257
  inst.unwrap = () => inst._zod.def.innerType;
23258
23258
  });
23259
23259
  function nonoptional(innerType, params) {
@@ -23266,7 +23266,7 @@ function nonoptional(innerType, params) {
23266
23266
  var ZodSuccess = /* @__PURE__ */ $constructor("ZodSuccess", (inst, def) => {
23267
23267
  $ZodSuccess.init(inst, def);
23268
23268
  ZodType.init(inst, def);
23269
- inst._zod.processJSONSchema = (ctx, json2, params) => successProcessor(inst, ctx, json2, params);
23269
+ inst._zod.processJSONSchema = (ctx, json3, params) => successProcessor(inst, ctx, json3, params);
23270
23270
  inst.unwrap = () => inst._zod.def.innerType;
23271
23271
  });
23272
23272
  function success(innerType) {
@@ -23278,7 +23278,7 @@ function success(innerType) {
23278
23278
  var ZodCatch = /* @__PURE__ */ $constructor("ZodCatch", (inst, def) => {
23279
23279
  $ZodCatch.init(inst, def);
23280
23280
  ZodType.init(inst, def);
23281
- inst._zod.processJSONSchema = (ctx, json2, params) => catchProcessor(inst, ctx, json2, params);
23281
+ inst._zod.processJSONSchema = (ctx, json3, params) => catchProcessor(inst, ctx, json3, params);
23282
23282
  inst.unwrap = () => inst._zod.def.innerType;
23283
23283
  inst.removeCatch = inst.unwrap;
23284
23284
  });
@@ -23292,7 +23292,7 @@ function _catch2(innerType, catchValue) {
23292
23292
  var ZodNaN = /* @__PURE__ */ $constructor("ZodNaN", (inst, def) => {
23293
23293
  $ZodNaN.init(inst, def);
23294
23294
  ZodType.init(inst, def);
23295
- inst._zod.processJSONSchema = (ctx, json2, params) => nanProcessor(inst, ctx, json2, params);
23295
+ inst._zod.processJSONSchema = (ctx, json3, params) => nanProcessor(inst, ctx, json3, params);
23296
23296
  });
23297
23297
  function nan(params) {
23298
23298
  return _nan(ZodNaN, params);
@@ -23300,7 +23300,7 @@ function nan(params) {
23300
23300
  var ZodPipe = /* @__PURE__ */ $constructor("ZodPipe", (inst, def) => {
23301
23301
  $ZodPipe.init(inst, def);
23302
23302
  ZodType.init(inst, def);
23303
- inst._zod.processJSONSchema = (ctx, json2, params) => pipeProcessor(inst, ctx, json2, params);
23303
+ inst._zod.processJSONSchema = (ctx, json3, params) => pipeProcessor(inst, ctx, json3, params);
23304
23304
  inst.in = def.in;
23305
23305
  inst.out = def.out;
23306
23306
  });
@@ -23342,7 +23342,7 @@ var ZodPreprocess = /* @__PURE__ */ $constructor("ZodPreprocess", (inst, def) =>
23342
23342
  var ZodReadonly = /* @__PURE__ */ $constructor("ZodReadonly", (inst, def) => {
23343
23343
  $ZodReadonly.init(inst, def);
23344
23344
  ZodType.init(inst, def);
23345
- inst._zod.processJSONSchema = (ctx, json2, params) => readonlyProcessor(inst, ctx, json2, params);
23345
+ inst._zod.processJSONSchema = (ctx, json3, params) => readonlyProcessor(inst, ctx, json3, params);
23346
23346
  inst.unwrap = () => inst._zod.def.innerType;
23347
23347
  });
23348
23348
  function readonly(innerType) {
@@ -23354,7 +23354,7 @@ function readonly(innerType) {
23354
23354
  var ZodTemplateLiteral = /* @__PURE__ */ $constructor("ZodTemplateLiteral", (inst, def) => {
23355
23355
  $ZodTemplateLiteral.init(inst, def);
23356
23356
  ZodType.init(inst, def);
23357
- inst._zod.processJSONSchema = (ctx, json2, params) => templateLiteralProcessor(inst, ctx, json2, params);
23357
+ inst._zod.processJSONSchema = (ctx, json3, params) => templateLiteralProcessor(inst, ctx, json3, params);
23358
23358
  });
23359
23359
  function templateLiteral(parts, params) {
23360
23360
  return new ZodTemplateLiteral({
@@ -23366,7 +23366,7 @@ function templateLiteral(parts, params) {
23366
23366
  var ZodLazy = /* @__PURE__ */ $constructor("ZodLazy", (inst, def) => {
23367
23367
  $ZodLazy.init(inst, def);
23368
23368
  ZodType.init(inst, def);
23369
- inst._zod.processJSONSchema = (ctx, json2, params) => lazyProcessor(inst, ctx, json2, params);
23369
+ inst._zod.processJSONSchema = (ctx, json3, params) => lazyProcessor(inst, ctx, json3, params);
23370
23370
  inst.unwrap = () => inst._zod.def.getter();
23371
23371
  });
23372
23372
  function lazy(getter) {
@@ -23378,7 +23378,7 @@ function lazy(getter) {
23378
23378
  var ZodPromise = /* @__PURE__ */ $constructor("ZodPromise", (inst, def) => {
23379
23379
  $ZodPromise.init(inst, def);
23380
23380
  ZodType.init(inst, def);
23381
- inst._zod.processJSONSchema = (ctx, json2, params) => promiseProcessor(inst, ctx, json2, params);
23381
+ inst._zod.processJSONSchema = (ctx, json3, params) => promiseProcessor(inst, ctx, json3, params);
23382
23382
  inst.unwrap = () => inst._zod.def.innerType;
23383
23383
  });
23384
23384
  function promise(innerType) {
@@ -23390,7 +23390,7 @@ function promise(innerType) {
23390
23390
  var ZodFunction = /* @__PURE__ */ $constructor("ZodFunction", (inst, def) => {
23391
23391
  $ZodFunction.init(inst, def);
23392
23392
  ZodType.init(inst, def);
23393
- inst._zod.processJSONSchema = (ctx, json2, params) => functionProcessor(inst, ctx, json2, params);
23393
+ inst._zod.processJSONSchema = (ctx, json3, params) => functionProcessor(inst, ctx, json3, params);
23394
23394
  });
23395
23395
  function _function(params) {
23396
23396
  return new ZodFunction({
@@ -23402,7 +23402,7 @@ function _function(params) {
23402
23402
  var ZodCustom = /* @__PURE__ */ $constructor("ZodCustom", (inst, def) => {
23403
23403
  $ZodCustom.init(inst, def);
23404
23404
  ZodType.init(inst, def);
23405
- inst._zod.processJSONSchema = (ctx, json2, params) => customProcessor(inst, ctx, json2, params);
23405
+ inst._zod.processJSONSchema = (ctx, json3, params) => customProcessor(inst, ctx, json3, params);
23406
23406
  });
23407
23407
  function check(fn) {
23408
23408
  const ch = new $ZodCheck({
@@ -23793,20 +23793,20 @@ function checkArrayGuards(arraySchema, guards) {
23793
23793
  if (guards.containsSchema) {
23794
23794
  const minContains = guards.minContains ?? 1;
23795
23795
  const ceiling = guards.maxContains !== void 0 ? guards.maxContains + 1 : Number.POSITIVE_INFINITY;
23796
- let matches = 0;
23796
+ let matches2 = 0;
23797
23797
  for (const item of items2) {
23798
- if (guards.containsSchema.safeParse(item).success && ++matches >= ceiling)
23798
+ if (guards.containsSchema.safeParse(item).success && ++matches2 >= ceiling)
23799
23799
  break;
23800
23800
  }
23801
- if (matches < minContains) {
23801
+ if (matches2 < minContains) {
23802
23802
  payload.issues.push({
23803
23803
  code: "custom",
23804
- message: `Array must contain at least ${minContains} matching ${plural(minContains)}; found ${matches}`,
23804
+ message: `Array must contain at least ${minContains} matching ${plural(minContains)}; found ${matches2}`,
23805
23805
  input: items2,
23806
23806
  continue: true
23807
23807
  });
23808
23808
  }
23809
- if (guards.maxContains !== void 0 && matches > guards.maxContains) {
23809
+ if (guards.maxContains !== void 0 && matches2 > guards.maxContains) {
23810
23810
  payload.issues.push({
23811
23811
  code: "custom",
23812
23812
  message: `Array must contain at most ${guards.maxContains} matching ${plural(guards.maxContains)}`,
@@ -24631,7 +24631,7 @@ var projectInitV5 = external_exports.discriminatedUnion("ok", [
24631
24631
  external_exports.strictObject({ contract: external_exports.literal("project-init"), version: external_exports.literal(5), ok: external_exports.literal(false), error: external_exports.strictObject({ code: external_exports.string(), message: external_exports.string() }) })
24632
24632
  ]);
24633
24633
 
24634
- // ../../packages/contracts/dist/versions/browser-specs-v3.js
24634
+ // ../../packages/contracts/dist/versions/browser-specs-v4.js
24635
24635
  var requirement = external_exports.strictObject({ id: external_exports.string(), title: external_exports.string(), body: external_exports.string() });
24636
24636
  var contributor = external_exports.strictObject({ email: external_exports.string(), name: external_exports.string(), commits: external_exports.number().int().nonnegative(), latest: external_exports.string() });
24637
24637
  var source = external_exports.strictObject({ title: external_exports.string(), path: external_exports.string().optional(), url: external_exports.string().optional(), note: external_exports.string().optional() });
@@ -24646,45 +24646,103 @@ var feature = external_exports.strictObject({
24646
24646
  contributors: external_exports.array(contributor),
24647
24647
  updatedAt: external_exports.string().nullable()
24648
24648
  });
24649
- var snapshot = requirement.extend({ specId: external_exports.string(), path: external_exports.string(), sources: external_exports.array(source).optional() }).nullable();
24650
24649
  var document = external_exports.strictObject({ id: external_exports.string(), path: external_exports.string(), title: external_exports.string(), body: external_exports.string(), updatedAt: external_exports.string().nullable() });
24650
+ var oid2 = external_exports.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/);
24651
+ var browserSpecsV4 = external_exports.strictObject({
24652
+ contract: external_exports.literal("browser-specs"),
24653
+ version: external_exports.literal(4),
24654
+ sessionId: external_exports.string(),
24655
+ head: oid2.nullable(),
24656
+ observedAt: external_exports.string(),
24657
+ working: external_exports.boolean(),
24658
+ features: external_exports.array(feature),
24659
+ documents: external_exports.array(document),
24660
+ contributors: external_exports.array(contributor),
24661
+ contributorsLimited: external_exports.boolean()
24662
+ });
24663
+ var reference = external_exports.strictObject({ id: external_exports.string(), title: external_exports.string(), specId: external_exports.string(), path: external_exports.string() }).nullable();
24664
+ var snapshot = requirement.extend({ specId: external_exports.string(), path: external_exports.string(), sources: external_exports.array(source).optional() }).nullable();
24665
+ var changeType = external_exports.enum(["created", "modified", "moved", "deleted"]);
24651
24666
  var event = external_exports.strictObject({
24652
24667
  key: external_exports.string(),
24653
- commit: external_exports.string(),
24668
+ commit: oid2,
24654
24669
  date: external_exports.string(),
24655
24670
  author: external_exports.string(),
24656
24671
  email: external_exports.string(),
24657
24672
  committer: external_exports.string(),
24658
24673
  message: external_exports.string(),
24659
24674
  id: external_exports.string(),
24660
- kind: external_exports.enum(["requirement", "design", "wiki"]).optional(),
24661
- types: external_exports.array(external_exports.enum(["created", "modified", "moved", "deleted"])),
24662
- before: snapshot,
24663
- after: snapshot,
24675
+ kind: external_exports.enum(["requirement", "design", "wiki"]),
24676
+ types: external_exports.array(changeType),
24677
+ before: reference,
24678
+ after: reference,
24664
24679
  reasons: external_exports.array(external_exports.string())
24665
24680
  });
24666
- var browserSpecsV3 = external_exports.strictObject({
24667
- contract: external_exports.literal("browser-specs"),
24668
- version: external_exports.literal(3),
24681
+ var browserHistoryV1 = external_exports.strictObject({
24682
+ contract: external_exports.literal("browser-history"),
24683
+ version: external_exports.literal(1),
24669
24684
  sessionId: external_exports.string(),
24670
- head: external_exports.string().nullable(),
24671
- observedAt: external_exports.string(),
24685
+ head: oid2,
24686
+ // Matching changes in all of history, not in this page; `offset` is where this page starts among them.
24687
+ total: external_exports.number().int().nonnegative(),
24688
+ offset: external_exports.number().int().nonnegative(),
24672
24689
  events: external_exports.array(event),
24673
- nextCursor: external_exports.number().int().nonnegative().nullable(),
24674
- boundary: external_exports.boolean(),
24675
- working: external_exports.boolean().optional(),
24676
- features: external_exports.array(feature).optional(),
24677
- documents: external_exports.array(document).optional(),
24678
- contributors: external_exports.array(contributor).optional(),
24679
- contributorsLimited: external_exports.boolean().optional()
24690
+ // History reaches back to records in the legacy JSON format, which it does not read.
24691
+ boundary: external_exports.boolean()
24692
+ });
24693
+ var browserHistorySummaryV1 = external_exports.strictObject({
24694
+ contract: external_exports.literal("browser-history-summary"),
24695
+ version: external_exports.literal(1),
24696
+ sessionId: external_exports.string(),
24697
+ head: oid2,
24698
+ total: external_exports.number().int().nonnegative(),
24699
+ byType: external_exports.strictObject({ created: external_exports.number().int().nonnegative(), modified: external_exports.number().int().nonnegative(), moved: external_exports.number().int().nonnegative(), deleted: external_exports.number().int().nonnegative() }),
24700
+ // One entry per commit within three weeks of the newest change, so the reader can count by its own calendar day.
24701
+ pulse: external_exports.array(external_exports.strictObject({ date: external_exports.string(), count: external_exports.number().int().positive() })),
24702
+ // The newest commits: a few of their changes each and how many there are in all.
24703
+ recent: external_exports.array(external_exports.strictObject({ commit: oid2, count: external_exports.number().int().positive(), events: external_exports.array(event) }))
24704
+ });
24705
+ var browserChangeV1 = external_exports.strictObject({
24706
+ contract: external_exports.literal("browser-change"),
24707
+ version: external_exports.literal(1),
24708
+ sessionId: external_exports.string(),
24709
+ event,
24710
+ before: snapshot,
24711
+ after: snapshot
24712
+ });
24713
+ var browserSearchV1 = external_exports.strictObject({
24714
+ contract: external_exports.literal("browser-search"),
24715
+ version: external_exports.literal(1),
24716
+ sessionId: external_exports.string(),
24717
+ query: external_exports.string(),
24718
+ hits: external_exports.array(external_exports.strictObject({
24719
+ id: external_exports.string(),
24720
+ kind: external_exports.enum(["feature", "requirement", "design", "document", "history"]),
24721
+ title: external_exports.string(),
24722
+ where: external_exports.string(),
24723
+ line: external_exports.string(),
24724
+ // What the hit opens: a feature (with the requirement or design tab), a wiki page, or one change in the activity.
24725
+ featureId: external_exports.string().optional(),
24726
+ documentId: external_exports.string().optional(),
24727
+ key: external_exports.string().optional()
24728
+ }))
24680
24729
  });
24681
- var browserSpecsFirstV3 = browserSpecsV3.required({
24682
- working: true,
24683
- features: true,
24684
- documents: true,
24685
- contributors: true,
24686
- contributorsLimited: true
24730
+ var headQuery = oid2;
24731
+ var count = (max) => external_exports.string().regex(/^(0|[1-9]\d{0,6})$/).transform(Number).pipe(external_exports.number().int().min(0).max(max));
24732
+ var browserHistoryQueryV1 = external_exports.strictObject({
24733
+ head: headQuery,
24734
+ offset: count(1e6).optional(),
24735
+ limit: count(100).pipe(external_exports.number().min(1)).optional(),
24736
+ kind: changeType.optional(),
24737
+ document: external_exports.enum(["requirement", "design", "wiki"]).optional(),
24738
+ feature: external_exports.string().regex(/^S-[a-z2-7]{10}$/).optional(),
24739
+ author: external_exports.string().min(1).max(320).optional(),
24740
+ q: external_exports.string().max(200).optional()
24687
24741
  });
24742
+ var browserHistorySummaryQueryV1 = external_exports.strictObject({ head: headQuery });
24743
+ var browserChangeQueryV1 = external_exports.strictObject({ key: external_exports.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64}):[RSW]-[a-z2-7]{10}$/) });
24744
+ var browserSearchQueryV1 = external_exports.strictObject({ q: external_exports.string().min(1).max(200), head: headQuery.optional() });
24745
+ var changelogQueryV1 = external_exports.strictObject({ lang: external_exports.string().regex(/^[a-z]{2}(?:-[A-Z]{2})?$/).optional() });
24688
24746
 
24689
24747
  // ../../packages/contracts/dist/versions/changelog-v1.js
24690
24748
  var items = external_exports.array(external_exports.string().min(1));
@@ -24862,6 +24920,7 @@ var messages_default2 = {
24862
24920
  "server.apiNotFound": "API\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24863
24921
  "server.sessionChanged": "\uC11C\uBC84 \uC138\uC158\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.",
24864
24922
  "server.badRange": "\uC870\uD68C \uBC94\uC704\uB97C \uD655\uC778\uD558\uC138\uC694.",
24923
+ "server.changeNotFound": "\uADF8 \uCEE4\uBC0B\uC5D0 \uD574\uB2F9 \uBCC0\uACBD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
24865
24924
  "server.specsUnreadable": "\uBA85\uC138\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24866
24925
  "server.refreshOrigin": "\uC0C8\uB85C\uACE0\uCE68\uC5D0\uB294 \uAC19\uC740 \uCD9C\uCC98\uC758 Origin\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
24867
24926
  "server.fileNotFound": "\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
@@ -24934,7 +24993,6 @@ var messages_default2 = {
24934
24993
  "agentBlock.duplicateStart": "GITIFACT \uC2DC\uC791 \uB9C8\uCEE4\uAC00 \uC5EC\uB7EC \uAC1C\uC785\uB2C8\uB2E4. \uC911\uBCF5 \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
24935
24994
  "specReader.headUnreadable": "HEAD\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24936
24995
  "specReader.schemaRequired": "\uC0C8 \uC2A4\uD0A4\uB9C8 \uD504\uB85C\uC81D\uD2B8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24937
- "specReader.historyChanged": "\uC774\uB825\uC774 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68 \uD6C4 \uB2E4\uC2DC \uC870\uD68C\uD558\uC138\uC694.",
24938
24996
  "specReader.authorUnreadable": "Git \uC791\uC131\uC790\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24939
24997
  "specReader.historyUnreadable": "Git \uC774\uB825 \uD615\uC2DD\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24940
24998
  "specReader.projectChanged": "\uC870\uD68C \uC911 \uD504\uB85C\uC81D\uD2B8\uAC00 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68\uD558\uC138\uC694.",
@@ -24954,7 +25012,6 @@ var messages_default2 = {
24954
25012
  "help.browserNoUpdateCheck": "\uC0C8 \uBC84\uC804 \uD655\uC778\uC744 \uC704\uD55C npm \uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC870\uD68C\uB97C \uB054 (GITIFACT_NO_UPDATE_CHECK\uC640 \uAC19\uC74C)",
24955
25013
  "help.updateCommit": "\uAC31\uC2E0\uD55C GITIFACT \uBE14\uB85D\uC774 HEAD\uC640 \uBE14\uB85D \uC548\uC5D0\uC11C\uB9CC \uB2E4\uB974\uBA74 \uADF8 \uD30C\uC77C\uB9CC \uACE0\uC815 \uBA54\uC2DC\uC9C0\uB85C \uCEE4\uBC0B",
24956
25014
  "help.update": "\uC0C8 \uBC84\uC804 \uD655\uC778\uACFC \uC124\uCE58 \uBC29\uBC95 \uC548\uB0B4, \uD504\uB85C\uC81D\uD2B8 \uC9C0\uCE68 \uD30C\uC77C\uC758 GITIFACT \uBE14\uB85D\uC744 \uD604\uC7AC \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0",
24957
- "server.badLanguage": "\uC5B8\uC5B4 \uCF54\uB4DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
24958
25015
  "server.changelogNotFound": "\uD328\uCE58\uB178\uD2B8\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24959
25016
  "server.changelogUnreadable": "\uD328\uCE58\uB178\uD2B8\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24960
25017
  "update.text.current": "\uD604\uC7AC \uBC84\uC804: {version}",
@@ -25056,43 +25113,7 @@ async function runStatus(format) {
25056
25113
  import { createServer } from "node:http";
25057
25114
  import { randomUUID as randomUUID4 } from "node:crypto";
25058
25115
  import { fileURLToPath } from "node:url";
25059
- import { lstat as lstat4, readFile as readFile4 } from "node:fs/promises";
25060
- import { join as join5 } from "node:path";
25061
-
25062
- // src/server/assets.ts
25063
- import { readdir, readFile } from "node:fs/promises";
25064
- import { join } from "node:path";
25065
- async function loadBrowserAssets(directory) {
25066
- const assets = /* @__PURE__ */ new Map();
25067
- async function walk(current, prefix) {
25068
- for (const entry2 of await readdir(current, { withFileTypes: true })) {
25069
- if (entry2.isSymbolicLink()) throw new Error(t2("browser.assetSymlink"));
25070
- const name = prefix + entry2.name;
25071
- if (entry2.isDirectory()) await walk(join(current, entry2.name), name + "/");
25072
- else if (entry2.isFile()) assets.set("/" + name, await readFile(join(current, entry2.name)));
25073
- }
25074
- }
25075
- try {
25076
- await walk(directory, "");
25077
- if (!assets.has("/index.html")) throw new Error("missing index");
25078
- } catch {
25079
- throw new Error(t2("browser.assetsUnreadable"));
25080
- }
25081
- return assets;
25082
- }
25083
- function contentType(path3) {
25084
- if (path3.endsWith(".html")) return "text/html; charset=utf-8";
25085
- if (path3.endsWith(".js")) return "text/javascript; charset=utf-8";
25086
- if (path3.endsWith(".css")) return "text/css; charset=utf-8";
25087
- if (path3.endsWith(".svg")) return "image/svg+xml";
25088
- if (path3.endsWith(".woff2")) return "font/woff2";
25089
- if (path3.endsWith(".png")) return "image/png";
25090
- if (/\.jpe?g$/.test(path3)) return "image/jpeg";
25091
- if (path3.endsWith(".gif")) return "image/gif";
25092
- if (path3.endsWith(".webp")) return "image/webp";
25093
- if (path3.endsWith(".pdf")) return "application/pdf";
25094
- return "application/octet-stream";
25095
- }
25116
+ import { readFile as readFile5 } from "node:fs/promises";
25096
25117
 
25097
25118
  // src/server/status-session.ts
25098
25119
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -25180,6 +25201,172 @@ function createStatusSession(initial, read, cliVersion = "0.0.0") {
25180
25201
  };
25181
25202
  }
25182
25203
 
25204
+ // src/server/http/respond.ts
25205
+ var HttpError = class extends Error {
25206
+ constructor(status, code, message) {
25207
+ super(message);
25208
+ this.status = status;
25209
+ this.code = code;
25210
+ }
25211
+ status;
25212
+ code;
25213
+ };
25214
+ function json2(response, status, value) {
25215
+ response.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
25216
+ response.end(JSON.stringify(value) + "\n");
25217
+ }
25218
+ function fail4(response, status, code, message) {
25219
+ json2(response, status, browserHttpErrorV1.parse({ contract: "browser-http-error", version: 1, error: { code, message } }));
25220
+ }
25221
+
25222
+ // src/server/http/guard.ts
25223
+ function admit(request, response, origin, dev) {
25224
+ response.setHeader("X-Content-Type-Options", "nosniff");
25225
+ response.setHeader("X-Frame-Options", "DENY");
25226
+ response.setHeader("Referrer-Policy", "no-referrer");
25227
+ response.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; base-uri 'none'; frame-ancestors 'none'");
25228
+ if (request.headers.host !== new URL(origin).host) {
25229
+ fail4(response, 403, "FORBIDDEN", t2("server.forbiddenHost"));
25230
+ return;
25231
+ }
25232
+ const requestOrigin = request.headers.origin;
25233
+ const allowedOrigin = requestOrigin === origin || dev && requestOrigin === "http://127.0.0.1:5173";
25234
+ if (requestOrigin && !allowedOrigin) {
25235
+ fail4(response, 403, "FORBIDDEN", t2("server.forbiddenOrigin"));
25236
+ return;
25237
+ }
25238
+ const raw = request.url ?? "/";
25239
+ if (!raw.startsWith("/") || raw.startsWith("//") || raw.includes("\\")) {
25240
+ fail4(response, 400, "BAD_REQUEST", t2("server.badPath"));
25241
+ return;
25242
+ }
25243
+ let url2;
25244
+ let path3;
25245
+ try {
25246
+ url2 = new URL(raw, origin);
25247
+ path3 = decodeURIComponent(url2.pathname);
25248
+ } catch {
25249
+ fail4(response, 400, "BAD_REQUEST", t2("server.badPath"));
25250
+ return;
25251
+ }
25252
+ if (path3.includes("\0") || path3.includes("\\") || path3.split("/").some((part) => part === ".." || part === ".")) {
25253
+ fail4(response, 400, "BAD_REQUEST", t2("server.badPath"));
25254
+ return;
25255
+ }
25256
+ if (request.headers["transfer-encoding"] || request.headers["content-length"] && request.headers["content-length"] !== "0") {
25257
+ request.resume();
25258
+ fail4(response, 400, "BAD_REQUEST", t2("server.noBody"));
25259
+ return;
25260
+ }
25261
+ const api = path3 === "/api" || path3.startsWith("/api/");
25262
+ if (api && request.headers["sec-fetch-site"] === "cross-site" && !allowedOrigin) {
25263
+ fail4(response, 403, "FORBIDDEN", t2("server.crossSite"));
25264
+ return;
25265
+ }
25266
+ return { url: url2, path: path3, api, allowedOrigin: !!allowedOrigin };
25267
+ }
25268
+
25269
+ // src/server/http/router.ts
25270
+ var route = (value) => value;
25271
+ var ok = (body) => ({ status: 200, body });
25272
+ var matches = (route2, path3) => route2.path.endsWith("/*") ? path3.startsWith(route2.path.slice(0, -1)) : route2.path === path3;
25273
+ async function dispatch(routes, sessionId, url2, path3, request, response, allowedOrigin) {
25274
+ const candidates2 = routes.filter((r) => matches(r, path3));
25275
+ if (!candidates2.length) return fail4(response, 404, "NOT_FOUND", t2("server.apiNotFound"));
25276
+ const found = candidates2.find((r) => r.method === request.method);
25277
+ if (!found) {
25278
+ response.setHeader("Allow", candidates2.map((r) => r.method).join(", "));
25279
+ return fail4(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25280
+ }
25281
+ let query = {};
25282
+ if (found.query) {
25283
+ const keys2 = [...url2.searchParams.keys()];
25284
+ if (new Set(keys2).size !== keys2.length) return fail4(response, 400, "BAD_REQUEST", t2("server.badRange"));
25285
+ const parsed = found.query.safeParse(Object.fromEntries(url2.searchParams));
25286
+ if (!parsed.success) return fail4(response, 400, "BAD_REQUEST", t2("server.badRange"));
25287
+ query = parsed.data;
25288
+ } else if (url2.search) return fail4(response, 400, "BAD_REQUEST", t2("server.noQuery"));
25289
+ if (found.session && request.headers["x-gitifact-session"] !== sessionId) return fail4(response, 409, "SESSION_CHANGED", t2("server.sessionChanged"));
25290
+ try {
25291
+ const reply = await found.handle({ query, path: path3, request, response, allowedOrigin });
25292
+ if (reply && !response.destroyed) json2(response, reply.status, reply.body);
25293
+ } catch (error62) {
25294
+ if (error62 instanceof HttpError) return fail4(response, error62.status, error62.code, error62.message);
25295
+ fail4(response, 503, "INTERNAL_ERROR", error62 instanceof Error && error62.message ? error62.message : found.unreadable ?? t2("server.internal"));
25296
+ }
25297
+ }
25298
+
25299
+ // src/server/http/static-files.ts
25300
+ import { readdir, readFile } from "node:fs/promises";
25301
+ import { join } from "node:path";
25302
+ async function loadBrowserAssets(directory) {
25303
+ const assets = /* @__PURE__ */ new Map();
25304
+ async function walk(current, prefix) {
25305
+ for (const entry2 of await readdir(current, { withFileTypes: true })) {
25306
+ if (entry2.isSymbolicLink()) throw new Error(t2("browser.assetSymlink"));
25307
+ const name = prefix + entry2.name;
25308
+ if (entry2.isDirectory()) await walk(join(current, entry2.name), name + "/");
25309
+ else if (entry2.isFile()) assets.set("/" + name, await readFile(join(current, entry2.name)));
25310
+ }
25311
+ }
25312
+ try {
25313
+ await walk(directory, "");
25314
+ if (!assets.has("/index.html")) throw new Error("missing index");
25315
+ } catch {
25316
+ throw new Error(t2("browser.assetsUnreadable"));
25317
+ }
25318
+ return assets;
25319
+ }
25320
+ function contentType(path3) {
25321
+ if (path3.endsWith(".html")) return "text/html; charset=utf-8";
25322
+ if (path3.endsWith(".js")) return "text/javascript; charset=utf-8";
25323
+ if (path3.endsWith(".css")) return "text/css; charset=utf-8";
25324
+ if (path3.endsWith(".svg")) return "image/svg+xml";
25325
+ if (path3.endsWith(".woff2")) return "font/woff2";
25326
+ if (path3.endsWith(".png")) return "image/png";
25327
+ if (/\.jpe?g$/.test(path3)) return "image/jpeg";
25328
+ if (path3.endsWith(".gif")) return "image/gif";
25329
+ if (path3.endsWith(".webp")) return "image/webp";
25330
+ if (path3.endsWith(".pdf")) return "application/pdf";
25331
+ return "application/octet-stream";
25332
+ }
25333
+ function serveStatic(request, response, path3, assets) {
25334
+ if (request.method !== "GET" && request.method !== "HEAD") {
25335
+ response.setHeader("Allow", "GET, HEAD");
25336
+ return fail4(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25337
+ }
25338
+ let assetPath = path3 === "/" ? "/index.html" : path3;
25339
+ let asset = assets.get(assetPath);
25340
+ if (!asset && !path3.startsWith("/assets/") && !path3.split("/").some((part) => part.includes(".")) && request.headers.accept?.includes("text/html")) {
25341
+ asset = assets.get("/index.html");
25342
+ assetPath = "/index.html";
25343
+ }
25344
+ if (!asset) return fail4(response, 404, "NOT_FOUND", t2("server.fileNotFound"));
25345
+ response.writeHead(200, { "Content-Type": contentType(assetPath), "Cache-Control": "no-cache", "Content-Length": asset.length });
25346
+ response.end(request.method === "HEAD" ? void 0 : asset);
25347
+ }
25348
+
25349
+ // src/server/routes/project-routes.ts
25350
+ function projectRoutes(store, readChangelog) {
25351
+ return [
25352
+ // Re-reading the session never contacts the registry; it returns the state the single startup check left.
25353
+ route({ method: "GET", path: "/api/v1/session", session: false, handle: () => ok(store.session) }),
25354
+ route({ method: "GET", path: "/api/v1/status", session: true, handle: () => ({ status: store.latest.ok ? 200 : 503, body: store.latest }) }),
25355
+ route({ method: "POST", path: "/api/v1/status/refresh", session: true, handle: async ({ allowedOrigin }) => {
25356
+ if (!allowedOrigin) throw new HttpError(403, "FORBIDDEN", t2("server.refreshOrigin"));
25357
+ const value = await store.refresh();
25358
+ return { status: value.ok ? 200 : 503, body: value };
25359
+ } }),
25360
+ route({ method: "GET", path: "/api/v1/changelog", session: true, query: changelogQueryV1, unreadable: t2("server.changelogUnreadable"), handle: async ({ query }) => {
25361
+ const language = query.lang ?? defaultLanguage2;
25362
+ const own2 = await readChangelog(language);
25363
+ const text2 = own2 ?? (language === defaultLanguage2 ? null : await readChangelog(defaultLanguage2));
25364
+ if (text2 === null) throw new HttpError(404, "NOT_FOUND", t2("server.changelogNotFound"));
25365
+ return ok(changelogV1.parse({ contract: "changelog", version: 1, language: own2 === null ? defaultLanguage2 : language, fallback: own2 === null, entries: parseChangelog(text2) }));
25366
+ } })
25367
+ ];
25368
+ }
25369
+
25183
25370
  // src/adapters/git/command-scope.ts
25184
25371
  import { AsyncLocalStorage } from "node:async_hooks";
25185
25372
  var storage = new AsyncLocalStorage();
@@ -25222,19 +25409,24 @@ function specPreviewReader(cwd) {
25222
25409
  }
25223
25410
  };
25224
25411
  return {
25412
+ /** Git under the same guarded environment, for readers that shape their own commands (the browser's history). */
25413
+ run(args, input2) {
25414
+ return git(args, input2);
25415
+ },
25416
+ decode: decode5,
25225
25417
  async index() {
25226
25418
  const output2 = decode5(await git(["ls-files", "--stage", "-z", "--", ...RECORD_PATHSPECS]));
25227
25419
  const files = /* @__PURE__ */ new Map();
25228
25420
  for (const row of output2.split("\0").filter(Boolean)) {
25229
25421
  const match = /^(\d+) ([a-f0-9]+) ([0-3])\t([\s\S]+)$/.exec(row);
25230
25422
  if (!match) throw new SpecPreviewError(t2("reader.invalidIndexEntry"));
25231
- const [, mode, oid2, stage, path3] = match;
25423
+ const [, mode, oid3, stage, path3] = match;
25232
25424
  if (!["100644", "100755"].includes(mode) || stage !== "0") throw new SpecPreviewError(t2("reader.stagingConflictOrLink"));
25233
25425
  if (!recordPathPattern.test(path3)) {
25234
25426
  if (path3.startsWith(WIKI_DIR + "/")) continue;
25235
25427
  throw new SpecPreviewError(t2("reader.stagingUnsupported"));
25236
25428
  }
25237
- files.set(path3, oid2);
25429
+ files.set(path3, oid3);
25238
25430
  }
25239
25431
  return files;
25240
25432
  },
@@ -25267,12 +25459,12 @@ function specPreviewReader(cwd) {
25267
25459
  });
25268
25460
  },
25269
25461
  async resolve(ref) {
25270
- const oid2 = (await git(["rev-parse", "--verify", "--end-of-options", ref + "^{commit}"])).toString("ascii").trim();
25271
- if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(oid2)) throw new SpecPreviewError(t2("reader.commitUnknown"));
25272
- return oid2;
25462
+ const oid3 = (await git(["rev-parse", "--verify", "--end-of-options", ref + "^{commit}"])).toString("ascii").trim();
25463
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(oid3)) throw new SpecPreviewError(t2("reader.commitUnknown"));
25464
+ return oid3;
25273
25465
  },
25274
- async files(oid2, allowLegacyBaseline = false) {
25275
- const entries = decode5(await git(["ls-tree", "--full-tree", "-r", "-z", oid2, "--", ...RECORD_PATHSPECS]));
25466
+ async files(oid3, allowLegacyBaseline = false) {
25467
+ const entries = decode5(await git(["ls-tree", "--full-tree", "-r", "-z", oid3, "--", ...RECORD_PATHSPECS]));
25276
25468
  const files = /* @__PURE__ */ new Map();
25277
25469
  let legacy;
25278
25470
  for (const row of entries.split("\0").filter(Boolean)) {
@@ -25292,7 +25484,7 @@ function specPreviewReader(cwd) {
25292
25484
  if (new Set([...files.keys()].map((p) => p.split("/")[0])).size > 1) throw new SpecPreviewError(t2("reader.mixedStores"));
25293
25485
  if (legacy) {
25294
25486
  if (files.size) throw new SpecPreviewError(t2("reader.mixedFormats"));
25295
- parseProjectConfig(decode5(await git(["show", `${oid2}:${legacy}/config.json`])));
25487
+ parseProjectConfig(decode5(await git(["show", `${oid3}:${legacy}/config.json`])));
25296
25488
  }
25297
25489
  if (files.size > 2e3) throw new SpecPreviewError(t2("reader.fileLimit"));
25298
25490
  const blobs = /* @__PURE__ */ new Map();
@@ -25316,12 +25508,12 @@ function specPreviewReader(cwd) {
25316
25508
  }
25317
25509
  return new Map([...files].map(([path3, id]) => [path3, blobs.get(id)]));
25318
25510
  },
25319
- async read(oid2) {
25320
- const files = await this.files(oid2);
25511
+ async read(oid3) {
25512
+ const files = await this.files(oid3);
25321
25513
  return parsePreviewFiles(files);
25322
25514
  },
25323
- async readBundle(oid2) {
25324
- return parsePreviewBundle(await this.files(oid2));
25515
+ async readBundle(oid3) {
25516
+ return parsePreviewBundle(await this.files(oid3));
25325
25517
  }
25326
25518
  };
25327
25519
  }
@@ -25455,7 +25647,7 @@ async function publishConfig(root, text2, recheck, beforePublish, replace = fals
25455
25647
  }
25456
25648
 
25457
25649
  // src/adapters/filesystem/spec-preview-store.ts
25458
- var fail4 = (message) => {
25650
+ var fail5 = (message) => {
25459
25651
  throw new SpecPreviewError(message);
25460
25652
  };
25461
25653
  var info2 = async (path3) => lstat3(path3).catch((e) => {
@@ -25465,7 +25657,7 @@ var info2 = async (path3) => lstat3(path3).catch((e) => {
25465
25657
  var digest = (value) => createHash2("sha256").update(value).digest("hex");
25466
25658
  var LEGACY_LOCKS = ["tryce-spec-preview.lock", "tryce-spec-commit.lock"];
25467
25659
  async function failOnLegacyLock(gitDir) {
25468
- for (const name of LEGACY_LOCKS) if (await info2(join4(gitDir, name))) fail4(t2("store.legacyLock", { path: join4(gitDir, name) }));
25660
+ for (const name of LEGACY_LOCKS) if (await info2(join4(gitDir, name))) fail5(t2("store.legacyLock", { path: join4(gitDir, name) }));
25469
25661
  }
25470
25662
  var decode3 = (bytes) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
25471
25663
  var generatePreviewId = (prefix) => prefix + "-" + [...randomBytes(10)].map((n) => "abcdefghijklmnopqrstuvwxyz234567"[n & 31]).join("");
@@ -25473,29 +25665,29 @@ var PreservedPreviewError = class extends SpecPreviewError {
25473
25665
  };
25474
25666
  async function snapshot2(root) {
25475
25667
  const files = /* @__PURE__ */ new Map();
25476
- let count = 0;
25668
+ let count2 = 0;
25477
25669
  let bytes = 0;
25478
25670
  const parent = await info2(join4(root, ".gitifact"));
25479
- if (parent && (!parent.isDirectory() || parent.isSymbolicLink())) fail4(t2("store.storeNotDirectory"));
25480
- if (!parent && await info2(join4(root, ".tryce"))) fail4(t2("store.migrateFirst"));
25671
+ if (parent && (!parent.isDirectory() || parent.isSymbolicLink())) fail5(t2("store.storeNotDirectory"));
25672
+ if (!parent && await info2(join4(root, ".tryce"))) fail5(t2("store.migrateFirst"));
25481
25673
  const config2 = await readConfigFile(root);
25482
- if (config2 !== void 0 && !("schemaVersion" in parseManagedConfig(config2)) || await info2(join4(root, "specs"))) fail4(t2("store.legacyProject"));
25674
+ if (config2 !== void 0 && !("schemaVersion" in parseManagedConfig(config2)) || await info2(join4(root, "specs"))) fail5(t2("store.legacyProject"));
25483
25675
  async function visit2(path3, depth, documents) {
25484
25676
  const stat3 = await info2(join4(root, path3));
25485
25677
  if (!stat3) return;
25486
- if (stat3.isSymbolicLink() || !stat3.isDirectory() && !stat3.isFile()) fail4(t2("store.linkOrSpecial", { path: path3 }));
25487
- if (++count > 4e3) fail4(t2("store.tooManyFiles"));
25678
+ if (stat3.isSymbolicLink() || !stat3.isDirectory() && !stat3.isFile()) fail5(t2("store.linkOrSpecial", { path: path3 }));
25679
+ if (++count2 > 4e3) fail5(t2("store.tooManyFiles"));
25488
25680
  if (stat3.isDirectory()) {
25489
- if (depth > (documents ? 8 : 1)) fail4(t2("store.tooDeep", { path: path3 }));
25681
+ if (depth > (documents ? 8 : 1)) fail5(t2("store.tooDeep", { path: path3 }));
25490
25682
  for (const name of (await readdir3(join4(root, path3))).sort()) await visit2(path3 + "/" + name, depth + 1, documents);
25491
25683
  } else {
25492
- if (path3.endsWith("/tryce.json")) fail4(t2("store.legacyJson"));
25684
+ if (path3.endsWith("/tryce.json")) fail5(t2("store.legacyJson"));
25493
25685
  if (documents ? !(path3.endsWith(".md") || depth === 1 && path3.endsWith("/history.jsonl")) : !/\/(requirements\.md|design\.md|history\.jsonl)$/.test(path3)) return;
25494
- if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/")) fail4(t2("store.unsupportedPath", { path: path3 }));
25495
- if (stat3.nlink !== 1 || stat3.size > 1024 * 1024) fail4(t2("store.hardLinkOrSize"));
25686
+ if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/")) fail5(t2("store.unsupportedPath", { path: path3 }));
25687
+ if (stat3.nlink !== 1 || stat3.size > 1024 * 1024) fail5(t2("store.hardLinkOrSize"));
25496
25688
  const raw = await readFile3(join4(root, path3));
25497
25689
  bytes += raw.length;
25498
- if (raw.length > 1024 * 1024 || bytes > 16 * 1024 * 1024) fail4(t2("store.sizeLimit"));
25690
+ if (raw.length > 1024 * 1024 || bytes > 16 * 1024 * 1024) fail5(t2("store.sizeLimit"));
25499
25691
  files.set(path3, decode3(raw));
25500
25692
  }
25501
25693
  }
@@ -25507,11 +25699,11 @@ async function snapshot2(root) {
25507
25699
  async function readWorkingPreviewState(cwd) {
25508
25700
  const { root, gitDir } = await specPreviewReader(cwd).location();
25509
25701
  await failOnLegacyLock(gitDir);
25510
- if (await info2(join4(gitDir, "gitifact-spec-preview.lock"))) fail4(t2("store.locked"));
25702
+ if (await info2(join4(gitDir, "gitifact-spec-preview.lock"))) fail5(t2("store.locked"));
25511
25703
  const first = await snapshot2(root);
25512
25704
  const second = await snapshot2(root);
25513
- if (first.stamp !== second.stamp) fail4(t2("store.changedWhileReading"));
25514
- if (await info2(join4(gitDir, "gitifact-spec-preview.lock"))) fail4(t2("store.lockedWhileReading"));
25705
+ if (first.stamp !== second.stamp) fail5(t2("store.changedWhileReading"));
25706
+ if (await info2(join4(gitDir, "gitifact-spec-preview.lock"))) fail5(t2("store.lockedWhileReading"));
25515
25707
  return first;
25516
25708
  }
25517
25709
  async function readWorkingPreview(cwd) {
@@ -25519,9 +25711,9 @@ async function readWorkingPreview(cwd) {
25519
25711
  return { stamp, specs, wiki, warnings: await workingWarnings(root, bundle) };
25520
25712
  }
25521
25713
  async function saveWorkingPreview(cwd, input2, publish = rename2) {
25522
- if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail4(t2("store.invalidInput"));
25714
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail5(t2("store.invalidInput"));
25523
25715
  const request = input2;
25524
- if (Object.keys(request).sort().join(",") !== "expected,operations" || typeof request.expected !== "string") fail4(t2("store.expectedOperations"));
25716
+ if (Object.keys(request).sort().join(",") !== "expected,operations" || typeof request.expected !== "string") fail5(t2("store.expectedOperations"));
25525
25717
  return previewTransaction(cwd, request.expected, async (before) => {
25526
25718
  const result = editSpecPreview(before.bundle, request.operations, generatePreviewId);
25527
25719
  const writes = /* @__PURE__ */ new Map();
@@ -25549,7 +25741,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename2, afte
25549
25741
  try {
25550
25742
  await mkdir2(lock);
25551
25743
  } catch (e) {
25552
- if (e.code === "EEXIST") fail4(t2("store.locked"));
25744
+ if (e.code === "EEXIST") fail5(t2("store.locked"));
25553
25745
  throw e;
25554
25746
  }
25555
25747
  const createdDirs = [];
@@ -25560,7 +25752,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename2, afte
25560
25752
  async function directory(path3) {
25561
25753
  const stat3 = await info2(path3);
25562
25754
  if (stat3) {
25563
- if (!stat3.isDirectory() || stat3.isSymbolicLink()) fail4(t2("store.notDirectory", { path: path3 }));
25755
+ if (!stat3.isDirectory() || stat3.isSymbolicLink()) fail5(t2("store.notDirectory", { path: path3 }));
25564
25756
  return;
25565
25757
  }
25566
25758
  await directory(dirname(path3));
@@ -25569,11 +25761,11 @@ async function previewTransaction(cwd, expected2, build, publish = rename2, afte
25569
25761
  }
25570
25762
  try {
25571
25763
  const before = await snapshot2(root);
25572
- if (before.stamp !== expected2) fail4(t2("store.staleExpected"));
25764
+ if (before.stamp !== expected2) fail5(t2("store.staleExpected"));
25573
25765
  const result = await build(before);
25574
25766
  for (const [path3, after2] of result.writes) {
25575
- if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/") || path3.split("/").some((p) => p === ".." || p === "." || /[\\:\0]/.test(p))) fail4(t2("store.unsupportedSavePath"));
25576
- if (after2 !== null && Buffer.byteLength(after2) > 1024 * 1024) fail4(t2("store.fileSizeLimit"));
25767
+ if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/") || path3.split("/").some((p) => p === ".." || p === "." || /[\\:\0]/.test(p))) fail5(t2("store.unsupportedSavePath"));
25768
+ if (after2 !== null && Buffer.byteLength(after2) > 1024 * 1024) fail5(t2("store.fileSizeLimit"));
25577
25769
  changed.push({ path: path3, before: before.files.get(path3) ?? null, after: after2 });
25578
25770
  }
25579
25771
  const finalFiles = new Map(before.files);
@@ -25581,7 +25773,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename2, afte
25581
25773
  if (c.after === null) finalFiles.delete(c.path);
25582
25774
  else finalFiles.set(c.path, c.after);
25583
25775
  }
25584
- if (finalFiles.size > 2e3 || [...finalFiles.values()].reduce((n, s) => n + Buffer.byteLength(s), 0) > 16 * 1024 * 1024) fail4(t2("store.totalLimit"));
25776
+ if (finalFiles.size > 2e3 || [...finalFiles.values()].reduce((n, s) => n + Buffer.byteLength(s), 0) > 16 * 1024 * 1024) fail5(t2("store.totalLimit"));
25585
25777
  await writeFile(join4(lock, "recovery.json"), JSON.stringify({ root, changed }), { flag: "wx" });
25586
25778
  for (const c of changed) {
25587
25779
  if (c.after === null) {
@@ -25593,19 +25785,19 @@ async function previewTransaction(cwd, expected2, build, publish = rename2, afte
25593
25785
  await writeFile(temp, c.after, { flag: "wx" });
25594
25786
  temporary.push(temp);
25595
25787
  }
25596
- if ((await snapshot2(root)).stamp !== before.stamp) fail4(t2("store.changedPreparing"));
25788
+ if ((await snapshot2(root)).stamp !== before.stamp) fail5(t2("store.changedPreparing"));
25597
25789
  await result.recheck?.();
25598
25790
  for (let i = 0; i < changed.length; i++) {
25599
25791
  const c = changed[i];
25600
25792
  const path3 = join4(root, c.path);
25601
25793
  const stat3 = await info2(path3);
25602
- if (stat3?.isSymbolicLink() || stat3 && !stat3.isFile() || (stat3 ? decode3(await readFile3(path3)) : null) !== c.before) fail4(t2("store.changedBeforeWrite"));
25794
+ if (stat3?.isSymbolicLink() || stat3 && !stat3.isFile() || (stat3 ? decode3(await readFile3(path3)) : null) !== c.before) fail5(t2("store.changedBeforeWrite"));
25603
25795
  if (c.after === null) await unlink2(path3);
25604
25796
  else await publish(temporary[i], path3);
25605
25797
  published.push(c);
25606
25798
  }
25607
25799
  const after = await snapshot2(root);
25608
- if (after.stamp !== digest(JSON.stringify([...finalFiles].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) + (before.config ?? ""))) fail4(t2("store.changedWhileWriting"));
25800
+ if (after.stamp !== digest(JSON.stringify([...finalFiles].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) + (before.config ?? ""))) fail5(t2("store.changedWhileWriting"));
25609
25801
  await result.recheck?.();
25610
25802
  await afterPublish?.(after);
25611
25803
  return { ...result.data, stamp: after.stamp, paths: changed.map((c) => c.path), specs: after.specs, wiki: after.wiki, warnings: await workingWarnings(root, after.bundle) };
@@ -25633,7 +25825,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename2, afte
25633
25825
  keepRecovery = true;
25634
25826
  }
25635
25827
  }
25636
- if (keepRecovery) fail4(t2("store.recoveryIncomplete", { path: lock }));
25828
+ if (keepRecovery) fail5(t2("store.recoveryIncomplete", { path: lock }));
25637
25829
  throw error62;
25638
25830
  } finally {
25639
25831
  for (const path3 of temporary.filter(Boolean)) await unlink2(path3).catch((e) => {
@@ -25650,144 +25842,686 @@ async function previewTransaction(cwd, expected2, build, publish = rename2, afte
25650
25842
  }
25651
25843
  }
25652
25844
 
25653
- // src/server/spec-reader.ts
25654
- function createSpecBrowserReader(root, sessionId, inherited = process.env) {
25845
+ // src/server/checkout/checkout-reader.ts
25846
+ var tally = (people, name, email3, latest) => {
25847
+ const person = people.get(email3);
25848
+ if (person) person.commits++;
25849
+ else people.set(email3, { name, email: email3, latest, commits: 1 });
25850
+ };
25851
+ async function settled(reads) {
25852
+ const results = await Promise.allSettled(reads);
25853
+ const failure2 = results.find((r) => r.status === "rejected");
25854
+ if (failure2) throw failure2.reason;
25855
+ return results.map((r) => r.value);
25856
+ }
25857
+ function createCheckoutReader(root, sessionId, inherited = process.env) {
25655
25858
  const reader = specPreviewReader(root);
25656
25859
  const runner = createGitRunner();
25657
25860
  const env = { ...inherited, GIT_OPTIONAL_LOCKS: "0", GIT_NO_REPLACE_OBJECTS: "1", GIT_TERMINAL_PROMPT: "0", LC_ALL: "C" };
25658
- const git = async (args, acceptedExitCodes = [0]) => (await runner(["--no-optional-locks", ...args], { cwd: root, env, timeoutMs: 15e3, maxBytes: 16 * 1024 * 1024, acceptedExitCodes })).toString("utf8");
25861
+ const git = async (args, acceptedExitCodes = [0]) => (await runner(["--no-optional-locks", ...args], { cwd: root, env, timeoutMs: 15e3, maxBytes: 32 * 1024 * 1024, acceptedExitCodes })).toString("utf8");
25659
25862
  const readHead = async () => {
25660
25863
  const head = (await git(["rev-parse", "--verify", "--quiet", "HEAD"], [0, 1])).trim();
25661
25864
  if (head && !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) throw new SpecPreviewError(t2("specReader.headUnreadable"));
25662
25865
  if (!head) await reader.baseline();
25663
25866
  return head || null;
25664
25867
  };
25665
- const snapshots = /* @__PURE__ */ new Map();
25666
- const snapshot3 = (oid2) => {
25667
- let value = snapshots.get(oid2);
25668
- if (!value) {
25669
- value = reader.readBundle(oid2).catch((e) => {
25670
- snapshots.delete(oid2);
25671
- throw e;
25672
- });
25673
- snapshots.set(oid2, value);
25674
- }
25675
- if (snapshots.size > 128) snapshots.delete(snapshots.keys().next().value);
25676
- return value;
25677
- };
25678
- let peopleCache;
25679
25868
  const pending = /* @__PURE__ */ new Map();
25680
- async function read(cursor, expectedHead) {
25869
+ async function storeAuthors(head) {
25870
+ const text2 = await git(["log", "--format=%x1e%aN%x00%aE%x00%aI", "-z", "--name-only", "--no-renames", "--max-count=20000", head, "--", ".gitifact", ".tryce"]);
25871
+ const folders = /* @__PURE__ */ new Map();
25872
+ const pages = /* @__PURE__ */ new Map();
25873
+ for (const chunk of text2.split("")) {
25874
+ if (!chunk) continue;
25875
+ const [name, email3, date5, ...paths2] = chunk.split("\0");
25876
+ if (!name || !email3 || !date5) throw new SpecPreviewError(t2("specReader.authorUnreadable"));
25877
+ const seen = /* @__PURE__ */ new Set();
25878
+ for (const raw of paths2) {
25879
+ const path3 = raw.replace(/^\n/, "");
25880
+ if (!path3) continue;
25881
+ const folder = /^\.(?:gitifact|tryce)\/(spec\/[^/]+)\//.exec(path3)?.[1];
25882
+ if (folder && !seen.has(folder)) {
25883
+ seen.add(folder);
25884
+ let entry2 = folders.get(folder);
25885
+ if (!entry2) folders.set(folder, entry2 = { people: /* @__PURE__ */ new Map(), count: 0, latest: date5 });
25886
+ if (entry2.count < 2e3) {
25887
+ entry2.count++;
25888
+ tally(entry2.people, name, email3, date5);
25889
+ }
25890
+ }
25891
+ if (path3.startsWith(WIKI_DIR + "/") && !pages.has(path3)) pages.set(path3, date5);
25892
+ }
25893
+ }
25894
+ return { folders, pages };
25895
+ }
25896
+ async function read() {
25681
25897
  const raw = await readConfigFile(root);
25682
25898
  if (!raw || !("schemaVersion" in parseManagedConfig(raw))) throw new SpecPreviewError(t2("specReader.schemaRequired"));
25683
- const base = { head: await readHead() };
25684
- if (cursor > 0 && expectedHead !== base.head) throw new SpecPreviewError(t2("specReader.historyChanged"));
25685
- const current = await readWorkingPreviewState(root);
25686
- const bare = current.specs.map(({ history: _history, ...s }) => ({ ...s, contributors: [], updatedAt: null }));
25687
- const bareDocuments = current.wiki.documents.map((d) => ({ ...d, updatedAt: null }));
25688
- if (!base.head) return browserSpecsV3.parse({ contract: "browser-specs", version: 3, sessionId, head: null, observedAt: (/* @__PURE__ */ new Date()).toISOString(), working: bare.length > 0 || bareDocuments.length > 0, features: bare, documents: bareDocuments, events: [], contributors: [], contributorsLimited: false, nextCursor: null, boundary: false });
25689
- const head = base.head;
25690
- const first = cursor === 0;
25691
- const features = !first ? void 0 : await Promise.all(bare.map(async (feature2) => {
25692
- const folder = feature2.path.replace(/^\.(?:gitifact|tryce)\/(spec\/[^/]+)\/requirements\.md$/, "$1");
25693
- const lines = (await git(["log", "--format=%aN%x00%aE%x00%aI", "--max-count=2000", head, "--", `.gitifact/${folder}`, `.tryce/${folder}`])).trim().split("\n").filter(Boolean);
25694
- const people = /* @__PURE__ */ new Map();
25695
- for (const line of lines) {
25696
- const [name, email3, latest] = line.split("\0");
25697
- if (!name || !email3 || !latest) throw new SpecPreviewError(t2("specReader.authorUnreadable"));
25698
- const person = people.get(email3);
25699
- if (person) person.commits++;
25700
- else people.set(email3, { name, email: email3, latest, commits: 1 });
25701
- }
25702
- return { ...feature2, contributors: [...people.values()].sort((a, b) => b.commits - a.commits), updatedAt: lines[0]?.split("\0")[2] ?? null };
25703
- }));
25704
- const documents = !first ? void 0 : await Promise.all(bareDocuments.map(async (doc) => ({ ...doc, updatedAt: (await git(["log", "--format=%aI", "--max-count=1", head, "--", doc.path])).trim() || null })));
25705
- const documentDirs = [WIKI_DIR];
25706
- const [rows, dirty] = await Promise.all([
25707
- git([
25708
- "log",
25709
- "--first-parent",
25710
- "--date-order",
25711
- "--format=%H%x00%P%x00%aN%x00%aE%x00%aI%x00%cN%x00%s",
25712
- "--max-count=11",
25713
- "--skip=" + cursor,
25714
- head,
25715
- "--",
25716
- ...[".gitifact", ".tryce"].flatMap((d) => [`:(glob)${d}/spec/*/requirements.md`, `:(glob)${d}/spec/*/design.md`, `:(glob)${d}/spec/*/history.jsonl`]),
25717
- ...documentDirs.flatMap((d) => [`:(glob)${d}/**/*.md`, `:(glob)${d}/history.jsonl`])
25718
- ]),
25719
- first ? git(["status", "--porcelain=v1", "--", ".gitifact/spec", ...documentDirs]) : Promise.resolve("")
25899
+ const head = await readHead();
25900
+ const [current, dirty, authors, everyone] = await settled([
25901
+ readWorkingPreviewState(root),
25902
+ head ? git(["status", "--porcelain=v1", "--", ".gitifact/spec", WIKI_DIR]) : Promise.resolve(""),
25903
+ head ? storeAuthors(head) : Promise.resolve(void 0),
25904
+ // Git mailmap may change without a new HEAD; refresh names with every observation that carries them.
25905
+ head ? git(["log", "--format=%aN%x00%aE%x00%aI", "--max-count=10001", head]) : Promise.resolve("")
25720
25906
  ]);
25721
- if (first) {
25722
- const people = /* @__PURE__ */ new Map();
25723
- const lines = (await git(["log", "--format=%aN%x00%aE%x00%aI", "--max-count=10001", head])).trim().split("\n").filter(Boolean);
25724
- for (const line of lines.slice(0, 1e4)) {
25725
- const [name, email3, latest] = line.split("\0");
25726
- if (!name || !email3 || !latest) throw new SpecPreviewError(t2("specReader.authorUnreadable"));
25727
- const person = people.get(email3);
25728
- if (person) person.commits++;
25729
- else people.set(email3, { name, email: email3, latest, commits: 1 });
25730
- }
25731
- peopleCache = { key: head, data: [...people.values()].sort((a, b) => b.commits - a.commits), limited: lines.length > 1e4 };
25732
- }
25733
- const commits = rows.trim().split("\n").filter(Boolean);
25734
- let boundary = false;
25735
- const groups = await Promise.all(commits.slice(0, 10).map(async (row) => {
25736
- const [commit, parents, author, email3, date5, committer, message] = row.split("\0");
25737
- if (!commit || author === void 0 || email3 === void 0 || !date5 || committer === void 0 || message === void 0) throw new SpecPreviewError(t2("specReader.historyUnreadable"));
25738
- const after = await snapshot3(commit);
25739
- let before = emptyBundle();
25740
- const parent = parents?.split(" ")[0];
25741
- if (parent) {
25742
- try {
25743
- before = await snapshot3(parent);
25744
- } catch (error62) {
25745
- if (error62 instanceof LegacyBaselineError) boundary = true;
25746
- else throw error62;
25747
- }
25748
- }
25749
- return comparePreviewBundles(before, after).changes.map((c) => ({
25750
- key: commit + ":" + c.id,
25751
- commit,
25752
- author,
25753
- email: email3,
25754
- date: date5,
25755
- committer,
25756
- message,
25757
- id: c.id,
25758
- kind: c.kind,
25759
- types: c.types,
25760
- before: c.before,
25761
- after: c.after,
25762
- reasons: c.reasons.map((r) => r.reason)
25763
- }));
25764
- }));
25765
- if (await readHead() !== head || (await readWorkingPreviewState(root)).stamp !== current.stamp) throw new SpecPreviewError(t2("specReader.projectChanged"));
25766
- return browserSpecsV3.parse({
25907
+ const people = /* @__PURE__ */ new Map();
25908
+ const lines = everyone.trim().split("\n").filter(Boolean);
25909
+ for (const line of lines.slice(0, 1e4)) {
25910
+ const [name, email3, latest] = line.split("\0");
25911
+ if (!name || !email3 || !latest) throw new SpecPreviewError(t2("specReader.authorUnreadable"));
25912
+ tally(people, name, email3, latest);
25913
+ }
25914
+ const features = current.specs.map(({ history: _history, ...feature2 }) => {
25915
+ const entry2 = authors?.folders.get(feature2.path.replace(/^\.(?:gitifact|tryce)\/(spec\/[^/]+)\/requirements\.md$/, "$1"));
25916
+ return { ...feature2, contributors: entry2 ? [...entry2.people.values()].sort((a, b) => b.commits - a.commits) : [], updatedAt: entry2?.latest ?? null };
25917
+ });
25918
+ const documents = current.wiki.documents.map((doc) => ({ ...doc, updatedAt: authors?.pages.get(doc.path) ?? null }));
25919
+ if (await readHead() !== head) throw new SpecPreviewError(t2("specReader.projectChanged"));
25920
+ const checkout = browserSpecsV4.parse({
25767
25921
  contract: "browser-specs",
25768
- version: 3,
25922
+ version: 4,
25769
25923
  sessionId,
25770
25924
  head,
25771
25925
  observedAt: (/* @__PURE__ */ new Date()).toISOString(),
25772
- events: groups.flat(),
25773
- nextCursor: commits.length > 10 ? cursor + 10 : null,
25774
- boundary,
25775
- ...first ? { working: !!dirty.trim(), features, documents, contributors: peopleCache?.data ?? [], contributorsLimited: peopleCache?.limited ?? false } : {}
25926
+ working: head ? !!dirty.trim() : features.length > 0 || documents.length > 0,
25927
+ features,
25928
+ documents,
25929
+ contributors: [...people.values()].sort((a, b) => b.commits - a.commits),
25930
+ contributorsLimited: lines.length > 1e4
25931
+ });
25932
+ const search = features.flatMap((f) => [
25933
+ { kind: "feature", ref: f.id, title: f.title, where: f.path.replace(/^\.gitifact\//, ""), body: f.description, featureId: f.id },
25934
+ ...f.requirements.map((r) => ({ kind: "requirement", ref: r.id, title: r.title, where: f.title, body: r.body, featureId: f.id })),
25935
+ ...f.design ? [{ kind: "design", ref: f.id + ":design", title: f.design.title, where: f.title, body: f.design.body, featureId: f.id }] : []
25936
+ ]).concat(documents.map((d) => ({ kind: "document", ref: d.id, title: d.title, where: d.path.replace(/^\.gitifact\/wiki\//, ""), body: d.body, documentId: d.id })));
25937
+ return { checkout, stamp: current.stamp, search };
25938
+ }
25939
+ return () => {
25940
+ let value = pending.get("");
25941
+ if (!value) {
25942
+ value = read().finally(() => pending.delete(""));
25943
+ pending.set("", value);
25944
+ }
25945
+ return value;
25946
+ };
25947
+ }
25948
+
25949
+ // src/server/history/commit-changes.ts
25950
+ var HISTORY_PATHSPECS = [
25951
+ ...STORE_DIRS.flatMap((d) => [`:(glob)${d}/spec/*/requirements.md`, `:(glob)${d}/spec/*/design.md`, `:(glob)${d}/spec/*/history.jsonl`]),
25952
+ `:(glob)${WIKI_DIR}/**/*.md`,
25953
+ `:(glob)${WIKI_HISTORY_PATH}`
25954
+ ];
25955
+ var RECORD_ROOTS = [...STORE_DIRS.map((d) => d + "/spec/"), WIKI_DIR + "/"];
25956
+ var isLegacy = (path3) => RECORD_ROOTS.some((root) => path3.startsWith(root)) && path3.endsWith("/tryce.json");
25957
+ var isZero = (oid3) => /^0+$/.test(oid3);
25958
+ var FORMAT = "%x1e%H%x00%P%x00%aN%x00%aE%x00%aI%x00%cN%x00%s";
25959
+ var BATCH = 100;
25960
+ function createCommitChanges(root, snapshot3) {
25961
+ const reader = specPreviewReader(root);
25962
+ function parseLog(text2) {
25963
+ return text2.split("").filter((chunk) => chunk.length).map((chunk) => {
25964
+ const parts = chunk.split("\0");
25965
+ const [commit, parents, author, email3, date5, committer, message] = parts;
25966
+ if (!commit || parents === void 0 || author === void 0 || email3 === void 0 || !date5 || committer === void 0 || message === void 0) throw new SpecPreviewError(t2("specReader.historyUnreadable"));
25967
+ const entries = [];
25968
+ for (let i = 7; i < parts.length; i++) {
25969
+ const meta3 = parts[i].replace(/^\n/, "");
25970
+ if (!meta3.startsWith(":")) continue;
25971
+ const [, , oldBlob, newBlob] = meta3.split(" ");
25972
+ const path3 = parts[++i];
25973
+ if (!oldBlob || !newBlob || path3 === void 0) throw new SpecPreviewError(t2("specReader.historyUnreadable"));
25974
+ if (recordPathPattern.test(path3) || isLegacy(path3)) entries.push({ oldBlob, newBlob, path: path3 });
25975
+ }
25976
+ return { commit, parent: parents.split(" ")[0] || void 0, author, email: email3, date: date5, committer, message, entries };
25977
+ });
25978
+ }
25979
+ function wanted(entries) {
25980
+ const folders = /* @__PURE__ */ new Set();
25981
+ const pages = /* @__PURE__ */ new Set();
25982
+ for (const { path: path3 } of entries) {
25983
+ if (isLegacy(path3)) continue;
25984
+ if (path3.startsWith(WIKI_DIR + "/")) {
25985
+ pages.add(path3);
25986
+ pages.add(WIKI_HISTORY_PATH);
25987
+ continue;
25988
+ }
25989
+ folders.add(path3.replace(/\/[^/]+$/, ""));
25990
+ }
25991
+ return [...[...folders].flatMap((f) => ["requirements.md", "design.md", "history.jsonl"].map((n) => f + "/" + n)), ...pages];
25992
+ }
25993
+ async function readBlobs(names) {
25994
+ const found = /* @__PURE__ */ new Map();
25995
+ if (!names.length) return found;
25996
+ const output2 = await reader.run(["cat-file", "--batch"], Buffer.from(names.join("\n") + "\n"));
25997
+ let offset = 0;
25998
+ let total = 0;
25999
+ for (const name of names) {
26000
+ const end = output2.indexOf(10, offset);
26001
+ if (end < 0) throw new SpecPreviewError(t2("reader.blobBoundary"));
26002
+ const header = output2.subarray(offset, end).toString("utf8");
26003
+ if (header.endsWith(" missing")) {
26004
+ offset = end + 1;
26005
+ continue;
26006
+ }
26007
+ const [, type, sizeText] = header.split(" ");
26008
+ const size = Number(sizeText);
26009
+ if (type !== "blob" || !Number.isSafeInteger(size) || size < 0 || size > 1024 * 1024 || output2[end + size + 1] !== 10) throw new SpecPreviewError(t2("reader.blobShape"));
26010
+ total += size;
26011
+ if (total > 64 * 1024 * 1024) throw new SpecPreviewError(t2("reader.totalLimit"));
26012
+ found.set(name, reader.decode(output2.subarray(end + 1, end + 1 + size)));
26013
+ offset = end + size + 2;
26014
+ }
26015
+ if (offset !== output2.length) throw new SpecPreviewError(t2("reader.blobBoundary"));
26016
+ return found;
26017
+ }
26018
+ const eventsOf = (c, changes) => changes.map((change2) => ({
26019
+ key: c.commit + ":" + change2.id,
26020
+ commit: c.commit,
26021
+ author: c.author,
26022
+ email: c.email,
26023
+ date: c.date,
26024
+ committer: c.committer,
26025
+ message: c.message,
26026
+ id: change2.id,
26027
+ kind: change2.kind,
26028
+ types: change2.types,
26029
+ before: change2.before,
26030
+ after: change2.after,
26031
+ reasons: change2.reasons.map((r) => r.reason)
26032
+ }));
26033
+ async function wholeStore(c) {
26034
+ const after = await snapshot3(c.commit);
26035
+ let before = emptyBundle();
26036
+ let boundary = false;
26037
+ if (c.parent) {
26038
+ try {
26039
+ before = await snapshot3(c.parent);
26040
+ } catch (error62) {
26041
+ if (error62 instanceof LegacyBaselineError) boundary = true;
26042
+ else throw error62;
26043
+ }
26044
+ }
26045
+ return { commit: c.commit, events: eventsOf(c, comparePreviewBundles(before, after).changes), boundary };
26046
+ }
26047
+ async function batch(commits) {
26048
+ const names = /* @__PURE__ */ new Map();
26049
+ for (const c of commits.filter((c2) => !c2.entries.some((e) => isLegacy(e.path) && !isZero(e.newBlob)))) {
26050
+ const files = wanted(c.entries);
26051
+ const boundary = c.entries.some((e) => isLegacy(e.path) && !isZero(e.oldBlob));
26052
+ names.set(c, { after: files.map((f) => c.commit + ":" + f), before: c.parent && !boundary ? files.map((f) => c.parent + ":" + f) : [], boundary });
26053
+ }
26054
+ let blobs;
26055
+ try {
26056
+ blobs = await readBlobs([...names.values()].flatMap((n) => [...n.before, ...n.after]));
26057
+ } catch {
26058
+ blobs = void 0;
26059
+ }
26060
+ const result = [];
26061
+ for (const c of commits) {
26062
+ let value;
26063
+ const want = names.get(c);
26064
+ if (want && blobs) {
26065
+ try {
26066
+ const side = (list, rev) => new Map(list.filter((name) => blobs.has(name)).map((name) => [name.slice(rev.length + 1), blobs.get(name)]));
26067
+ const after = parsePreviewBundle(side(want.after, c.commit));
26068
+ const before = want.before.length ? parsePreviewBundle(side(want.before, c.parent)) : emptyBundle();
26069
+ value = { commit: c.commit, events: eventsOf(c, comparePreviewBundles(before, after).changes), boundary: want.boundary };
26070
+ } catch {
26071
+ value = void 0;
26072
+ }
26073
+ }
26074
+ result.push(value ?? await wholeStore(c));
26075
+ }
26076
+ return result;
26077
+ }
26078
+ return {
26079
+ /** The commits of `head`'s first-parent history that touched records, newest first. One Git process. */
26080
+ async lineage(head) {
26081
+ const text2 = reader.decode(await reader.run(["rev-list", "--first-parent", head, "--", ...HISTORY_PATHSPECS]));
26082
+ return text2.split("\n").filter(Boolean);
26083
+ },
26084
+ /** The changes of the given commits, in the given order; two Git processes per hundred commits. */
26085
+ async of(commits) {
26086
+ const out = [];
26087
+ for (let i = 0; i < commits.length; i += BATCH) {
26088
+ const slice = commits.slice(i, i + BATCH);
26089
+ const raw = parseLog(reader.decode(await reader.run(
26090
+ ["log", "--stdin", "--no-walk=unsorted", "--diff-merges=first-parent", "--raw", "-z", "--no-renames", "--no-abbrev", `--format=${FORMAT}`],
26091
+ Buffer.from(slice.join("\n") + "\n")
26092
+ )));
26093
+ const byCommit = new Map(raw.map((c) => [c.commit, c]));
26094
+ const missing2 = slice.find((oid3) => !byCommit.has(oid3));
26095
+ if (missing2) throw new SpecPreviewError(t2("specReader.historyUnreadable"));
26096
+ out.push(...await batch(slice.map((oid3) => byCommit.get(oid3))));
26097
+ }
26098
+ return out;
26099
+ }
26100
+ };
26101
+ }
26102
+
26103
+ // src/server/history/index-database.ts
26104
+ import { DatabaseSync } from "node:sqlite";
26105
+ import { mkdir as mkdir3, rm } from "node:fs/promises";
26106
+ import { join as join5 } from "node:path";
26107
+ var INDEX_FORMAT = 1;
26108
+ var SCHEMA = `
26109
+ -- Commits already read, and whether the commit's parent was legacy JSON the history does not read past.
26110
+ CREATE TABLE commits (oid TEXT PRIMARY KEY, boundary INTEGER NOT NULL);
26111
+ -- One row per change. 'row' is the list shape as JSON; 'detail' the text on both sides.
26112
+ CREATE TABLE changes (
26113
+ key TEXT PRIMARY KEY, oid TEXT NOT NULL, ord INTEGER NOT NULL,
26114
+ id TEXT NOT NULL, kind TEXT NOT NULL, types TEXT NOT NULL, email TEXT NOT NULL, date TEXT NOT NULL,
26115
+ before_spec TEXT, after_spec TEXT, needle TEXT NOT NULL, row TEXT NOT NULL, detail TEXT NOT NULL);
26116
+ CREATE INDEX changes_by_commit ON changes (oid, ord);
26117
+ -- The commits of one HEAD's first-parent history that touched records, newest first (pos 0).
26118
+ CREATE TABLE lineage (head TEXT NOT NULL, pos INTEGER NOT NULL, oid TEXT NOT NULL, PRIMARY KEY (head, pos));
26119
+ CREATE INDEX lineage_by_commit ON lineage (head, oid);
26120
+ CREATE TABLE heads (head TEXT PRIMARY KEY, seen INTEGER NOT NULL);
26121
+ -- Which checkout of which worktree the search rows describe.
26122
+ CREATE TABLE checkouts (scope TEXT PRIMARY KEY, stamp TEXT NOT NULL);
26123
+ -- Everything the search box finds. The searched columns hold lower-cased text; trigram lets LIKE '%...%' use the
26124
+ -- index from three characters on and scan below that. The rest is carried for display and navigation.
26125
+ CREATE VIRTUAL TABLE search USING fts5(
26126
+ scope UNINDEXED, kind UNINDEXED, ref UNINDEXED, oid UNINDEXED, payload UNINDEXED,
26127
+ title, place, body, tokenize = 'trigram');
26128
+ `;
26129
+ function prepare(db) {
26130
+ db.exec("PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL;");
26131
+ const version2 = db.prepare("PRAGMA user_version").get().user_version;
26132
+ if (version2 === INDEX_FORMAT) return;
26133
+ db.exec("BEGIN IMMEDIATE");
26134
+ try {
26135
+ for (const { name, type } of db.prepare("SELECT name, type FROM sqlite_master WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'search_%'").all()) {
26136
+ db.exec(`DROP ${type === "view" ? "VIEW" : "TABLE"} IF EXISTS "${name}"`);
26137
+ }
26138
+ db.exec(SCHEMA);
26139
+ db.exec(`PRAGMA user_version = ${INDEX_FORMAT}`);
26140
+ db.exec("COMMIT");
26141
+ } catch (error62) {
26142
+ db.exec("ROLLBACK");
26143
+ throw error62;
26144
+ }
26145
+ }
26146
+ function createIndexDatabase(root) {
26147
+ let path3;
26148
+ let memory;
26149
+ const usable = (file2) => {
26150
+ try {
26151
+ const probe = new DatabaseSync(file2);
26152
+ try {
26153
+ prepare(probe);
26154
+ } finally {
26155
+ probe.close();
26156
+ }
26157
+ return true;
26158
+ } catch {
26159
+ return false;
26160
+ }
26161
+ };
26162
+ const locate = () => path3 ??= (async () => {
26163
+ try {
26164
+ const git = specPreviewReader(root);
26165
+ const common = git.decode(await git.run(["rev-parse", "--path-format=absolute", "--git-common-dir"])).trim();
26166
+ const folder = join5(common, "gitifact");
26167
+ await mkdir3(folder, { recursive: true });
26168
+ const file2 = join5(folder, "index.sqlite");
26169
+ if (usable(file2)) return file2;
26170
+ for (const leftover of [file2, file2 + "-wal", file2 + "-shm"]) await rm(leftover, { force: true });
26171
+ return usable(file2) ? file2 : void 0;
26172
+ } catch {
26173
+ return void 0;
26174
+ }
26175
+ })();
26176
+ return {
26177
+ /** Runs `use` on an open database. Everything inside is synchronous, so the connection never outlives the call. */
26178
+ async with(use) {
26179
+ const file2 = await locate();
26180
+ if (!file2) {
26181
+ if (!memory) {
26182
+ memory = new DatabaseSync(":memory:");
26183
+ prepare(memory);
26184
+ }
26185
+ return use(memory);
26186
+ }
26187
+ const db = new DatabaseSync(file2);
26188
+ try {
26189
+ prepare(db);
26190
+ return use(db);
26191
+ } finally {
26192
+ db.close();
26193
+ }
26194
+ },
26195
+ /** Where the index is kept, or undefined when it lives in memory. */
26196
+ location: () => locate()
26197
+ };
26198
+ }
26199
+ function transaction(db, write) {
26200
+ db.exec("BEGIN IMMEDIATE");
26201
+ try {
26202
+ const value = write();
26203
+ db.exec("COMMIT");
26204
+ return value;
26205
+ } catch (error62) {
26206
+ db.exec("ROLLBACK");
26207
+ throw error62;
26208
+ }
26209
+ }
26210
+
26211
+ // src/server/history/search-text.ts
26212
+ function plain(body) {
26213
+ return body.replace(/```[\s\S]*?```/g, " ").replace(/<!--[\s\S]*?-->/g, " ").replace(/^\s*[#>]+\s*/gm, " ").replace(/^\s*[-*+]\s+/gm, " ").replace(/^\s*\|/gm, " ").replace(/\|/g, " ").replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[*_`]/g, "").replace(/\s+/g, " ").trim();
26214
+ }
26215
+ function snippet(text2, query) {
26216
+ const at = text2.toLowerCase().indexOf(query);
26217
+ if (at < 0) return text2.slice(0, 90);
26218
+ const from = Math.max(0, at - 30);
26219
+ return (from > 0 ? "\u2026" : "") + text2.slice(from, at + query.length + 70).trim() + (at + query.length + 70 < text2.length ? "\u2026" : "");
26220
+ }
26221
+ var containing = (query) => "%" + query.replace(/[\\%_]/g, (c) => "\\" + c) + "%";
26222
+
26223
+ // src/server/history/history-index.ts
26224
+ var listed = (e) => {
26225
+ const reference2 = (s) => s ? { id: s.id, title: s.title, specId: s.specId, path: s.path } : null;
26226
+ return { ...e, before: reference2(e.before), after: reference2(e.after) };
26227
+ };
26228
+ var titleOf = (e) => (e.after ?? e.before)?.title ?? e.id;
26229
+ var DAY = 864e5;
26230
+ var KEPT_HEADS = 4;
26231
+ var RECENT_COMMITS = 3;
26232
+ var RECENT_CHANGES = 12;
26233
+ function createHistoryIndex(root, snapshot3) {
26234
+ const changes = createCommitChanges(root, snapshot3);
26235
+ const database = createIndexDatabase(root);
26236
+ const building = /* @__PURE__ */ new Map();
26237
+ const built = /* @__PURE__ */ new Set();
26238
+ function insert(db, commits) {
26239
+ const commit = db.prepare("INSERT OR IGNORE INTO commits (oid, boundary) VALUES (?, ?)");
26240
+ const change2 = db.prepare("INSERT OR IGNORE INTO changes (key, oid, ord, id, kind, types, email, date, before_spec, after_spec, needle, row, detail) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)");
26241
+ const search = db.prepare("INSERT INTO search (scope, kind, ref, oid, payload, title, place, body) VALUES (?,?,?,?,?,?,?,?)");
26242
+ transaction(db, () => {
26243
+ for (const c of commits) {
26244
+ if (!Number(commit.run(c.commit, c.boundary ? 1 : 0).changes)) continue;
26245
+ c.events.forEach((e, ord) => {
26246
+ change2.run(
26247
+ e.key,
26248
+ e.commit,
26249
+ ord,
26250
+ e.id,
26251
+ e.kind,
26252
+ e.types.join(","),
26253
+ e.email,
26254
+ e.date,
26255
+ e.before?.specId ?? null,
26256
+ e.after?.specId ?? null,
26257
+ [e.id, e.before?.title ?? "", e.after?.title ?? ""].join(" ").toLowerCase(),
26258
+ JSON.stringify(listed(e)),
26259
+ JSON.stringify({ before: e.before, after: e.after })
26260
+ );
26261
+ const line = e.reasons.length ? e.reasons.join(" \xB7 ") : e.message;
26262
+ const where2 = e.commit.slice(0, 7) + " \xB7 " + e.author;
26263
+ search.run(
26264
+ "history",
26265
+ "history",
26266
+ e.key,
26267
+ e.commit,
26268
+ JSON.stringify({ title: titleOf(e), where: where2, line }),
26269
+ titleOf(e).toLowerCase(),
26270
+ where2.toLowerCase(),
26271
+ [line, e.message, e.id].join(" ").toLowerCase()
26272
+ );
26273
+ });
26274
+ }
25776
26275
  });
25777
26276
  }
25778
- return (cursor = 0, head) => {
25779
- const key = `${cursor}:${head ?? ""}`;
25780
- let value = pending.get(key);
26277
+ async function build(head) {
26278
+ const lineage = await changes.lineage(head);
26279
+ const known = await database.with((db) => new Set(db.prepare("SELECT oid FROM commits").all().map((r) => r.oid)));
26280
+ const missing2 = lineage.filter((oid3) => !known.has(oid3));
26281
+ for (let i = 0; i < missing2.length; i += 100) {
26282
+ const read = await changes.of(missing2.slice(i, i + 100));
26283
+ await database.with((db) => insert(db, read));
26284
+ }
26285
+ await database.with((db) => transaction(db, () => {
26286
+ db.prepare("DELETE FROM lineage WHERE head = ?").run(head);
26287
+ const row = db.prepare("INSERT INTO lineage (head, pos, oid) VALUES (?, ?, ?)");
26288
+ lineage.forEach((oid3, pos) => row.run(head, pos, oid3));
26289
+ db.prepare("INSERT INTO heads (head, seen) VALUES (?, ?) ON CONFLICT (head) DO UPDATE SET seen = excluded.seen").run(head, Date.now());
26290
+ for (const { head: old } of db.prepare("SELECT head FROM heads ORDER BY seen DESC LIMIT -1 OFFSET ?").all(KEPT_HEADS)) {
26291
+ db.prepare("DELETE FROM lineage WHERE head = ?").run(old);
26292
+ db.prepare("DELETE FROM heads WHERE head = ?").run(old);
26293
+ }
26294
+ }));
26295
+ }
26296
+ function ensure(head) {
26297
+ if (built.has(head)) return Promise.resolve();
26298
+ let pending = building.get(head);
26299
+ if (!pending) {
26300
+ pending = build(head).then(() => {
26301
+ built.add(head);
26302
+ }).finally(() => building.delete(head));
26303
+ building.set(head, pending);
26304
+ }
26305
+ return pending;
26306
+ }
26307
+ function where(filter) {
26308
+ const clauses = [];
26309
+ const params = [];
26310
+ if (filter.kind) {
26311
+ clauses.push("instr(',' || c.types || ',', ?) > 0");
26312
+ params.push("," + filter.kind + ",");
26313
+ }
26314
+ if (filter.document) {
26315
+ clauses.push("c.kind = ?");
26316
+ params.push(filter.document);
26317
+ }
26318
+ if (filter.feature) {
26319
+ clauses.push("(c.before_spec = ? OR c.after_spec = ?)");
26320
+ params.push(filter.feature, filter.feature);
26321
+ }
26322
+ if (filter.author) {
26323
+ clauses.push("c.email = ?");
26324
+ params.push(filter.author);
26325
+ }
26326
+ if (filter.q?.trim()) {
26327
+ clauses.push("instr(c.needle, ?) > 0");
26328
+ params.push(filter.q.trim().toLowerCase());
26329
+ }
26330
+ return { sql: clauses.map((c) => " AND " + c).join(""), params };
26331
+ }
26332
+ return {
26333
+ ensure,
26334
+ /** One page of the changes that match, newest first, with how many match in all. */
26335
+ async page(head, filter, offset, limit) {
26336
+ await ensure(head);
26337
+ return database.with((db) => {
26338
+ const { sql, params } = where(filter);
26339
+ const from = "FROM lineage l JOIN changes c ON c.oid = l.oid WHERE l.head = ?" + sql;
26340
+ const total = Number(db.prepare("SELECT count(*) AS n " + from).get(head, ...params).n);
26341
+ const rows = db.prepare(`SELECT c.row ${from} ORDER BY l.pos, c.ord LIMIT ? OFFSET ?`).all(head, ...params, limit, offset);
26342
+ const boundary = !!db.prepare("SELECT 1 FROM lineage l JOIN commits m ON m.oid = l.oid WHERE l.head = ? AND m.boundary = 1 LIMIT 1").get(head);
26343
+ return { total, events: rows.map((r) => JSON.parse(r.row)), boundary };
26344
+ });
26345
+ },
26346
+ /** Counts over all of history and its newest commits, for the overview. */
26347
+ async summary(head) {
26348
+ await ensure(head);
26349
+ return database.with((db) => {
26350
+ const from = "FROM lineage l JOIN changes c ON c.oid = l.oid WHERE l.head = ?";
26351
+ const count2 = (type) => Number(db.prepare(`SELECT count(*) AS n ${from} AND instr(',' || c.types || ',', ?) > 0`).get(head, "," + type + ",").n);
26352
+ const total = Number(db.prepare(`SELECT count(*) AS n ${from}`).get(head).n);
26353
+ const commits = db.prepare(`SELECT l.oid AS oid, max(c.date) AS date, count(*) AS n ${from} GROUP BY l.pos, l.oid ORDER BY l.pos`).all(head);
26354
+ const newest = Math.max(0, ...commits.map((c) => Date.parse(c.date)).filter(Number.isFinite));
26355
+ const pulse = commits.filter((c) => Date.parse(c.date) >= newest - 22 * DAY).map((c) => ({ date: c.date, count: Number(c.n) }));
26356
+ const recent = commits.slice(0, RECENT_COMMITS).map((c) => ({
26357
+ commit: c.oid,
26358
+ count: Number(c.n),
26359
+ events: db.prepare("SELECT row FROM changes WHERE oid = ? ORDER BY ord LIMIT ?").all(c.oid, RECENT_CHANGES).map((r) => JSON.parse(r.row))
26360
+ }));
26361
+ return { total, byType: { created: count2("created"), modified: count2("modified"), moved: count2("moved"), deleted: count2("deleted") }, pulse, recent };
26362
+ });
26363
+ },
26364
+ /** One change with the text on both sides; a commit the index has not read yet is read now. */
26365
+ async change(key) {
26366
+ const lookup = () => database.with((db) => db.prepare("SELECT row, detail FROM changes WHERE key = ?").get(key));
26367
+ let found = await lookup();
26368
+ if (!found) {
26369
+ const commit = key.slice(0, key.indexOf(":"));
26370
+ const known = await database.with((db) => !!db.prepare("SELECT 1 FROM commits WHERE oid = ?").get(commit));
26371
+ if (known) return void 0;
26372
+ const read = await changes.of([commit]).catch(() => void 0);
26373
+ if (!read) return void 0;
26374
+ await database.with((db) => insert(db, read));
26375
+ found = await lookup();
26376
+ }
26377
+ if (!found) return void 0;
26378
+ const detail = JSON.parse(found.detail);
26379
+ return { event: JSON.parse(found.row), before: detail.before, after: detail.after };
26380
+ },
26381
+ /** Replaces the search rows of one worktree's checkout when it changed since they were written. */
26382
+ async syncCheckout(scope, stamp, documents) {
26383
+ await database.with((db) => {
26384
+ const current = db.prepare("SELECT stamp FROM checkouts WHERE scope = ?").get(scope);
26385
+ if (current?.stamp === stamp) return;
26386
+ transaction(db, () => {
26387
+ db.prepare("DELETE FROM search WHERE scope = ?").run(scope);
26388
+ const row = db.prepare("INSERT INTO search (scope, kind, ref, oid, payload, title, place, body) VALUES (?,?,?,?,?,?,?,?)");
26389
+ for (const d of documents) {
26390
+ const body = plain(d.body);
26391
+ row.run(
26392
+ scope,
26393
+ d.kind,
26394
+ d.ref,
26395
+ null,
26396
+ JSON.stringify({ title: d.title, where: d.where, body, featureId: d.featureId, documentId: d.documentId }),
26397
+ d.title.toLowerCase(),
26398
+ d.where.toLowerCase(),
26399
+ body.toLowerCase()
26400
+ );
26401
+ }
26402
+ db.prepare("INSERT INTO checkouts (scope, stamp) VALUES (?, ?) ON CONFLICT (scope) DO UPDATE SET stamp = excluded.stamp").run(scope, stamp);
26403
+ });
26404
+ });
26405
+ },
26406
+ /**
26407
+ * Records whose title, place or text holds the query. The checkout comes first — a title match before a place
26408
+ * match before a text match — then past changes of `head`'s history, newest first.
26409
+ */
26410
+ async search(scope, head, raw) {
26411
+ const query = raw.trim().toLowerCase();
26412
+ if (!query) return [];
26413
+ if (head) await ensure(head);
26414
+ return database.with((db) => {
26415
+ const literal2 = /[\\%_]/.test(query);
26416
+ const match = (column) => literal2 ? `instr(${column}, ?) > 0` : `${column} LIKE ?`;
26417
+ const needle = literal2 ? query : containing(query);
26418
+ const found = db.prepare(`SELECT kind, ref, payload, title, place, body FROM search WHERE scope = ? AND (${match("title")} OR ${match("place")} OR ${match("body")}) LIMIT 400`).all(scope, needle, needle, needle);
26419
+ const documents = found.map((r) => {
26420
+ const at = r.title.indexOf(query);
26421
+ const rank = at === 0 ? 0 : at > 0 ? 1 : r.place.includes(query) ? 2 : 3;
26422
+ const p = JSON.parse(r.payload);
26423
+ const hit = {
26424
+ id: r.ref,
26425
+ kind: r.kind,
26426
+ title: p.title,
26427
+ where: p.where,
26428
+ line: snippet(p.body, query),
26429
+ ...p.featureId ? { featureId: p.featureId } : {},
26430
+ ...p.documentId ? { documentId: p.documentId } : {}
26431
+ };
26432
+ return { rank, hit };
26433
+ }).sort((a, b) => a.rank - b.rank || a.hit.title.localeCompare(b.hit.title)).slice(0, 24).map((r) => r.hit);
26434
+ const past = !head ? [] : db.prepare(`SELECT s.ref AS ref, s.payload AS payload FROM search s JOIN lineage l ON l.head = ? AND l.oid = s.oid
26435
+ WHERE s.scope = 'history' AND (${match("s.title")} OR ${match("s.body")}) ORDER BY l.pos LIMIT 8`).all(head, needle, needle).map((r) => {
26436
+ const p = JSON.parse(r.payload);
26437
+ return { id: r.ref, kind: "history", title: p.title, where: p.where, line: snippet(p.line, query), key: r.ref };
26438
+ });
26439
+ return [...documents, ...past];
26440
+ });
26441
+ }
26442
+ };
26443
+ }
26444
+
26445
+ // src/server/routes/record-routes.ts
26446
+ var PAGE = 50;
26447
+ function recordRoutes(root, sessionId, env) {
26448
+ const reader = specPreviewReader(root);
26449
+ const snapshots = /* @__PURE__ */ new Map();
26450
+ const snapshot3 = (oid3) => {
26451
+ let value = snapshots.get(oid3);
25781
26452
  if (!value) {
25782
- value = read(cursor, head).finally(() => pending.delete(key));
25783
- pending.set(key, value);
26453
+ value = reader.readBundle(oid3).catch((e) => {
26454
+ snapshots.delete(oid3);
26455
+ throw e;
26456
+ });
26457
+ snapshots.set(oid3, value);
25784
26458
  }
26459
+ if (snapshots.size > 128) snapshots.delete(snapshots.keys().next().value);
25785
26460
  return value;
25786
26461
  };
26462
+ const readCheckout = createCheckoutReader(root, sessionId, env);
26463
+ const history = createHistoryIndex(root, snapshot3);
26464
+ const scope = "checkout:" + root;
26465
+ const unreadable = t2("server.specsUnreadable");
26466
+ let synced;
26467
+ const checkout = async () => {
26468
+ const read = await readCheckout();
26469
+ synced = history.syncCheckout(scope, read.stamp, read.search);
26470
+ await synced;
26471
+ return read.checkout;
26472
+ };
26473
+ return [
26474
+ route({ method: "GET", path: "/api/v1/specs", session: true, unreadable, handle: async () => {
26475
+ return ok(await checkout());
26476
+ } }),
26477
+ route({ method: "GET", path: "/api/v1/history", session: true, query: browserHistoryQueryV1, unreadable, handle: async ({ query }) => {
26478
+ const offset = query.offset ?? 0;
26479
+ const page = await history.page(query.head, { kind: query.kind, document: query.document, feature: query.feature, author: query.author, q: query.q }, offset, query.limit ?? PAGE);
26480
+ return ok(browserHistoryV1.parse({ contract: "browser-history", version: 1, sessionId, head: query.head, offset, ...page }));
26481
+ } }),
26482
+ route({ method: "GET", path: "/api/v1/history/summary", session: true, query: browserHistorySummaryQueryV1, unreadable, handle: async ({ query }) => ok(browserHistorySummaryV1.parse({ contract: "browser-history-summary", version: 1, sessionId, head: query.head, ...await history.summary(query.head) })) }),
26483
+ route({ method: "GET", path: "/api/v1/change", session: true, query: browserChangeQueryV1, unreadable, handle: async ({ query }) => {
26484
+ const change2 = await history.change(query.key);
26485
+ if (!change2) throw new HttpError(404, "NOT_FOUND", t2("server.changeNotFound"));
26486
+ return ok(browserChangeV1.parse({ contract: "browser-change", version: 1, sessionId, ...change2 }));
26487
+ } }),
26488
+ route({ method: "GET", path: "/api/v1/search", session: true, query: browserSearchQueryV1, unreadable, handle: async ({ query }) => {
26489
+ await (synced ?? checkout()).catch(() => void 0);
26490
+ return ok(browserSearchV1.parse({ contract: "browser-search", version: 1, sessionId, query: query.q, hits: await history.search(scope, query.head ?? null, query.q) }));
26491
+ } })
26492
+ ];
26493
+ }
26494
+
26495
+ // src/server/routes/asset-routes.ts
26496
+ import { lstat as lstat4, readFile as readFile4 } from "node:fs/promises";
26497
+ import { join as join6 } from "node:path";
26498
+ function assetRoutes(root) {
26499
+ return [
26500
+ route({ method: "GET", path: "/api/v1/assets/*", session: false, handle: async ({ path: path3, response }) => {
26501
+ const relative = path3.slice("/api/v1/assets/".length);
26502
+ const assetPath = ASSETS_DIR + "/" + relative;
26503
+ if (!isAssetPath(assetPath)) throw new HttpError(404, "NOT_FOUND", t2("server.assetNotFound"));
26504
+ const file2 = join6(root, ...assetPath.split("/"));
26505
+ const stat3 = await lstat4(file2).catch(() => void 0);
26506
+ if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > 20 * 1024 * 1024) throw new HttpError(404, "NOT_FOUND", t2("server.assetNotFound"));
26507
+ const bytes = await readFile4(file2);
26508
+ const extension = assetExtension(relative);
26509
+ const inline = ["png", "jpg", "jpeg", "gif", "webp", "svg"].includes(extension);
26510
+ response.writeHead(200, {
26511
+ "Content-Type": contentType("." + extension),
26512
+ "Cache-Control": "no-cache",
26513
+ "Content-Length": bytes.length,
26514
+ "Content-Security-Policy": "default-src 'none'; sandbox",
26515
+ "Content-Disposition": inline ? "inline" : 'attachment; filename="' + encodeURIComponent(relative.split("/").pop()) + '"'
26516
+ });
26517
+ response.end(bytes);
26518
+ return void 0;
26519
+ } })
26520
+ ];
25787
26521
  }
25788
26522
 
25789
26523
  // src/server/browser-server.ts
25790
- var readBundledChangelog = (language) => readFile4(new URL("./i18n/" + language + "/changelog.md", import.meta.url), "utf8").catch((error62) => {
26524
+ var readBundledChangelog = (language) => readFile5(new URL("./i18n/" + language + "/changelog.md", import.meta.url), "utf8").catch((error62) => {
25791
26525
  if (error62.code === "ENOENT") return null;
25792
26526
  throw error62;
25793
26527
  });
@@ -25812,127 +26546,24 @@ async function startBrowserServer(options) {
25812
26546
  }
25813
26547
  const store = createStatusSession(initial, () => read(controller.signal), options.cliVersion);
25814
26548
  const sessionId = store.session.sessionId;
25815
- const readChangelog = options.readChangelog ?? readBundledChangelog;
26549
+ const root = initial.repository.rootPath;
26550
+ const routes = [
26551
+ ...projectRoutes(store, options.readChangelog ?? readBundledChangelog),
26552
+ ...recordRoutes(root, sessionId, options.env),
26553
+ ...assetRoutes(root)
26554
+ ];
25816
26555
  let updatePending;
25817
26556
  let closing = false;
25818
26557
  let origin = "";
25819
- const readSpecs = createSpecBrowserReader(initial.repository.rootPath, sessionId, options.env);
25820
- function json2(response, status, value) {
25821
- response.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
25822
- response.end(JSON.stringify(value) + "\n");
25823
- }
25824
- function fail8(response, status, code, message) {
25825
- json2(response, status, browserHttpErrorV1.parse({ contract: "browser-http-error", version: 1, error: { code, message } }));
25826
- }
25827
- async function handle(request, response) {
25828
- response.setHeader("X-Content-Type-Options", "nosniff");
25829
- response.setHeader("X-Frame-Options", "DENY");
25830
- response.setHeader("Referrer-Policy", "no-referrer");
25831
- response.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; base-uri 'none'; frame-ancestors 'none'");
25832
- if (closing) return fail8(response, 503, "SERVER_CLOSING", t2("server.closing"));
25833
- if (request.headers.host !== new URL(origin).host) return fail8(response, 403, "FORBIDDEN", t2("server.forbiddenHost"));
25834
- const requestOrigin = request.headers.origin;
25835
- const allowedOrigin = requestOrigin === origin || options.dev && requestOrigin === "http://127.0.0.1:5173";
25836
- if (requestOrigin && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.forbiddenOrigin"));
25837
- const raw = request.url ?? "/";
25838
- if (!raw.startsWith("/") || raw.startsWith("//") || raw.includes("\\")) return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25839
- let url2;
25840
- let path3;
25841
- try {
25842
- url2 = new URL(raw, origin);
25843
- path3 = decodeURIComponent(url2.pathname);
25844
- } catch {
25845
- return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25846
- }
25847
- if (path3.includes("\0") || path3.includes("\\") || path3.split("/").some((part) => part === ".." || part === ".")) {
25848
- return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25849
- }
25850
- if (request.headers["transfer-encoding"] || request.headers["content-length"] && request.headers["content-length"] !== "0") {
25851
- request.resume();
25852
- return fail8(response, 400, "BAD_REQUEST", t2("server.noBody"));
25853
- }
25854
- const api = path3 === "/api" || path3.startsWith("/api/");
25855
- if (api) {
25856
- if (request.headers["sec-fetch-site"] === "cross-site" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.crossSite"));
25857
- if (url2.search && path3 !== "/api/v1/specs" && path3 !== "/api/v1/changelog") return fail8(response, 400, "BAD_REQUEST", t2("server.noQuery"));
25858
- if (path3.startsWith("/api/v1/assets/")) {
25859
- const relative = path3.slice("/api/v1/assets/".length);
25860
- const assetPath2 = ASSETS_DIR + "/" + relative;
25861
- if (request.method !== "GET") {
25862
- response.setHeader("Allow", "GET");
25863
- return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25864
- }
25865
- if (!isAssetPath(assetPath2)) return fail8(response, 404, "NOT_FOUND", t2("server.assetNotFound"));
25866
- const file2 = join5(initial.repository.rootPath, ...assetPath2.split("/"));
25867
- const stat3 = await lstat4(file2).catch(() => void 0);
25868
- if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > 20 * 1024 * 1024) return fail8(response, 404, "NOT_FOUND", t2("server.assetNotFound"));
25869
- const bytes = await readFile4(file2);
25870
- const extension = assetExtension(relative);
25871
- const inline = ["png", "jpg", "jpeg", "gif", "webp", "svg"].includes(extension);
25872
- response.writeHead(200, {
25873
- "Content-Type": contentType("." + extension),
25874
- "Cache-Control": "no-cache",
25875
- "Content-Length": bytes.length,
25876
- "Content-Security-Policy": "default-src 'none'; sandbox",
25877
- "Content-Disposition": inline ? "inline" : 'attachment; filename="' + encodeURIComponent(relative.split("/").pop()) + '"'
25878
- });
25879
- response.end(bytes);
25880
- return;
25881
- }
25882
- const method = path3 === "/api/v1/status/refresh" ? "POST" : "GET";
25883
- if (!["/api/v1/session", "/api/v1/status", "/api/v1/status/refresh", "/api/v1/specs", "/api/v1/changelog"].includes(path3)) return fail8(response, 404, "NOT_FOUND", t2("server.apiNotFound"));
25884
- if (request.method !== method) {
25885
- response.setHeader("Allow", method);
25886
- return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25887
- }
25888
- if (path3 === "/api/v1/session") return json2(response, 200, store.session);
25889
- if (request.headers["x-gitifact-session"] !== sessionId) return fail8(response, 409, "SESSION_CHANGED", t2("server.sessionChanged"));
25890
- if (path3 === "/api/v1/specs") {
25891
- const cursor = url2.searchParams.get("cursor") ?? "0";
25892
- const head = url2.searchParams.get("head");
25893
- if ([...url2.searchParams.keys()].some((k) => !["cursor", "head"].includes(k)) || url2.searchParams.getAll("cursor").length > 1 || url2.searchParams.getAll("head").length > 1 || !/^(0|[1-9]\d{0,5})$/.test(cursor) || head !== null && !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) return fail8(response, 400, "BAD_REQUEST", t2("server.badRange"));
25894
- try {
25895
- json2(response, 200, await readSpecs(Number(cursor), head ?? void 0));
25896
- } catch (error62) {
25897
- fail8(response, 503, "INTERNAL_ERROR", error62 instanceof Error ? error62.message : t2("server.specsUnreadable"));
25898
- }
25899
- return;
25900
- }
25901
- if (path3 === "/api/v1/changelog") {
25902
- const language = url2.searchParams.get("lang") ?? defaultLanguage2;
25903
- if ([...url2.searchParams.keys()].some((key) => key !== "lang") || url2.searchParams.getAll("lang").length > 1 || !/^[a-z]{2}(?:-[A-Z]{2})?$/.test(language)) return fail8(response, 400, "BAD_REQUEST", t2("server.badLanguage"));
25904
- try {
25905
- const own2 = await readChangelog(language);
25906
- const text2 = own2 ?? (language === defaultLanguage2 ? null : await readChangelog(defaultLanguage2));
25907
- if (text2 === null) return fail8(response, 404, "NOT_FOUND", t2("server.changelogNotFound"));
25908
- json2(response, 200, changelogV1.parse({ contract: "changelog", version: 1, language: own2 === null ? defaultLanguage2 : language, fallback: own2 === null, entries: parseChangelog(text2) }));
25909
- } catch (error62) {
25910
- fail8(response, 503, "INTERNAL_ERROR", error62 instanceof Error ? error62.message : t2("server.changelogUnreadable"));
25911
- }
25912
- return;
25913
- }
25914
- if (method === "POST" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.refreshOrigin"));
25915
- const value = method === "POST" ? await store.refresh() : store.latest;
25916
- if (!response.destroyed) json2(response, value.ok ? 200 : 503, value);
25917
- return;
25918
- }
25919
- if (request.method !== "GET" && request.method !== "HEAD") {
25920
- response.setHeader("Allow", "GET, HEAD");
25921
- return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25922
- }
25923
- let asset = assets.get(path3 === "/" ? "/index.html" : path3);
25924
- let assetPath = path3 === "/" ? "/index.html" : path3;
25925
- if (!asset && !path3.startsWith("/assets/") && !path3.split("/").some((part) => part.includes(".")) && request.headers.accept?.includes("text/html")) {
25926
- asset = assets.get("/index.html");
25927
- assetPath = "/index.html";
25928
- }
25929
- if (!asset) return fail8(response, 404, "NOT_FOUND", t2("server.fileNotFound"));
25930
- response.writeHead(200, { "Content-Type": contentType(assetPath), "Cache-Control": "no-cache", "Content-Length": asset.length });
25931
- response.end(request.method === "HEAD" ? void 0 : asset);
25932
- }
25933
26558
  const server = createServer({ requestTimeout: 5e3, headersTimeout: 5e3, maxHeaderSize: 8192 }, (request, response) => {
25934
- void handle(request, response).catch(() => {
25935
- if (!response.headersSent && !response.destroyed) fail8(response, 500, "INTERNAL_ERROR", t2("server.internal"));
26559
+ void (async () => {
26560
+ if (closing) return fail4(response, 503, "SERVER_CLOSING", t2("server.closing"));
26561
+ const admitted = admit(request, response, origin, !!options.dev);
26562
+ if (!admitted) return;
26563
+ if (admitted.api) return dispatch(routes, sessionId, admitted.url, admitted.path, request, response, admitted.allowedOrigin);
26564
+ return serveStatic(request, response, admitted.path, assets);
26565
+ })().catch(() => {
26566
+ if (!response.headersSent && !response.destroyed) fail4(response, 500, "INTERNAL_ERROR", t2("server.internal"));
25936
26567
  else response.destroy();
25937
26568
  });
25938
26569
  });
@@ -26039,13 +26670,13 @@ async function runBrowser(options, version2) {
26039
26670
  }
26040
26671
 
26041
26672
  // src/commands/spec-init.ts
26042
- import { mkdir as mkdir4, readdir as readdir4, writeFile as writeFile2 } from "node:fs/promises";
26043
- import { join as join9 } from "node:path";
26673
+ import { mkdir as mkdir5, readdir as readdir4, writeFile as writeFile2 } from "node:fs/promises";
26674
+ import { join as join10 } from "node:path";
26044
26675
 
26045
26676
  // src/adapters/git/init-repository.ts
26046
26677
  import { createHash as createHash3 } from "node:crypto";
26047
- import { readFile as readFile5 } from "node:fs/promises";
26048
- import { join as join6 } from "node:path";
26678
+ import { readFile as readFile6 } from "node:fs/promises";
26679
+ import { join as join7 } from "node:path";
26049
26680
  function initRepository(cwd, inherited = process.env) {
26050
26681
  const env = { ...inherited, GIT_OPTIONAL_LOCKS: "0", GIT_NO_LAZY_FETCH: "1", GIT_TERMINAL_PROMPT: "0", GIT_LITERAL_PATHSPECS: "1", LC_ALL: "C" };
26051
26682
  const runner = createGitRunner();
@@ -26065,10 +26696,10 @@ function initRepository(cwd, inherited = process.env) {
26065
26696
  const gitDir = locations.length === 2 ? locations[0] : decodeGitLine(await git(["rev-parse", "--absolute-git-dir"], root));
26066
26697
  const indexPath = locations.length === 2 ? locations[1] : decodeGitLine(await git(["rev-parse", "--path-format=absolute", "--git-path", "index"], root));
26067
26698
  for (const marker2 of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"]) {
26068
- if (await fileInfo(join6(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
26699
+ if (await fileInfo(join7(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
26069
26700
  }
26070
26701
  if (state.changes.some((change2) => change2.kind === "unmerged")) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
26071
- const index = await readFile5(indexPath).catch((error62) => {
26702
+ const index = await readFile6(indexPath).catch((error62) => {
26072
26703
  if (error62.code === "ENOENT") return Buffer.alloc(0);
26073
26704
  throw error62;
26074
26705
  });
@@ -26102,18 +26733,18 @@ function initRepository(cwd, inherited = process.env) {
26102
26733
  }
26103
26734
 
26104
26735
  // src/adapters/filesystem/managed-file.ts
26105
- import { open as open3, readFile as readFile6, mkdir as mkdir3, realpath as realpath2, rename as rename3, link as link2, unlink as unlink3 } from "node:fs/promises";
26106
- import { join as join7, dirname as dirname2 } from "node:path";
26736
+ import { open as open3, readFile as readFile7, mkdir as mkdir4, realpath as realpath2, rename as rename3, link as link2, unlink as unlink3 } from "node:fs/promises";
26737
+ import { join as join8, dirname as dirname2 } from "node:path";
26107
26738
  import { randomUUID as randomUUID5 } from "node:crypto";
26108
26739
  var DEFAULT_LIMIT = 1024 * 1024;
26109
26740
  async function managedPath(root, path3, create = false) {
26110
26741
  let full = root;
26111
26742
  const parts = path3.split("/");
26112
26743
  for (let i = 0; i < parts.length; i++) {
26113
- full = join7(full, parts[i]);
26744
+ full = join8(full, parts[i]);
26114
26745
  let info7 = await fileInfo(full);
26115
26746
  if (!info7 && create && i < parts.length - 1) {
26116
- await mkdir3(full).catch((error62) => {
26747
+ await mkdir4(full).catch((error62) => {
26117
26748
  if (error62.code !== "EEXIST") throw error62;
26118
26749
  });
26119
26750
  info7 = await fileInfo(full);
@@ -26129,7 +26760,7 @@ async function managedRead(root, path3, limit = DEFAULT_LIMIT) {
26129
26760
  const before = await fileInfo(full);
26130
26761
  if (!before) return null;
26131
26762
  if (before.size > limit) throw new InitError("FILE_TOO_LARGE", t2("managedFile.tooLarge", { kib: limit / 1024, path: path3 }));
26132
- const bytes = await readFile6(full);
26763
+ const bytes = await readFile7(full);
26133
26764
  await managedPath(root, path3);
26134
26765
  const after = await fileInfo(full);
26135
26766
  if (!after || before.ino !== after.ino || before.dev !== after.dev || before.mtimeMs !== after.mtimeMs || bytes.length > limit) {
@@ -26158,7 +26789,7 @@ async function managedWrite(root, path3, previous, next, recheck) {
26158
26789
  if (previous !== null) await unlink3(full);
26159
26790
  return;
26160
26791
  }
26161
- const temp = join7(directory, ".gitifact-managed-" + randomUUID5() + ".tmp");
26792
+ const temp = join8(directory, ".gitifact-managed-" + randomUUID5() + ".tmp");
26162
26793
  const handle = await open3(temp, "wx", 384);
26163
26794
  const tempOwner = await handle.stat();
26164
26795
  try {
@@ -26170,7 +26801,7 @@ async function managedWrite(root, path3, previous, next, recheck) {
26170
26801
  }
26171
26802
  await recheck();
26172
26803
  await unchanged();
26173
- if (await managedRead(root, path3) !== previous || await readFile6(temp, "utf8") !== next) throw new InitError("INPUT_CHANGED", t2("managedFile.publishTargetChanged", { path: path3 }));
26804
+ if (await managedRead(root, path3) !== previous || await readFile7(temp, "utf8") !== next) throw new InitError("INPUT_CHANGED", t2("managedFile.publishTargetChanged", { path: path3 }));
26174
26805
  if (previous === null) await link2(temp, full);
26175
26806
  else await rename3(temp, full);
26176
26807
  } finally {
@@ -26181,14 +26812,14 @@ async function managedWrite(root, path3, previous, next, recheck) {
26181
26812
  }
26182
26813
 
26183
26814
  // src/commands/agent-block.ts
26184
- import { readFile as readFile8 } from "node:fs/promises";
26815
+ import { readFile as readFile9 } from "node:fs/promises";
26185
26816
 
26186
26817
  // src/commands/docs.ts
26187
- import { lstat as lstat5, readFile as readFile7 } from "node:fs/promises";
26188
- import { dirname as dirname3, join as join8 } from "node:path";
26818
+ import { lstat as lstat5, readFile as readFile8 } from "node:fs/promises";
26819
+ import { dirname as dirname3, join as join9 } from "node:path";
26189
26820
  var docTopics = ["workflow", "spec", "design", "wiki", "writing", "commit"];
26190
26821
  var isDocTopic = (value) => docTopics.includes(value);
26191
- var readBundledDoc = (name, lang) => readFile7(new URL("./i18n/" + lang + "/docs/" + name + ".md", import.meta.url), "utf8");
26822
+ var readBundledDoc = (name, lang) => readFile8(new URL("./i18n/" + lang + "/docs/" + name + ".md", import.meta.url), "utf8");
26192
26823
  var info3 = (path3) => lstat5(path3).catch((e) => {
26193
26824
  if (e.code === "ENOENT") return void 0;
26194
26825
  throw e;
@@ -26199,16 +26830,16 @@ function listDocTopics(lang = defaultLanguage2) {
26199
26830
  }
26200
26831
  async function findProjectRoot(cwd) {
26201
26832
  for (let dir = cwd; ; dir = dirname3(dir)) {
26202
- if ((await info3(join8(dir, ".gitifact", "config.json")))?.isFile()) return dir;
26833
+ if ((await info3(join9(dir, ".gitifact", "config.json")))?.isFile()) return dir;
26203
26834
  if (dirname3(dir) === dir) return void 0;
26204
26835
  }
26205
26836
  }
26206
26837
  async function readWikiPolicy(root) {
26207
26838
  if (!root) return void 0;
26208
- const path3 = join8(root, ...WIKI_ENTRY_PATH.split("/"));
26839
+ const path3 = join9(root, ...WIKI_ENTRY_PATH.split("/"));
26209
26840
  const stat3 = await info3(path3);
26210
26841
  if (!stat3?.isFile() || stat3.size > 1024 * 1024) return void 0;
26211
- const lines = (await readFile7(path3, "utf8")).replace(/\r\n/g, "\n").split("\n");
26842
+ const lines = (await readFile8(path3, "utf8")).replace(/\r\n/g, "\n").split("\n");
26212
26843
  if (lines[0] === "---") {
26213
26844
  const end = lines.indexOf("---", 1);
26214
26845
  if (end > 0) lines.splice(0, end + 1);
@@ -26260,7 +26891,7 @@ function boilerplateFor(path3) {
26260
26891
  const name = path3 === "AGENTS.md" ? path3 : path3.split("/").pop().replace(/^\./, "").replace(/\.md$/, "");
26261
26892
  return "# " + name + "\n\nProject-specific guidance for AI coding agents.\n";
26262
26893
  }
26263
- var readBundledBlock = (lang) => readFile8(new URL("./i18n/" + lang + "/block.md", import.meta.url), "utf8");
26894
+ var readBundledBlock = (lang) => readFile9(new URL("./i18n/" + lang + "/block.md", import.meta.url), "utf8");
26264
26895
  async function renderAgentBlock(version2, controls = {}, lang = defaultLanguage2) {
26265
26896
  const body = await (controls.readBlock ?? readBundledBlock)(lang);
26266
26897
  const filled = body.trimEnd().replace(/\{(version|language|topics)\}/g, (_whole, name) => name === "version" ? version2 : name === "language" ? lang : docTopics.join(", "));
@@ -26419,8 +27050,8 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
26419
27050
  const text2 = JSON.stringify(config2, null, 2) + "\n";
26420
27051
  const replaceLegacy = async (before, version2) => {
26421
27052
  const onlyConfig = async () => {
26422
- const entries = await readdir4(join9(root, ".gitifact"));
26423
- if (await fileInfo(join9(root, "specs")) || entries.some((name) => name !== "config.json" && !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) {
27053
+ const entries = await readdir4(join10(root, ".gitifact"));
27054
+ if (await fileInfo(join10(root, "specs")) || entries.some((name) => name !== "config.json" && !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) {
26424
27055
  throw new InitError("UNSUPPORTED_SCHEMA", t2("init.legacyRecords", { version: String(version2) }));
26425
27056
  }
26426
27057
  };
@@ -26451,8 +27082,8 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
26451
27082
  }
26452
27083
  if (first.trackedConfig) throw new InitError("CONFIG_DELETED", t2("init.configDeleted"));
26453
27084
  const checkRecords = async () => {
26454
- if (await fileInfo(join9(root, "specs"))) throw new InitError("EXISTING_RECORDS", t2("init.existingSpecs"));
26455
- const entries = await readdir4(join9(root, ".gitifact")).catch((e) => {
27085
+ if (await fileInfo(join10(root, "specs"))) throw new InitError("EXISTING_RECORDS", t2("init.existingSpecs"));
27086
+ const entries = await readdir4(join10(root, ".gitifact")).catch((e) => {
26456
27087
  if (e.code === "ENOENT") return [];
26457
27088
  throw e;
26458
27089
  });
@@ -26489,7 +27120,7 @@ function legacySchemaVersion(text2) {
26489
27120
  return Number.isInteger(version2) && version2 < SCHEMA_VERSION ? version2 : void 0;
26490
27121
  }
26491
27122
  async function writeWikiPolicy(root, readDoc) {
26492
- if (await fileInfo(join9(root, ...WIKI_DIR.split("/")))) return;
27123
+ if (await fileInfo(join10(root, ...WIKI_DIR.split("/")))) return;
26493
27124
  const template = await readDoc("wiki.default").catch((e) => {
26494
27125
  if (e.code === "ENOENT") return void 0;
26495
27126
  throw e;
@@ -26498,8 +27129,8 @@ async function writeWikiPolicy(root, readDoc) {
26498
27129
  const doc = { id: generatePreviewId("W"), path: WIKI_ENTRY_PATH, title: t2("init.wikiReadmeTitle"), body: template.trim() };
26499
27130
  const text2 = renderDocument(doc);
26500
27131
  parseDocument(doc.path, text2);
26501
- await mkdir4(join9(root, ...WIKI_DIR.split("/")), { recursive: true });
26502
- await writeFile2(join9(root, ...WIKI_ENTRY_PATH.split("/")), text2, { flag: "wx" });
27132
+ await mkdir5(join10(root, ...WIKI_DIR.split("/")), { recursive: true });
27133
+ await writeFile2(join10(root, ...WIKI_ENTRY_PATH.split("/")), text2, { flag: "wx" });
26503
27134
  }
26504
27135
 
26505
27136
  // src/commands/init.ts
@@ -26674,14 +27305,14 @@ async function runUpdate(options, version2) {
26674
27305
  }
26675
27306
 
26676
27307
  // src/commands/spec-preview.ts
26677
- import { join as join14 } from "node:path";
26678
- import { readFile as readFile11, stat as stat2 } from "node:fs/promises";
27308
+ import { join as join15 } from "node:path";
27309
+ import { readFile as readFile12, stat as stat2 } from "node:fs/promises";
26679
27310
 
26680
27311
  // src/adapters/filesystem/spec-preview-context.ts
26681
27312
  import { lstat as lstat6 } from "node:fs/promises";
26682
- import { join as join10 } from "node:path";
27313
+ import { join as join11 } from "node:path";
26683
27314
  import { createHash as createHash4 } from "node:crypto";
26684
- var fail5 = (message) => {
27315
+ var fail6 = (message) => {
26685
27316
  throw new SpecPreviewError(message);
26686
27317
  };
26687
27318
  var same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
@@ -26692,11 +27323,11 @@ async function readPreviewContext(cwd) {
26692
27323
  const { gitDir } = await reader.location();
26693
27324
  const checkOperation = async () => {
26694
27325
  for (const name of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"]) {
26695
- const exists = await lstat6(join10(gitDir, name)).catch((e) => {
27326
+ const exists = await lstat6(join11(gitDir, name)).catch((e) => {
26696
27327
  if (e.code === "ENOENT") return void 0;
26697
27328
  throw e;
26698
27329
  });
26699
- if (exists) fail5(t2("prepare.integrationInProgress"));
27330
+ if (exists) fail6(t2("prepare.integrationInProgress"));
26700
27331
  }
26701
27332
  };
26702
27333
  await checkOperation();
@@ -26707,7 +27338,7 @@ async function readPreviewContext(cwd) {
26707
27338
  const specs = bundle.specs;
26708
27339
  const recheck = async () => {
26709
27340
  await checkOperation();
26710
- if (!same(base, await reader.baseline())) fail5(t2("prepare.headChanged"));
27341
+ if (!same(base, await reader.baseline())) fail6(t2("prepare.headChanged"));
26711
27342
  };
26712
27343
  return { reader, base, files, specs, bundle, recheck, working };
26713
27344
  }
@@ -26723,9 +27354,9 @@ async function readFinalPreviewChanges(cwd) {
26723
27354
 
26724
27355
  // src/adapters/filesystem/agent-inputs.ts
26725
27356
  import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
26726
- import { lstat as lstat7, mkdir as mkdir5, readdir as readdir5, realpath as realpath3, unlink as unlink4, writeFile as writeFile3 } from "node:fs/promises";
27357
+ import { lstat as lstat7, mkdir as mkdir6, readdir as readdir5, realpath as realpath3, unlink as unlink4, writeFile as writeFile3 } from "node:fs/promises";
26727
27358
  import { tmpdir } from "node:os";
26728
- import { basename, dirname as dirname4, join as join11 } from "node:path";
27359
+ import { basename, dirname as dirname4, join as join12 } from "node:path";
26729
27360
  var maxAge = 7 * 24 * 60 * 60 * 1e3;
26730
27361
  var info4 = (path3) => lstat7(path3).catch((e) => {
26731
27362
  if (e.code === "ENOENT") return void 0;
@@ -26734,14 +27365,14 @@ var info4 = (path3) => lstat7(path3).catch((e) => {
26734
27365
  var comparable = (path3) => process.platform === "win32" ? path3.toLowerCase() : path3;
26735
27366
  async function candidates(root, controls) {
26736
27367
  const key = createHash5("sha256").update(comparable(await realpath3(root))).digest("hex").slice(0, 16);
26737
- return { system: join11((controls.tmpdir ?? tmpdir)(), "gitifact", key), project: join11(root, ".gitifact", "tmp") };
27368
+ return { system: join12((controls.tmpdir ?? tmpdir)(), "gitifact", key), project: join12(root, ".gitifact", "tmp") };
26738
27369
  }
26739
27370
  async function writable(directory) {
26740
27371
  try {
26741
- await mkdir5(directory, { recursive: true });
27372
+ await mkdir6(directory, { recursive: true });
26742
27373
  const stat3 = await info4(directory);
26743
27374
  if (!stat3?.isDirectory() || stat3.isSymbolicLink()) return false;
26744
- const probe = join11(directory, ".probe-" + randomBytes2(8).toString("hex"));
27375
+ const probe = join12(directory, ".probe-" + randomBytes2(8).toString("hex"));
26745
27376
  await writeFile3(probe, "", { flag: "wx" });
26746
27377
  await unlink4(probe);
26747
27378
  return true;
@@ -26755,7 +27386,7 @@ async function prepareAgentInputs(root, controls = {}) {
26755
27386
  if (await writable(system)) directory = system;
26756
27387
  else if (await writable(project)) {
26757
27388
  directory = project;
26758
- await writeFile3(join11(project, ".gitignore"), "*\n", { flag: "wx" }).catch((e) => {
27389
+ await writeFile3(join12(project, ".gitignore"), "*\n", { flag: "wx" }).catch((e) => {
26759
27390
  if (e.code !== "EEXIST") throw e;
26760
27391
  });
26761
27392
  }
@@ -26763,10 +27394,10 @@ async function prepareAgentInputs(root, controls = {}) {
26763
27394
  const now = (controls.now ?? Date.now)();
26764
27395
  for (const name of await readdir5(directory).catch(() => [])) {
26765
27396
  if (name === ".gitignore") continue;
26766
- const stat3 = await info4(join11(directory, name)).catch(() => void 0);
26767
- if (stat3?.isFile() && now - stat3.mtimeMs > maxAge) await unlink4(join11(directory, name)).catch(() => void 0);
27397
+ const stat3 = await info4(join12(directory, name)).catch(() => void 0);
27398
+ if (stat3?.isFile() && now - stat3.mtimeMs > maxAge) await unlink4(join12(directory, name)).catch(() => void 0);
26768
27399
  }
26769
- return { save: join11(directory, "save.json"), commit: join11(directory, "commit.json") };
27400
+ return { save: join12(directory, "save.json"), commit: join12(directory, "commit.json") };
26770
27401
  }
26771
27402
  async function discardAgentInput(root, file2, controls = {}) {
26772
27403
  try {
@@ -26788,18 +27419,18 @@ async function discardAgentInput(root, file2, controls = {}) {
26788
27419
 
26789
27420
  // src/commands/spec-commit.ts
26790
27421
  import { createHash as createHash7, randomUUID as randomUUID6 } from "node:crypto";
26791
- import { mkdir as mkdir6, open as open4, readFile as readFile10, rename as rename4, rmdir as rmdir2, unlink as unlink5, writeFile as writeFile4 } from "node:fs/promises";
26792
- import { join as join13 } from "node:path";
27422
+ import { mkdir as mkdir7, open as open4, readFile as readFile11, rename as rename4, rmdir as rmdir2, unlink as unlink5, writeFile as writeFile4 } from "node:fs/promises";
27423
+ import { join as join14 } from "node:path";
26793
27424
 
26794
27425
  // src/commands/spec-commit-files.ts
26795
27426
  import { createHash as createHash6 } from "node:crypto";
26796
- import { lstat as lstat8, readFile as readFile9 } from "node:fs/promises";
26797
- import { join as join12 } from "node:path";
26798
- var fail6 = (message) => {
27427
+ import { lstat as lstat8, readFile as readFile10 } from "node:fs/promises";
27428
+ import { join as join13 } from "node:path";
27429
+ var fail7 = (message) => {
26799
27430
  throw new SpecPreviewError(message);
26800
27431
  };
26801
27432
  var hash2 = (value) => createHash6("sha256").update(value).digest("hex");
26802
- var optional2 = (path3) => readFile9(path3).catch((e) => {
27433
+ var optional2 = (path3) => readFile10(path3).catch((e) => {
26803
27434
  if (e.code === "ENOENT") return null;
26804
27435
  throw e;
26805
27436
  });
@@ -26809,34 +27440,34 @@ var info5 = (path3) => lstat8(path3).catch((e) => {
26809
27440
  });
26810
27441
  var record2 = (path3) => recordPathPattern.test(path3);
26811
27442
  function validPath2(path3) {
26812
- if (typeof path3 !== "string" || path3.length > 1e3 || /[\\:\x00-\x1f\x7f]/.test(path3) || path3.split("/").some((p) => !p || p === "." || p === ".." || p.toLowerCase() === ".git")) fail6(t2("commitFiles.relativePath"));
27443
+ if (typeof path3 !== "string" || path3.length > 1e3 || /[\\:\x00-\x1f\x7f]/.test(path3) || path3.split("/").some((p) => !p || p === "." || p === ".." || p.toLowerCase() === ".git")) fail7(t2("commitFiles.relativePath"));
26813
27444
  }
26814
27445
  async function fingerprint(root, path3) {
26815
27446
  validPath2(path3);
26816
27447
  const parts = path3.split("/");
26817
27448
  for (let i = 1; i <= parts.length; i++) {
26818
- const target = join12(root, ...parts.slice(0, i));
27449
+ const target = join13(root, ...parts.slice(0, i));
26819
27450
  const stat3 = await info5(target);
26820
27451
  if (!stat3) return null;
26821
- if (stat3.isSymbolicLink() || (i < parts.length ? !stat3.isDirectory() : !stat3.isFile())) fail6(t2("commitFiles.linkOrDirectory"));
26822
- if (i < parts.length && await info5(join12(target, ".git"))) fail6(t2("commitFiles.nestedRepository"));
27452
+ if (stat3.isSymbolicLink() || (i < parts.length ? !stat3.isDirectory() : !stat3.isFile())) fail7(t2("commitFiles.linkOrDirectory"));
27453
+ if (i < parts.length && await info5(join13(target, ".git"))) fail7(t2("commitFiles.nestedRepository"));
26823
27454
  if (i === parts.length) {
26824
- if (stat3.nlink !== 1 || stat3.size > 16 * 1024 * 1024) fail6(t2("commitFiles.hardLinkOrSize"));
26825
- return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await readFile9(target)]));
27455
+ if (stat3.nlink !== 1 || stat3.size > 16 * 1024 * 1024) fail7(t2("commitFiles.hardLinkOrSize"));
27456
+ return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await readFile10(target)]));
26826
27457
  }
26827
27458
  }
26828
27459
  return null;
26829
27460
  }
26830
27461
  function object3(input2) {
26831
- if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) return fail6(t2("commitFiles.invalidInput"));
27462
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) return fail7(t2("commitFiles.invalidInput"));
26832
27463
  return input2;
26833
27464
  }
26834
27465
  function text(value, limit) {
26835
- if (typeof value !== "string" || !value.trim() || value.length > limit || value.includes("\0")) return fail6(t2("commitFiles.emptyOrTooLong"));
27466
+ if (typeof value !== "string" || !value.trim() || value.length > limit || value.includes("\0")) return fail7(t2("commitFiles.emptyOrTooLong"));
26836
27467
  return value;
26837
27468
  }
26838
27469
  function paths(value, limit = 128) {
26839
- if (!Array.isArray(value) || !value.length || value.length > limit || value.some((p) => typeof p !== "string")) return fail6(t2("commitFiles.invalidPaths"));
27470
+ if (!Array.isArray(value) || !value.length || value.length > limit || value.some((p) => typeof p !== "string")) return fail7(t2("commitFiles.invalidPaths"));
26840
27471
  const list = [...new Set(value)].sort();
26841
27472
  list.forEach(validPath2);
26842
27473
  return list;
@@ -26853,10 +27484,10 @@ async function checkLegacySelection(root, selected) {
26853
27484
  const legacyJson = /^\.(?:gitifact|tryce)\/(?:spec\/[^/]+\/tryce\.json|notes\/N-[a-f0-9-]+\.json|mode-[a-f0-9-]+\.json|config\.(?:init-1|prototype-1)\.[a-f0-9]+\.json)$|^\.gitifact\/(?:product|guides|overrides)\/.+$/;
26854
27485
  for (const p of selected.filter((p2) => p2.startsWith(".gitifact/") && !record2(p2) && p2 !== ".gitifact/config.json")) {
26855
27486
  if (isAssetPath(p)) continue;
26856
- if (!legacyJson.test(p) || await fingerprint(root, p) !== null) fail6(t2("commitFiles.legacyDeleteOnly", { path: p }));
27487
+ if (!legacyJson.test(p) || await fingerprint(root, p) !== null) fail7(t2("commitFiles.legacyDeleteOnly", { path: p }));
26857
27488
  }
26858
27489
  for (const p of selected.filter((p2) => p2.startsWith(".tryce/"))) {
26859
- if (!(record2(p) || p === ".tryce/config.json" || legacyJson.test(p)) || await fingerprint(root, p) !== null) fail6(t2("commitFiles.tryceDeleteOnly", { path: p }));
27490
+ if (!(record2(p) || p === ".tryce/config.json" || legacyJson.test(p)) || await fingerprint(root, p) !== null) fail7(t2("commitFiles.tryceDeleteOnly", { path: p }));
26860
27491
  }
26861
27492
  }
26862
27493
 
@@ -26866,17 +27497,17 @@ var integration = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merg
26866
27497
  var same2 = (a, b) => JSON.stringify(a) === JSON.stringify(b);
26867
27498
  async function specCommit(cwd, input2, dryRun) {
26868
27499
  const request = object3(input2);
26869
- if (Object.keys(request).some((k) => !fields.includes(k))) fail6(t2("commit.unknownField"));
27500
+ if (Object.keys(request).some((k) => !fields.includes(k))) fail7(t2("commit.unknownField"));
26870
27501
  const selected = paths(request.paths);
26871
27502
  const authorization = object3(request.authorization);
26872
- if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail6(t2("commit.authorizationRequired"));
27503
+ if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail7(t2("commit.authorizationRequired"));
26873
27504
  text(authorization.evidence, 2e3);
26874
27505
  const message = text(request.message, 4e3);
26875
- if (/^\s*Gitifact-/im.test(message)) fail6(t2("commit.trailerInMessage"));
27506
+ if (/^\s*Gitifact-/im.test(message)) fail7(t2("commit.trailerInMessage"));
26876
27507
  const references = request.requirements ?? [];
26877
- if (!Array.isArray(references) || references.length > 1e3 || references.some((r) => typeof r !== "string")) fail6(t2("commit.invalidReferences"));
27508
+ if (!Array.isArray(references) || references.length > 1e3 || references.some((r) => typeof r !== "string")) fail7(t2("commit.invalidReferences"));
26878
27509
  const extra = request.policyFiles === void 0 ? [] : paths(request.policyFiles, 1024);
26879
- if (request.expected !== void 0 && typeof request.expected !== "string") fail6(t2("commit.expectedType"));
27510
+ if (request.expected !== void 0 && typeof request.expected !== "string") fail7(t2("commit.expectedType"));
26880
27511
  const c = await readPreviewContext(cwd);
26881
27512
  const { root, gitDir, indexPath, objectFormat } = await c.reader.location();
26882
27513
  const runner = createGitRunner();
@@ -26899,13 +27530,13 @@ async function specCommit(cwd, input2, dryRun) {
26899
27530
  ...stdin ? { input: stdin } : {}
26900
27531
  });
26901
27532
  const staged = async (index) => (await git(["diff", "--cached", "--ita-visible-in-index", "--name-only", "--no-renames", "-z"], index)).toString("utf8").split("\0").filter(Boolean).sort();
26902
- const busy = join13(gitDir, "gitifact-spec-commit.lock");
27533
+ const busy = join14(gitDir, "gitifact-spec-commit.lock");
26903
27534
  await failOnLegacyLock(gitDir);
26904
- if (await info5(busy)) fail6(t2("commit.busy", { path: busy }));
26905
- if ((await staged()).length) fail6(t2("commit.existingStaging"));
27535
+ if (await info5(busy)) fail7(t2("commit.busy", { path: busy }));
27536
+ if ((await staged()).length) fail7(t2("commit.existingStaging"));
26906
27537
  const indexHash = hash2(await optional2(indexPath) ?? Buffer.alloc(0));
26907
27538
  const current = c.working;
26908
- if (request.expected !== void 0 && request.expected !== previewExpected(c.base, current.stamp)) fail6(t2("commit.staleInput"));
27539
+ if (request.expected !== void 0 && request.expected !== previewExpected(c.base, current.stamp)) fail7(t2("commit.staleInput"));
26909
27540
  const reasons = request.reasons ?? pendingPreviewReasons(c.bundle, current.bundle).map((h) => ({ requirements: h.requirements, ...h.designs ? { designs: h.designs } : {}, ...h.documents ? { documents: h.documents } : {}, reason: h.reason }));
26910
27541
  const prepared = prepareSpecPreview(c.bundle, current.bundle, c.files, current.files, reasons, () => generatePreviewId("H"));
26911
27542
  const blobId = (text2) => {
@@ -26913,14 +27544,14 @@ async function specCommit(cwd, input2, dryRun) {
26913
27544
  return createHash7(objectFormat).update(`blob ${bytes.length}\0`).update(bytes).digest("hex");
26914
27545
  };
26915
27546
  const present = [...current.files.keys()];
26916
- if (present.some((p) => p.includes("\n"))) fail6(t2("commit.newlinePath"));
27547
+ if (present.some((p) => p.includes("\n"))) fail7(t2("commit.newlinePath"));
26917
27548
  const stored = present.length ? (await git(["hash-object", "--stdin-paths"], void 0, Buffer.from(present.join("\n") + "\n"))).toString("utf8").split("\n") : [""];
26918
- if (stored.length !== present.length + 1) fail6(t2("commit.storedShape"));
27549
+ if (stored.length !== present.length + 1) fail7(t2("commit.storedShape"));
26919
27550
  const workingIds = new Map(present.map((p, i) => [p, stored[i]]));
26920
27551
  const writes = new Map([...prepared.writes].filter(([p, next]) => next === null || workingIds.get(p) !== blobId(next)));
26921
27552
  const finalId = (p) => writes.has(p) ? writes.get(p) === null ? void 0 : blobId(writes.get(p)) : workingIds.get(p);
26922
27553
  const pending = [.../* @__PURE__ */ new Set([...c.files.keys(), ...present, ...writes.keys()])].filter((p) => (c.files.has(p) ? blobId(c.files.get(p)) : void 0) !== finalId(p));
26923
- if (pending.some((p) => !selected.includes(p))) fail6(t2("commit.selectPending"));
27554
+ if (pending.some((p) => !selected.includes(p))) fail7(t2("commit.selectPending"));
26924
27555
  const finalFiles = new Map(current.files);
26925
27556
  for (const [path3, next] of writes) {
26926
27557
  if (next === null) finalFiles.delete(path3);
@@ -26929,7 +27560,7 @@ async function specCommit(cwd, input2, dryRun) {
26929
27560
  await checkLegacySelection(root, selected);
26930
27561
  const stageable = selected.filter((p) => !record2(p) || finalFiles.has(p) || c.files.has(p));
26931
27562
  const known = /* @__PURE__ */ new Set([...current.specs.flatMap((s) => s.requirements.map((r) => r.id)), ...prepared.changes.filter((x) => x.kind === "requirement").map((x) => x.id)]);
26932
- if (references.some((r) => !known.has(r))) fail6(t2("commit.unknownRequirement"));
27563
+ if (references.some((r) => !known.has(r))) fail7(t2("commit.unknownRequirement"));
26933
27564
  const requirements = [.../* @__PURE__ */ new Set([...references, ...prepared.changes.filter((x) => x.kind === "requirement").map((x) => x.id)])].sort();
26934
27565
  const contextPaths = [.../* @__PURE__ */ new Set([...policyPaths(selected), ...extra])].sort();
26935
27566
  const hashes = async (list) => new Map(await Promise.all(list.map(async (p) => [p, await fingerprint(root, p)])));
@@ -26953,17 +27584,17 @@ async function specCommit(cwd, input2, dryRun) {
26953
27584
  ...prepared.changes.filter((c2) => c2.kind === "design").map((c2) => "Gitifact-Design: " + c2.id),
26954
27585
  ...prepared.changes.filter((c2) => c2.kind === "wiki").map((c2) => "Gitifact-Doc: " + c2.id)
26955
27586
  ];
26956
- const temporary = join13(gitDir, "gitifact-commit-index-" + randomUUID6());
27587
+ const temporary = join14(gitDir, "gitifact-commit-index-" + randomUUID6());
26957
27588
  let owned = false;
26958
27589
  let uncertain = false;
26959
27590
  let indexLock;
26960
27591
  let committed;
26961
27592
  try {
26962
27593
  try {
26963
- await mkdir6(busy);
27594
+ await mkdir7(busy);
26964
27595
  owned = true;
26965
27596
  } catch (e) {
26966
- if (e.code === "EEXIST") fail6(t2("commit.busy", { path: busy }));
27597
+ if (e.code === "EEXIST") fail7(t2("commit.busy", { path: busy }));
26967
27598
  throw e;
26968
27599
  }
26969
27600
  await previewTransaction(cwd, current.stamp, async () => ({ writes, data: {}, recheck: c.recheck }), rename4, async (published) => {
@@ -26971,15 +27602,15 @@ async function specCommit(cwd, input2, dryRun) {
26971
27602
  try {
26972
27603
  const lock = indexLock = await open4(indexPath + ".lock", "wx", 384);
26973
27604
  const original = await optional2(indexPath);
26974
- if (hash2(original ?? Buffer.alloc(0)) !== indexHash || (await staged()).length) fail6(t2("commit.indexChanged"));
27605
+ if (hash2(original ?? Buffer.alloc(0)) !== indexHash || (await staged()).length) fail7(t2("commit.indexChanged"));
26975
27606
  const locked = await hashes([.../* @__PURE__ */ new Set([...selected, ...contextPaths])]);
26976
- for (const [path3, value] of started) if (locked.get(path3) !== value) fail6(t2("commit.fileChangedRunning", { path: path3 }));
26977
- await writeFile4(join13(busy, "recovery.json"), JSON.stringify({ before: c.base, originalIndex: original?.toString("base64") ?? null, temporary, paths: selected, message, requirements }));
27607
+ for (const [path3, value] of started) if (locked.get(path3) !== value) fail7(t2("commit.fileChangedRunning", { path: path3 }));
27608
+ await writeFile4(join14(busy, "recovery.json"), JSON.stringify({ before: c.base, originalIndex: original?.toString("base64") ?? null, temporary, paths: selected, message, requirements }));
26978
27609
  if (original) await writeFile4(temporary, original, { flag: "wx" });
26979
27610
  else await git(["read-tree", "--empty"], temporary);
26980
27611
  await git(["add", "--", ...stageable], temporary);
26981
27612
  const actual = await staged(temporary);
26982
- if (!actual.length || actual.some((p) => !selected.includes(p))) fail6(t2("commit.unexpectedFiles"));
27613
+ if (!actual.length || actual.some((p) => !selected.includes(p))) fail7(t2("commit.unexpectedFiles"));
26983
27614
  const records = selected.filter((p) => record2(p) && locked.get(p) !== null);
26984
27615
  if (records.length) {
26985
27616
  const output2 = await git(["cat-file", "--batch"], temporary, Buffer.from(records.map((p) => ":" + p).join("\n") + "\n"));
@@ -26988,32 +27619,32 @@ async function specCommit(cwd, input2, dryRun) {
26988
27619
  const end = output2.indexOf(10, offset);
26989
27620
  const header = output2.subarray(offset, end).toString("utf8").split(" ");
26990
27621
  const size = Number(header[2]);
26991
- if (end < 0 || header[1] !== "blob" || !Number.isSafeInteger(size) || output2[end + 1 + size] !== 10) fail6(t2("commit.stagedUnreadable", { path: path3 }));
27622
+ if (end < 0 || header[1] !== "blob" || !Number.isSafeInteger(size) || output2[end + 1 + size] !== 10) fail7(t2("commit.stagedUnreadable", { path: path3 }));
26992
27623
  const staged2 = output2.subarray(end + 1, end + 1 + size);
26993
- const file2 = await readFile10(join13(root, path3));
26994
- if (!staged2.equals(file2) && !staged2.equals(Buffer.from(file2.toString("latin1").replace(/\r\n/g, "\n"), "latin1"))) fail6(t2("commit.filterChanged"));
27624
+ const file2 = await readFile11(join14(root, path3));
27625
+ if (!staged2.equals(file2) && !staged2.equals(Buffer.from(file2.toString("latin1").replace(/\r\n/g, "\n"), "latin1"))) fail7(t2("commit.filterChanged"));
26995
27626
  offset = end + size + 2;
26996
27627
  }
26997
27628
  }
26998
27629
  const again = await hashes([...locked.keys()]);
26999
- for (const [path3, value] of locked) if (again.get(path3) !== value) fail6(t2("commit.fileChangedPreparing", { path: path3 }));
27000
- if ((await readLockedPreviewState(root)).stamp !== published.stamp) fail6(t2("commit.specsChangedPreparing"));
27001
- for (const name of integration) if (await info5(join13(gitDir, name))) fail6(t2("commit.integrationStarted"));
27002
- if (!same2(c.base, await c.reader.baseline())) fail6(t2("commit.headChanged"));
27630
+ for (const [path3, value] of locked) if (again.get(path3) !== value) fail7(t2("commit.fileChangedPreparing", { path: path3 }));
27631
+ if ((await readLockedPreviewState(root)).stamp !== published.stamp) fail7(t2("commit.specsChangedPreparing"));
27632
+ for (const name of integration) if (await info5(join14(gitDir, name))) fail7(t2("commit.integrationStarted"));
27633
+ if (!same2(c.base, await c.reader.baseline())) fail7(t2("commit.headChanged"));
27003
27634
  const tree = (await git(["write-tree"], temporary)).toString("utf8").trim();
27004
27635
  commitStarted = true;
27005
27636
  await git(["commit", "-m", message.trim() + (trailers.length ? "\n\n" + trailers.join("\n") : "")], temporary);
27006
27637
  const after = await c.reader.baseline();
27007
- if (!after.head) return fail6(t2("commit.resultUnknown"));
27638
+ if (!after.head) return fail7(t2("commit.resultUnknown"));
27008
27639
  const raw = (await git(["cat-file", "commit", after.head])).toString("utf8");
27009
27640
  const split = raw.indexOf("\n\n");
27010
27641
  const headers = raw.slice(0, split < 0 ? raw.length : split).split("\n");
27011
27642
  const body = split < 0 ? "" : raw.slice(split + 2);
27012
27643
  const parents = headers.filter((h) => h.startsWith("parent ")).map((h) => h.slice(7));
27013
- if (headers[0] !== "tree " + tree || after.branch !== c.base.branch || !same2(parents, c.base.head ? [c.base.head] : []) || trailers.some((t3) => !body.split(/\r?\n/).includes(t3))) fail6(t2("commit.resultAltered"));
27014
- if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== indexHash) fail6(t2("commit.indexChangedAfter"));
27015
- if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6(t2("commit.hookChangedStaging"));
27016
- await lock.writeFile(await readFile10(temporary));
27644
+ if (headers[0] !== "tree " + tree || after.branch !== c.base.branch || !same2(parents, c.base.head ? [c.base.head] : []) || trailers.some((t3) => !body.split(/\r?\n/).includes(t3))) fail7(t2("commit.resultAltered"));
27645
+ if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== indexHash) fail7(t2("commit.indexChangedAfter"));
27646
+ if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail7(t2("commit.hookChangedStaging"));
27647
+ await lock.writeFile(await readFile11(temporary));
27017
27648
  await lock.sync();
27018
27649
  await lock.close();
27019
27650
  await rename4(indexPath + ".lock", indexPath);
@@ -27040,7 +27671,7 @@ async function specCommit(cwd, input2, dryRun) {
27040
27671
  await unlink5(temporary).catch(() => {
27041
27672
  });
27042
27673
  if (owned) {
27043
- await unlink5(join13(busy, "recovery.json")).catch(() => {
27674
+ await unlink5(join14(busy, "recovery.json")).catch(() => {
27044
27675
  });
27045
27676
  await rmdir2(busy);
27046
27677
  }
@@ -27057,7 +27688,7 @@ async function execute(action, options, controls) {
27057
27688
  try {
27058
27689
  const guard = specPreviewReader(process.cwd());
27059
27690
  const { root, gitDir, objectFormat } = await guard.location();
27060
- for (const marker2 of operations) if (await fileInfo(join14(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
27691
+ for (const marker2 of operations) if (await fileInfo(join15(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
27061
27692
  if (await guard.hasUnmerged()) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
27062
27693
  const raw = await readConfigFile(root);
27063
27694
  if (raw === void 0) throw new SpecPreviewError(t2("preview.notInitialized"));
@@ -27104,7 +27735,7 @@ async function execute(action, options, controls) {
27104
27735
  async function readInputFile(path3) {
27105
27736
  const source2 = await stat2(path3);
27106
27737
  if (!source2.isFile() || source2.size > 1024 * 1024) throw new SpecPreviewError(t2("preview.inputFile"));
27107
- return readFile11(path3);
27738
+ return readFile12(path3);
27108
27739
  }
27109
27740
  async function readStdin(stream) {
27110
27741
  const chunks = [];
@@ -27136,8 +27767,8 @@ function narrowWorking(working, options, inputs) {
27136
27767
  }
27137
27768
 
27138
27769
  // src/commands/migrate.ts
27139
- import { lstat as lstat9, readdir as readdir6, readFile as readFile12, rename as rename5, writeFile as writeFile5, unlink as unlink6 } from "node:fs/promises";
27140
- import { join as join15 } from "node:path";
27770
+ import { lstat as lstat9, readdir as readdir6, readFile as readFile13, rename as rename5, writeFile as writeFile5, unlink as unlink6 } from "node:fs/promises";
27771
+ import { join as join16 } from "node:path";
27141
27772
  import { randomBytes as randomBytes3 } from "node:crypto";
27142
27773
  var operations2 = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"];
27143
27774
  var info6 = (path3) => lstat9(path3).catch((e) => {
@@ -27145,46 +27776,46 @@ var info6 = (path3) => lstat9(path3).catch((e) => {
27145
27776
  throw e;
27146
27777
  });
27147
27778
  var decode4 = (bytes) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
27148
- var fail7 = (code, message) => {
27779
+ var fail8 = (code, message) => {
27149
27780
  throw new InitError(code, message);
27150
27781
  };
27151
27782
  async function migrateStore(cwd, dryRun = false) {
27152
27783
  const reader = specPreviewReader(cwd);
27153
27784
  const { root, gitDir } = await reader.location();
27154
- for (const marker3 of operations2) if (await info6(join15(gitDir, marker3))) fail7("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker3 }));
27155
- if (await reader.hasUnmerged()) fail7("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
27156
- for (const name of [...LEGACY_LOCKS, "gitifact-spec-preview.lock", "gitifact-spec-commit.lock"]) if (await info6(join15(gitDir, name))) fail7("LOCKED", t2("migrate.locked", { path: join15(gitDir, name) }));
27157
- const from = join15(root, ".tryce");
27158
- const to = join15(root, ".gitifact");
27785
+ for (const marker3 of operations2) if (await info6(join16(gitDir, marker3))) fail8("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker3 }));
27786
+ if (await reader.hasUnmerged()) fail8("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
27787
+ for (const name of [...LEGACY_LOCKS, "gitifact-spec-preview.lock", "gitifact-spec-commit.lock"]) if (await info6(join16(gitDir, name))) fail8("LOCKED", t2("migrate.locked", { path: join16(gitDir, name) }));
27788
+ const from = join16(root, ".tryce");
27789
+ const to = join16(root, ".gitifact");
27159
27790
  const fromInfo = await info6(from);
27160
- if (await info6(to)) fail7("ALREADY_MIGRATED", t2("migrate.alreadyMigrated"));
27161
- if (!fromInfo) return fail7("NOTHING_TO_MIGRATE", t2("migrate.nothingToMigrate"));
27162
- if (!fromInfo.isDirectory() || fromInfo.isSymbolicLink()) fail7("PATH_CONFLICT", t2("migrate.notDirectory"));
27163
- const configInfo = await info6(join15(from, "config.json"));
27164
- if (!configInfo?.isFile() || configInfo.isSymbolicLink()) fail7("NOT_INITIALIZED", t2("migrate.noConfig"));
27165
- const config2 = parseManagedConfig(decode4(await readFile12(join15(from, "config.json"))));
27166
- if (!("schemaVersion" in config2)) fail7("UNSUPPORTED_FORMAT", t2("migrate.legacyJson"));
27791
+ if (await info6(to)) fail8("ALREADY_MIGRATED", t2("migrate.alreadyMigrated"));
27792
+ if (!fromInfo) return fail8("NOTHING_TO_MIGRATE", t2("migrate.nothingToMigrate"));
27793
+ if (!fromInfo.isDirectory() || fromInfo.isSymbolicLink()) fail8("PATH_CONFLICT", t2("migrate.notDirectory"));
27794
+ const configInfo = await info6(join16(from, "config.json"));
27795
+ if (!configInfo?.isFile() || configInfo.isSymbolicLink()) fail8("NOT_INITIALIZED", t2("migrate.noConfig"));
27796
+ const config2 = parseManagedConfig(decode4(await readFile13(join16(from, "config.json"))));
27797
+ if (!("schemaVersion" in config2)) fail8("UNSUPPORTED_FORMAT", t2("migrate.legacyJson"));
27167
27798
  const top = (await readdir6(from)).sort();
27168
- if (top.some((name) => name !== "config.json" && name !== "spec")) fail7("UNSUPPORTED_FORMAT", t2("migrate.extraEntries"));
27799
+ if (top.some((name) => name !== "config.json" && name !== "spec")) fail8("UNSUPPORTED_FORMAT", t2("migrate.extraEntries"));
27169
27800
  const files = /* @__PURE__ */ new Map();
27170
27801
  const rewrites = [];
27171
27802
  const legacyRecords = [];
27172
27803
  const marker2 = /^<!-- tryce-(spec|req|design|ref): /;
27173
27804
  if (top.includes("spec")) {
27174
- for (const feature2 of (await readdir6(join15(from, "spec"))).sort()) {
27175
- const dir = join15(from, "spec", feature2);
27805
+ for (const feature2 of (await readdir6(join16(from, "spec"))).sort()) {
27806
+ const dir = join16(from, "spec", feature2);
27176
27807
  const stat3 = await info6(dir);
27177
- if (!stat3?.isDirectory() || stat3.isSymbolicLink()) fail7("UNSUPPORTED_FORMAT", t2("migrate.notSpecFolder", { feature: feature2 }));
27808
+ if (!stat3?.isDirectory() || stat3.isSymbolicLink()) fail8("UNSUPPORTED_FORMAT", t2("migrate.notSpecFolder", { feature: feature2 }));
27178
27809
  for (const name of (await readdir6(dir)).sort()) {
27179
- if (!["requirements.md", "design.md", "history.jsonl", "tryce.json"].includes(name)) fail7("UNSUPPORTED_FORMAT", t2("migrate.unsupportedFile", { feature: feature2, name }));
27180
- const fileStat = await info6(join15(dir, name));
27181
- if (!fileStat?.isFile() || fileStat.isSymbolicLink() || fileStat.nlink !== 1 || fileStat.size > 1024 * 1024) fail7("UNSUPPORTED_FORMAT", t2("migrate.fileTooLarge", { name }));
27810
+ if (!["requirements.md", "design.md", "history.jsonl", "tryce.json"].includes(name)) fail8("UNSUPPORTED_FORMAT", t2("migrate.unsupportedFile", { feature: feature2, name }));
27811
+ const fileStat = await info6(join16(dir, name));
27812
+ if (!fileStat?.isFile() || fileStat.isSymbolicLink() || fileStat.nlink !== 1 || fileStat.size > 1024 * 1024) fail8("UNSUPPORTED_FORMAT", t2("migrate.fileTooLarge", { name }));
27182
27813
  const newPath = `.gitifact/spec/${feature2}/${name}`;
27183
27814
  if (name === "tryce.json") {
27184
27815
  legacyRecords.push(newPath);
27185
27816
  continue;
27186
27817
  }
27187
- const text2 = decode4(await readFile12(join15(dir, name)));
27818
+ const text2 = decode4(await readFile13(join16(dir, name)));
27188
27819
  if (name === "history.jsonl") {
27189
27820
  files.set(newPath, text2);
27190
27821
  continue;
@@ -27229,8 +27860,8 @@ async function migrateStore(cwd, dryRun = false) {
27229
27860
  if (dryRun) return result("planned");
27230
27861
  await rename5(from, to);
27231
27862
  for (const r of rewrites) {
27232
- const full = join15(root, r.path);
27233
- const temp = join15(root, ".gitifact", "spec", ".gitifact-migrate-" + randomBytes3(8).toString("hex"));
27863
+ const full = join16(root, r.path);
27864
+ const temp = join16(root, ".gitifact", "spec", ".gitifact-migrate-" + randomBytes3(8).toString("hex"));
27234
27865
  await writeFile5(temp, r.content, { flag: "wx" });
27235
27866
  try {
27236
27867
  await rename5(temp, full);
@@ -27253,16 +27884,16 @@ async function runMigrate(options) {
27253
27884
  }
27254
27885
 
27255
27886
  // src/main.ts
27256
- var program2 = new Command().name("gitifact").description(t2("help.program")).version("0.6.0").allowExcessArguments(false).addHelpText("after", "\n" + t2("help.notYet")).action(() => program2.outputHelp());
27887
+ var program2 = new Command().name("gitifact").description(t2("help.program")).version("0.6.2").allowExcessArguments(false).addHelpText("after", "\n" + t2("help.notYet")).action(() => program2.outputHelp());
27257
27888
  program2.command("status").description(t2("help.status")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action(async (options) => {
27258
27889
  await runStatus(options.format);
27259
27890
  });
27260
- program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).option("--no-update-check", t2("help.browserNoUpdateCheck")).action((options) => runBrowser(options, "0.6.0"));
27261
- program2.command("init").description(t2("help.init")).allowExcessArguments(false).option("--dry-run", t2("help.initDryRun")).addOption(new Option("--agent <agent>", t2("help.initAgent")).choices([...agentPresetNames])).addOption(new Option("--remove-agents", t2("help.initRemoveAgents")).conflicts("skipAgents")).option("--skip-agents", t2("help.initSkipAgents")).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action((options) => runInit(options, "0.6.0"));
27891
+ program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).option("--no-update-check", t2("help.browserNoUpdateCheck")).action((options) => runBrowser(options, "0.6.2"));
27892
+ program2.command("init").description(t2("help.init")).allowExcessArguments(false).option("--dry-run", t2("help.initDryRun")).addOption(new Option("--agent <agent>", t2("help.initAgent")).choices([...agentPresetNames])).addOption(new Option("--remove-agents", t2("help.initRemoveAgents")).conflicts("skipAgents")).option("--skip-agents", t2("help.initSkipAgents")).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action((options) => runInit(options, "0.6.2"));
27262
27893
  program2.command("docs").description(t2("help.docs")).argument("[topic]", t2("help.docsTopic")).allowExcessArguments(false).action(async (topic) => {
27263
27894
  await runDocs(topic);
27264
27895
  });
27265
- program2.command("update").description(t2("help.update")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).option("--commit", t2("help.updateCommit")).action((options) => runUpdate(options, "0.6.0"));
27896
+ program2.command("update").description(t2("help.update")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).option("--commit", t2("help.updateCommit")).action((options) => runUpdate(options, "0.6.2"));
27266
27897
  program2.command("migrate").description(t2("help.migrate")).allowExcessArguments(false).option("--dry-run", t2("help.migrateDryRun")).action(runMigrate);
27267
27898
  var spec = program2.command("spec").description(t2("help.spec"));
27268
27899
  spec.command("commit").description(t2("help.specCommit")).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specCommitFile")).option("--dry-run", t2("help.specCommitDryRun")).action((o) => runSpecPreview("commit", o));