shell-dsl 0.0.34 → 0.0.36

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 (92) hide show
  1. package/README.md +41 -5
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/src/fs/memfs-adapter.cjs +56 -2
  4. package/dist/cjs/src/fs/memfs-adapter.cjs.map +3 -3
  5. package/dist/cjs/src/fs/real-fs.cjs +134 -3
  6. package/dist/cjs/src/fs/real-fs.cjs.map +3 -3
  7. package/dist/cjs/src/fs/special-files.cjs +3 -2
  8. package/dist/cjs/src/fs/special-files.cjs.map +3 -3
  9. package/dist/cjs/src/fs/web-fs.cjs +72 -3
  10. package/dist/cjs/src/fs/web-fs.cjs.map +3 -3
  11. package/dist/cjs/src/index.cjs +2 -7
  12. package/dist/cjs/src/index.cjs.map +3 -3
  13. package/dist/cjs/src/interpreter/interpreter.cjs +186 -68
  14. package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
  15. package/dist/cjs/src/parser/ast.cjs +5 -25
  16. package/dist/cjs/src/parser/ast.cjs.map +3 -3
  17. package/dist/cjs/src/parser/index.cjs +2 -7
  18. package/dist/cjs/src/parser/index.cjs.map +3 -3
  19. package/dist/cjs/src/parser/parser.cjs +132 -82
  20. package/dist/cjs/src/parser/parser.cjs.map +3 -3
  21. package/dist/cjs/src/types.cjs.map +2 -2
  22. package/dist/cjs/src/vcs/content.cjs +106 -0
  23. package/dist/cjs/src/vcs/content.cjs.map +10 -0
  24. package/dist/cjs/src/vcs/diff.cjs +72 -28
  25. package/dist/cjs/src/vcs/diff.cjs.map +3 -3
  26. package/dist/cjs/src/vcs/index.cjs.map +1 -1
  27. package/dist/cjs/src/vcs/objects.cjs +141 -0
  28. package/dist/cjs/src/vcs/objects.cjs.map +10 -0
  29. package/dist/cjs/src/vcs/rules.cjs +6 -3
  30. package/dist/cjs/src/vcs/rules.cjs.map +3 -3
  31. package/dist/cjs/src/vcs/snapshot.cjs +89 -39
  32. package/dist/cjs/src/vcs/snapshot.cjs.map +3 -3
  33. package/dist/cjs/src/vcs/storage.cjs +44 -3
  34. package/dist/cjs/src/vcs/storage.cjs.map +3 -3
  35. package/dist/cjs/src/vcs/text-diff.cjs +219 -0
  36. package/dist/cjs/src/vcs/text-diff.cjs.map +10 -0
  37. package/dist/cjs/src/vcs/vcs.cjs +108 -61
  38. package/dist/cjs/src/vcs/vcs.cjs.map +3 -3
  39. package/dist/mjs/package.json +1 -1
  40. package/dist/mjs/src/fs/memfs-adapter.mjs +57 -2
  41. package/dist/mjs/src/fs/memfs-adapter.mjs.map +3 -3
  42. package/dist/mjs/src/fs/real-fs.mjs +135 -3
  43. package/dist/mjs/src/fs/real-fs.mjs.map +3 -3
  44. package/dist/mjs/src/fs/special-files.mjs +3 -2
  45. package/dist/mjs/src/fs/special-files.mjs.map +3 -3
  46. package/dist/mjs/src/fs/web-fs.mjs +72 -3
  47. package/dist/mjs/src/fs/web-fs.mjs.map +3 -3
  48. package/dist/mjs/src/index.mjs +4 -14
  49. package/dist/mjs/src/index.mjs.map +3 -3
  50. package/dist/mjs/src/interpreter/interpreter.mjs +186 -68
  51. package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
  52. package/dist/mjs/src/parser/ast.mjs +5 -25
  53. package/dist/mjs/src/parser/ast.mjs.map +3 -3
  54. package/dist/mjs/src/parser/index.mjs +4 -14
  55. package/dist/mjs/src/parser/index.mjs.map +3 -3
  56. package/dist/mjs/src/parser/parser.mjs +132 -82
  57. package/dist/mjs/src/parser/parser.mjs.map +3 -3
  58. package/dist/mjs/src/types.mjs.map +2 -2
  59. package/dist/mjs/src/vcs/content.mjs +66 -0
  60. package/dist/mjs/src/vcs/content.mjs.map +10 -0
  61. package/dist/mjs/src/vcs/diff.mjs +72 -28
  62. package/dist/mjs/src/vcs/diff.mjs.map +3 -3
  63. package/dist/mjs/src/vcs/index.mjs.map +1 -1
  64. package/dist/mjs/src/vcs/objects.mjs +106 -0
  65. package/dist/mjs/src/vcs/objects.mjs.map +10 -0
  66. package/dist/mjs/src/vcs/rules.mjs +6 -3
  67. package/dist/mjs/src/vcs/rules.mjs.map +3 -3
  68. package/dist/mjs/src/vcs/snapshot.mjs +89 -39
  69. package/dist/mjs/src/vcs/snapshot.mjs.map +3 -3
  70. package/dist/mjs/src/vcs/storage.mjs +45 -3
  71. package/dist/mjs/src/vcs/storage.mjs.map +3 -3
  72. package/dist/mjs/src/vcs/text-diff.mjs +179 -0
  73. package/dist/mjs/src/vcs/text-diff.mjs.map +10 -0
  74. package/dist/mjs/src/vcs/vcs.mjs +115 -63
  75. package/dist/mjs/src/vcs/vcs.mjs.map +3 -3
  76. package/dist/types/src/fs/real-fs.d.ts +12 -1
  77. package/dist/types/src/index.d.ts +4 -4
  78. package/dist/types/src/interpreter/interpreter.d.ts +15 -1
  79. package/dist/types/src/parser/ast.d.ts +34 -38
  80. package/dist/types/src/parser/index.d.ts +2 -2
  81. package/dist/types/src/parser/parser.d.ts +4 -1
  82. package/dist/types/src/types.d.ts +10 -0
  83. package/dist/types/src/vcs/content.d.ts +6 -0
  84. package/dist/types/src/vcs/diff.d.ts +10 -7
  85. package/dist/types/src/vcs/index.d.ts +1 -1
  86. package/dist/types/src/vcs/objects.d.ts +22 -0
  87. package/dist/types/src/vcs/snapshot.d.ts +13 -8
  88. package/dist/types/src/vcs/storage.d.ts +7 -1
  89. package/dist/types/src/vcs/text-diff.d.ts +1 -0
  90. package/dist/types/src/vcs/types.d.ts +20 -5
  91. package/dist/types/src/vcs/vcs.d.ts +6 -0
  92. package/package.json +7 -2
@@ -39,63 +39,107 @@ var __export = (target, all) => {
39
39
  // src/vcs/diff.ts
40
40
  var exports_diff = {};
41
41
  __export(exports_diff, {
42
- diffWorkingTree: () => diffWorkingTree,
43
42
  diffManifests: () => diffManifests
44
43
  });
45
44
  module.exports = __toCommonJS(exports_diff);
45
+ var import_content = require("./content.cjs");
46
46
  var import_rules = require("./rules.cjs");
47
- var import_snapshot = require("./snapshot.cjs");
48
- function diffManifests(before, after, rules = new import_rules.VCSRules) {
47
+ var import_text_diff = require("./text-diff.cjs");
48
+ async function diffManifests(before, after, options) {
49
49
  const entries = [];
50
50
  const allPaths = new Set([...Object.keys(before), ...Object.keys(after)]);
51
- for (const path of allPaths) {
51
+ for (const path of [...allPaths].sort((a, b) => a.localeCompare(b))) {
52
52
  const prev = before[path];
53
53
  const curr = after[path];
54
54
  if (!prev && curr) {
55
- entries.push(createDiffEntry("add", path, curr, undefined, rules));
55
+ entries.push(await createDiffEntry("add", path, curr, undefined, options));
56
56
  } else if (prev && !curr) {
57
- entries.push(createDiffEntry("delete", path, undefined, prev, rules));
57
+ entries.push(await createDiffEntry("delete", path, undefined, prev, options));
58
58
  } else if (prev && curr && !entriesEqual(prev, curr)) {
59
- entries.push(createDiffEntry("modify", path, curr, prev, rules));
59
+ entries.push(await createDiffEntry("modify", path, curr, prev, options));
60
60
  }
61
61
  }
62
- return entries.sort((a, b) => a.path.localeCompare(b.path));
62
+ return entries;
63
63
  }
64
- async function diffWorkingTree(fs, rootPath, manifest, rules = new import_rules.VCSRules({ internalDirName: ".vcs" })) {
65
- const workingManifest = await import_snapshot.buildTreeManifest(fs, rootPath, {
66
- rules,
67
- trackedPaths: Object.keys(manifest)
68
- });
69
- return diffManifests(manifest, workingManifest, rules);
70
- }
71
- function createDiffEntry(type, path, current, previous, rules) {
64
+ async function createDiffEntry(type, path, current, previous, options) {
65
+ const rules = options.rules ?? new import_rules.VCSRules;
72
66
  const attributes = rules.resolveAttributes(path);
73
67
  const entryKind = getEntryKind(current ?? previous);
74
68
  const previousEntryKind = previous ? getEntryKind(previous) : undefined;
69
+ const currentFile = isFileEntry(current) ? current : undefined;
70
+ const previousFile = isFileEntry(previous) ? previous : undefined;
71
+ const binary = await resolveBinary(path, currentFile, previousFile, attributes, options);
72
+ const diff = resolveDiffMode(attributes, binary);
75
73
  const entry = {
76
74
  type,
77
75
  path,
78
- binary: attributes.binary,
79
- diff: attributes.diff,
76
+ binary,
77
+ diff,
80
78
  entryKind,
81
- previousEntryKind
79
+ previousEntryKind,
80
+ blobId: currentFile?.blobId,
81
+ previousBlobId: previousFile?.blobId
82
82
  };
83
- if (attributes.diff !== "none") {
84
- if (isFileEntry(current)) {
85
- entry.content = current.content;
86
- }
87
- if (isFileEntry(previous)) {
88
- entry.previousContent = previous.content;
89
- }
83
+ if (!currentFile && !previousFile) {
84
+ return entry;
85
+ }
86
+ if (diff === "none") {
87
+ entry.patchSuppressedReason = "none";
88
+ return entry;
90
89
  }
90
+ if (diff === "binary") {
91
+ entry.patchSuppressedReason = "binary";
92
+ return entry;
93
+ }
94
+ const largestSize = Math.max(currentFile?.size ?? 0, previousFile?.size ?? 0);
95
+ if (largestSize > import_content.MAX_PATCH_BYTES) {
96
+ entry.patchSuppressedReason = "too-large";
97
+ return entry;
98
+ }
99
+ const previousText = previousFile ? await options.objectStore.readBlobText(previousFile.blobId) : "";
100
+ const currentText = currentFile ? await options.objectStore.readBlobText(currentFile.blobId) : "";
101
+ entry.patch = import_text_diff.createUnifiedPatch(path, previousText, currentText);
91
102
  return entry;
92
103
  }
104
+ async function resolveBinary(path, current, previous, attributes, options) {
105
+ if (attributes.diff === "text") {
106
+ return false;
107
+ }
108
+ if (attributes.diff === "binary" || attributes.binary === true) {
109
+ return true;
110
+ }
111
+ const currentBinary = await resolveEntryBinary(path, current, options.afterIndex, options.objectStore);
112
+ const previousBinary = await resolveEntryBinary(path, previous, options.beforeIndex, options.objectStore);
113
+ return currentBinary || previousBinary;
114
+ }
115
+ async function resolveEntryBinary(path, entry, indexEntries, objectStore) {
116
+ if (!entry) {
117
+ return false;
118
+ }
119
+ const cached = indexEntries?.[path];
120
+ if (cached?.blobId === entry.blobId) {
121
+ return cached.binary;
122
+ }
123
+ return objectStore.isBinaryBlob(entry.blobId);
124
+ }
125
+ function resolveDiffMode(attributes, binary) {
126
+ if (attributes.diff === "none") {
127
+ return "none";
128
+ }
129
+ if (attributes.diff === "text") {
130
+ return "text";
131
+ }
132
+ if (attributes.diff === "binary" || binary) {
133
+ return "binary";
134
+ }
135
+ return "text";
136
+ }
93
137
  function entriesEqual(a, b) {
94
138
  if (getEntryKind(a) !== getEntryKind(b))
95
139
  return false;
96
140
  if (!isFileEntry(a) || !isFileEntry(b))
97
141
  return true;
98
- return a.content === b.content;
142
+ return a.blobId === b.blobId && a.size === b.size;
99
143
  }
100
144
  function getEntryKind(entry) {
101
145
  return entry?.kind === "directory" ? "directory" : "file";
@@ -104,4 +148,4 @@ function isFileEntry(entry) {
104
148
  return !!entry && entry.kind !== "directory";
105
149
  }
106
150
 
107
- //# debugId=F0849DE3546011FF64756E2164756E21
151
+ //# debugId=07954E8C085717B664756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/vcs/diff.ts"],
4
4
  "sourcesContent": [
5
- "import type { VirtualFS } from \"../types.cjs\";\nimport type { TreeManifest, DiffEntry, TreeEntry } from \"./types.cjs\";\nimport { VCSRules } from \"./rules.cjs\";\nimport { buildTreeManifest } from \"./snapshot.cjs\";\n\n/**\n * Compute diff entries between two tree manifests.\n */\nexport function diffManifests(\n before: TreeManifest,\n after: TreeManifest,\n rules: VCSRules = new VCSRules(),\n): DiffEntry[] {\n const entries: DiffEntry[] = [];\n const allPaths = new Set([...Object.keys(before), ...Object.keys(after)]);\n\n for (const path of allPaths) {\n const prev = before[path];\n const curr = after[path];\n\n if (!prev && curr) {\n entries.push(createDiffEntry(\"add\", path, curr, undefined, rules));\n } else if (prev && !curr) {\n entries.push(createDiffEntry(\"delete\", path, undefined, prev, rules));\n } else if (prev && curr && !entriesEqual(prev, curr)) {\n entries.push(createDiffEntry(\"modify\", path, curr, prev, rules));\n }\n }\n\n return entries.sort((a, b) => a.path.localeCompare(b.path));\n}\n\n/**\n * Compute diff between a tree manifest and the current working tree.\n */\nexport async function diffWorkingTree(\n fs: VirtualFS,\n rootPath: string,\n manifest: TreeManifest,\n rules: VCSRules = new VCSRules({ internalDirName: \".vcs\" }),\n): Promise<DiffEntry[]> {\n const workingManifest = await buildTreeManifest(fs, rootPath, {\n rules,\n trackedPaths: Object.keys(manifest),\n });\n return diffManifests(manifest, workingManifest, rules);\n}\n\nfunction createDiffEntry(\n type: DiffEntry[\"type\"],\n path: string,\n current: TreeEntry | undefined,\n previous: TreeEntry | undefined,\n rules: VCSRules,\n): DiffEntry {\n const attributes = rules.resolveAttributes(path);\n const entryKind = getEntryKind(current ?? previous);\n const previousEntryKind = previous ? getEntryKind(previous) : undefined;\n const entry: DiffEntry = {\n type,\n path,\n binary: attributes.binary,\n diff: attributes.diff,\n entryKind,\n previousEntryKind,\n };\n\n if (attributes.diff !== \"none\") {\n if (isFileEntry(current)) {\n entry.content = current.content;\n }\n if (isFileEntry(previous)) {\n entry.previousContent = previous.content;\n }\n }\n\n return entry;\n}\n\nfunction entriesEqual(a: TreeEntry, b: TreeEntry): boolean {\n if (getEntryKind(a) !== getEntryKind(b)) return false;\n if (!isFileEntry(a) || !isFileEntry(b)) return true;\n return a.content === b.content;\n}\n\nfunction getEntryKind(entry: TreeEntry | undefined): \"file\" | \"directory\" {\n return entry?.kind === \"directory\" ? \"directory\" : \"file\";\n}\n\nfunction isFileEntry(entry: TreeEntry | undefined): entry is Extract<TreeEntry, { kind?: \"file\" }> {\n return !!entry && entry.kind !== \"directory\";\n}\n"
5
+ "import type { TreeManifest, DiffEntry, TreeEntry, VCSIndexEntry } from \"./types.cjs\";\nimport { MAX_PATCH_BYTES } from \"./content.cjs\";\nimport { VCSObjectStore } from \"./objects.cjs\";\nimport { VCSRules } from \"./rules.cjs\";\nimport { createUnifiedPatch } from \"./text-diff.cjs\";\n\ninterface DiffOptions {\n rules?: VCSRules;\n objectStore: VCSObjectStore;\n beforeIndex?: Record<string, VCSIndexEntry>;\n afterIndex?: Record<string, VCSIndexEntry>;\n}\n\n/**\n * Compute diff entries between two tree manifests.\n */\nexport async function diffManifests(\n before: TreeManifest,\n after: TreeManifest,\n options: DiffOptions,\n): Promise<DiffEntry[]> {\n const entries: DiffEntry[] = [];\n const allPaths = new Set([...Object.keys(before), ...Object.keys(after)]);\n\n for (const path of [...allPaths].sort((a, b) => a.localeCompare(b))) {\n const prev = before[path];\n const curr = after[path];\n\n if (!prev && curr) {\n entries.push(await createDiffEntry(\"add\", path, curr, undefined, options));\n } else if (prev && !curr) {\n entries.push(await createDiffEntry(\"delete\", path, undefined, prev, options));\n } else if (prev && curr && !entriesEqual(prev, curr)) {\n entries.push(await createDiffEntry(\"modify\", path, curr, prev, options));\n }\n }\n\n return entries;\n}\n\nasync function createDiffEntry(\n type: DiffEntry[\"type\"],\n path: string,\n current: TreeEntry | undefined,\n previous: TreeEntry | undefined,\n options: DiffOptions,\n): Promise<DiffEntry> {\n const rules = options.rules ?? new VCSRules();\n const attributes = rules.resolveAttributes(path);\n const entryKind = getEntryKind(current ?? previous);\n const previousEntryKind = previous ? getEntryKind(previous) : undefined;\n const currentFile = isFileEntry(current) ? current : undefined;\n const previousFile = isFileEntry(previous) ? previous : undefined;\n const binary = await resolveBinary(path, currentFile, previousFile, attributes, options);\n const diff = resolveDiffMode(attributes, binary);\n const entry: DiffEntry = {\n type,\n path,\n binary,\n diff,\n entryKind,\n previousEntryKind,\n blobId: currentFile?.blobId,\n previousBlobId: previousFile?.blobId,\n };\n\n if (!currentFile && !previousFile) {\n return entry;\n }\n\n if (diff === \"none\") {\n entry.patchSuppressedReason = \"none\";\n return entry;\n }\n\n if (diff === \"binary\") {\n entry.patchSuppressedReason = \"binary\";\n return entry;\n }\n\n const largestSize = Math.max(currentFile?.size ?? 0, previousFile?.size ?? 0);\n if (largestSize > MAX_PATCH_BYTES) {\n entry.patchSuppressedReason = \"too-large\";\n return entry;\n }\n\n const previousText = previousFile\n ? await options.objectStore.readBlobText(previousFile.blobId)\n : \"\";\n const currentText = currentFile\n ? await options.objectStore.readBlobText(currentFile.blobId)\n : \"\";\n entry.patch = createUnifiedPatch(path, previousText, currentText);\n return entry;\n}\n\nasync function resolveBinary(\n path: string,\n current: Extract<TreeEntry, { kind?: \"file\" }> | undefined,\n previous: Extract<TreeEntry, { kind?: \"file\" }> | undefined,\n attributes: ReturnType<VCSRules[\"resolveAttributes\"]>,\n options: DiffOptions,\n): Promise<boolean> {\n if (attributes.diff === \"text\") {\n return false;\n }\n if (attributes.diff === \"binary\" || attributes.binary === true) {\n return true;\n }\n\n const currentBinary = await resolveEntryBinary(\n path,\n current,\n options.afterIndex,\n options.objectStore,\n );\n const previousBinary = await resolveEntryBinary(\n path,\n previous,\n options.beforeIndex,\n options.objectStore,\n );\n\n return currentBinary || previousBinary;\n}\n\nasync function resolveEntryBinary(\n path: string,\n entry: Extract<TreeEntry, { kind?: \"file\" }> | undefined,\n indexEntries: Record<string, VCSIndexEntry> | undefined,\n objectStore: VCSObjectStore,\n): Promise<boolean> {\n if (!entry) {\n return false;\n }\n const cached = indexEntries?.[path];\n if (cached?.blobId === entry.blobId) {\n return cached.binary;\n }\n return objectStore.isBinaryBlob(entry.blobId);\n}\n\nfunction resolveDiffMode(\n attributes: ReturnType<VCSRules[\"resolveAttributes\"]>,\n binary: boolean,\n): DiffEntry[\"diff\"] {\n if (attributes.diff === \"none\") {\n return \"none\";\n }\n if (attributes.diff === \"text\") {\n return \"text\";\n }\n if (attributes.diff === \"binary\" || binary) {\n return \"binary\";\n }\n return \"text\";\n}\n\nfunction entriesEqual(a: TreeEntry, b: TreeEntry): boolean {\n if (getEntryKind(a) !== getEntryKind(b)) return false;\n if (!isFileEntry(a) || !isFileEntry(b)) return true;\n return a.blobId === b.blobId && a.size === b.size;\n}\n\nfunction getEntryKind(entry: TreeEntry | undefined): \"file\" | \"directory\" {\n return entry?.kind === \"directory\" ? \"directory\" : \"file\";\n}\n\nfunction isFileEntry(entry: TreeEntry | undefined): entry is Extract<TreeEntry, { kind?: \"file\" }> {\n return !!entry && entry.kind !== \"directory\";\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEyB,IAAzB;AACkC,IAAlC;AAKO,SAAS,aAAa,CAC3B,QACA,OACA,QAAkB,IAAI,uBACT;AAAA,EACb,MAAM,UAAuB,CAAC;AAAA,EAC9B,MAAM,WAAW,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC;AAAA,EAExE,WAAW,QAAQ,UAAU;AAAA,IAC3B,MAAM,OAAO,OAAO;AAAA,IACpB,MAAM,OAAO,MAAM;AAAA,IAEnB,IAAI,CAAC,QAAQ,MAAM;AAAA,MACjB,QAAQ,KAAK,gBAAgB,OAAO,MAAM,MAAM,WAAW,KAAK,CAAC;AAAA,IACnE,EAAO,SAAI,QAAQ,CAAC,MAAM;AAAA,MACxB,QAAQ,KAAK,gBAAgB,UAAU,MAAM,WAAW,MAAM,KAAK,CAAC;AAAA,IACtE,EAAO,SAAI,QAAQ,QAAQ,CAAC,aAAa,MAAM,IAAI,GAAG;AAAA,MACpD,QAAQ,KAAK,gBAAgB,UAAU,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,OAAO,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA;AAM5D,eAAsB,eAAe,CACnC,IACA,UACA,UACA,QAAkB,IAAI,sBAAS,EAAE,iBAAiB,OAAO,CAAC,GACpC;AAAA,EACtB,MAAM,kBAAkB,MAAM,kCAAkB,IAAI,UAAU;AAAA,IAC5D;AAAA,IACA,cAAc,OAAO,KAAK,QAAQ;AAAA,EACpC,CAAC;AAAA,EACD,OAAO,cAAc,UAAU,iBAAiB,KAAK;AAAA;AAGvD,SAAS,eAAe,CACtB,MACA,MACA,SACA,UACA,OACW;AAAA,EACX,MAAM,aAAa,MAAM,kBAAkB,IAAI;AAAA,EAC/C,MAAM,YAAY,aAAa,WAAW,QAAQ;AAAA,EAClD,MAAM,oBAAoB,WAAW,aAAa,QAAQ,IAAI;AAAA,EAC9D,MAAM,QAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA,QAAQ,WAAW;AAAA,IACnB,MAAM,WAAW;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AAAA,EAEA,IAAI,WAAW,SAAS,QAAQ;AAAA,IAC9B,IAAI,YAAY,OAAO,GAAG;AAAA,MACxB,MAAM,UAAU,QAAQ;AAAA,IAC1B;AAAA,IACA,IAAI,YAAY,QAAQ,GAAG;AAAA,MACzB,MAAM,kBAAkB,SAAS;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,OAAO;AAAA;AAGT,SAAS,YAAY,CAAC,GAAc,GAAuB;AAAA,EACzD,IAAI,aAAa,CAAC,MAAM,aAAa,CAAC;AAAA,IAAG,OAAO;AAAA,EAChD,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC;AAAA,IAAG,OAAO;AAAA,EAC/C,OAAO,EAAE,YAAY,EAAE;AAAA;AAGzB,SAAS,YAAY,CAAC,OAAoD;AAAA,EACxE,OAAO,OAAO,SAAS,cAAc,cAAc;AAAA;AAGrD,SAAS,WAAW,CAAC,OAA8E;AAAA,EACjG,OAAO,CAAC,CAAC,SAAS,MAAM,SAAS;AAAA;",
8
- "debugId": "F0849DE3546011FF64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "07954E8C085717B664756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -2,7 +2,7 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/vcs/index.ts"],
4
4
  "sourcesContent": [
5
- "export { VersionControlSystem } from \"./vcs.cjs\";\nexport type {\n VCSConfig,\n VCSAttributeRule,\n VCSResolvedAttributes,\n VCSDiffMode,\n Revision,\n DiffEntry,\n TreeManifest,\n TreeEntry,\n FileEntry,\n DirectoryEntry,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./types.cjs\";\n"
5
+ "export { VersionControlSystem } from \"./vcs.cjs\";\nexport type {\n VCSConfig,\n VCSAttributeRule,\n VCSResolvedAttributes,\n VCSDiffMode,\n VCSPatchSuppressionReason,\n Revision,\n DiffEntry,\n TreeManifest,\n TreeEntry,\n FileEntry,\n DirectoryEntry,\n VCSIndexEntry,\n VCSIndexFile,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./types.cjs\";\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAqC,IAArC;",
8
8
  "debugId": "882B2013CEEDB5D864756E2164756E21",
@@ -0,0 +1,141 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/vcs/objects.ts
40
+ var exports_objects = {};
41
+ __export(exports_objects, {
42
+ VCSObjectStore: () => VCSObjectStore
43
+ });
44
+ module.exports = __toCommonJS(exports_objects);
45
+ var import_sha2 = require("@noble/hashes/sha2.js");
46
+ var import_content = require("./content.cjs");
47
+
48
+ class VCSObjectStore {
49
+ fs;
50
+ basePath;
51
+ constructor(fs, basePath) {
52
+ this.fs = fs;
53
+ this.basePath = basePath;
54
+ }
55
+ async initialize() {
56
+ await this.fs.mkdir(this.path("objects", "blobs"), { recursive: true });
57
+ await this.fs.mkdir(this.path("tmp"), { recursive: true });
58
+ }
59
+ async hasBlob(blobId) {
60
+ return this.fs.exists(this.blobPath(blobId));
61
+ }
62
+ async store(source) {
63
+ const tempPath = this.path("tmp", `${Date.now()}-${Math.random().toString(36).slice(2)}.blob`);
64
+ const writer = await this.fs.writeStream(tempPath);
65
+ const hash = import_sha2.sha256.create();
66
+ let size = 0;
67
+ let sample = new Uint8Array;
68
+ try {
69
+ for await (const chunk of source) {
70
+ const bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
71
+ hash.update(bytes);
72
+ size += bytes.byteLength;
73
+ sample = import_content.appendSample(sample, bytes);
74
+ await writer.write(bytes);
75
+ }
76
+ await writer.close();
77
+ const blobId = toHex(hash.digest());
78
+ const finalPath = this.blobPath(blobId);
79
+ await this.fs.mkdir(this.fs.dirname(finalPath), { recursive: true });
80
+ if (!await this.fs.exists(finalPath)) {
81
+ await copyStream(this.fs, tempPath, finalPath);
82
+ }
83
+ await this.fs.rm(tempPath, { force: true });
84
+ return {
85
+ blobId,
86
+ size,
87
+ binary: import_content.detectBinaryFromSample(sample),
88
+ sampleHash: import_content.hashSample(sample)
89
+ };
90
+ } catch (error) {
91
+ await writer.abort?.(error);
92
+ await this.fs.rm(tempPath, { force: true });
93
+ throw error;
94
+ }
95
+ }
96
+ async readBlob(blobId) {
97
+ return this.fs.readFile(this.blobPath(blobId));
98
+ }
99
+ async readBlobText(blobId) {
100
+ return this.fs.readFile(this.blobPath(blobId), "utf8");
101
+ }
102
+ readBlobStream(blobId) {
103
+ return this.fs.readStream(this.blobPath(blobId));
104
+ }
105
+ async isBinaryBlob(blobId) {
106
+ const sample = await import_content.readStreamSample(this.readBlobStream(blobId));
107
+ return import_content.detectBinaryFromSample(sample);
108
+ }
109
+ async deleteTempFiles() {
110
+ await this.fs.rm(this.path("tmp"), { recursive: true, force: true });
111
+ await this.fs.mkdir(this.path("tmp"), { recursive: true });
112
+ }
113
+ blobPath(blobId) {
114
+ return this.path("objects", "blobs", blobId.slice(0, 2), blobId.slice(2));
115
+ }
116
+ path(...segments) {
117
+ return this.fs.resolve(this.basePath, ...segments);
118
+ }
119
+ }
120
+ async function copyStream(fs, fromPath, toPath) {
121
+ const writer = await fs.writeStream(toPath);
122
+ try {
123
+ for await (const chunk of fs.readStream(fromPath)) {
124
+ await writer.write(chunk);
125
+ }
126
+ await writer.close();
127
+ } catch (error) {
128
+ await writer.abort?.(error);
129
+ await fs.rm(toPath, { force: true });
130
+ throw error;
131
+ }
132
+ }
133
+ function toHex(bytes) {
134
+ let out = "";
135
+ for (const byte of bytes) {
136
+ out += byte.toString(16).padStart(2, "0");
137
+ }
138
+ return out;
139
+ }
140
+
141
+ //# debugId=46E2107E1DA7789564756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/vcs/objects.ts"],
4
+ "sourcesContent": [
5
+ "import { sha256 } from \"@noble/hashes/sha2.js\";\nimport type { VirtualFS } from \"../types.cjs\";\nimport {\n appendSample,\n detectBinaryFromSample,\n hashSample,\n readStreamSample,\n} from \"./content.cjs\";\n\nexport interface StoredBlob {\n blobId: string;\n size: number;\n binary: boolean;\n sampleHash: string;\n}\n\nexport class VCSObjectStore {\n constructor(\n private readonly fs: VirtualFS,\n private readonly basePath: string,\n ) {}\n\n async initialize(): Promise<void> {\n await this.fs.mkdir(this.path(\"objects\", \"blobs\"), { recursive: true });\n await this.fs.mkdir(this.path(\"tmp\"), { recursive: true });\n }\n\n async hasBlob(blobId: string): Promise<boolean> {\n return this.fs.exists(this.blobPath(blobId));\n }\n\n async store(source: AsyncIterable<Uint8Array>): Promise<StoredBlob> {\n const tempPath = this.path(\"tmp\", `${Date.now()}-${Math.random().toString(36).slice(2)}.blob`);\n const writer = await this.fs.writeStream(tempPath);\n const hash = sha256.create();\n let size = 0;\n let sample: Uint8Array<ArrayBufferLike> = new Uint8Array();\n\n try {\n for await (const chunk of source) {\n const bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\n hash.update(bytes);\n size += bytes.byteLength;\n sample = appendSample(sample, bytes);\n await writer.write(bytes);\n }\n await writer.close();\n\n const blobId = toHex(hash.digest());\n const finalPath = this.blobPath(blobId);\n await this.fs.mkdir(this.fs.dirname(finalPath), { recursive: true });\n\n if (!(await this.fs.exists(finalPath))) {\n await copyStream(this.fs, tempPath, finalPath);\n }\n\n await this.fs.rm(tempPath, { force: true });\n return {\n blobId,\n size,\n binary: detectBinaryFromSample(sample),\n sampleHash: hashSample(sample),\n };\n } catch (error) {\n await writer.abort?.(error);\n await this.fs.rm(tempPath, { force: true });\n throw error;\n }\n }\n\n async readBlob(blobId: string): Promise<Buffer> {\n return this.fs.readFile(this.blobPath(blobId));\n }\n\n async readBlobText(blobId: string): Promise<string> {\n return this.fs.readFile(this.blobPath(blobId), \"utf8\");\n }\n\n readBlobStream(blobId: string): AsyncIterable<Uint8Array> {\n return this.fs.readStream(this.blobPath(blobId));\n }\n\n async isBinaryBlob(blobId: string): Promise<boolean> {\n const sample = await readStreamSample(this.readBlobStream(blobId));\n return detectBinaryFromSample(sample);\n }\n\n async deleteTempFiles(): Promise<void> {\n await this.fs.rm(this.path(\"tmp\"), { recursive: true, force: true });\n await this.fs.mkdir(this.path(\"tmp\"), { recursive: true });\n }\n\n private blobPath(blobId: string): string {\n return this.path(\"objects\", \"blobs\", blobId.slice(0, 2), blobId.slice(2));\n }\n\n private path(...segments: string[]): string {\n return this.fs.resolve(this.basePath, ...segments);\n }\n}\n\nasync function copyStream(fs: VirtualFS, fromPath: string, toPath: string): Promise<void> {\n const writer = await fs.writeStream(toPath);\n try {\n for await (const chunk of fs.readStream(fromPath)) {\n await writer.write(chunk);\n }\n await writer.close();\n } catch (error) {\n await writer.abort?.(error);\n await fs.rm(toPath, { force: true });\n throw error;\n }\n}\n\nfunction toHex(bytes: Uint8Array): string {\n let out = \"\";\n for (const byte of bytes) {\n out += byte.toString(16).padStart(2, \"0\");\n }\n return out;\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "46E2107E1DA7789564756E2164756E21",
9
+ "names": []
10
+ }
@@ -97,8 +97,8 @@ class VCSRules {
97
97
  return this.isIgnored(relPath);
98
98
  }
99
99
  resolveAttributes(relPath) {
100
- let binary = false;
101
- let diff = "text";
100
+ let binary;
101
+ let diff;
102
102
  for (const rule of this.attributeRules) {
103
103
  if (!matchVCSPath(rule.pattern, relPath))
104
104
  continue;
@@ -112,6 +112,9 @@ class VCSRules {
112
112
  if (diff === "binary") {
113
113
  binary = true;
114
114
  }
115
+ if (diff === "text") {
116
+ binary = false;
117
+ }
115
118
  return { binary, diff };
116
119
  }
117
120
  }
@@ -177,4 +180,4 @@ function hasTrackedPathAtOrBelow(relPath, trackedPaths) {
177
180
  return false;
178
181
  }
179
182
 
180
- //# debugId=FD722B600498944364756E2164756E21
183
+ //# debugId=44746568854B06D364756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/vcs/rules.ts"],
4
4
  "sourcesContent": [
5
- "import { matchGlobPath } from \"./match.cjs\";\nimport type { VCSAttributeRule, VCSResolvedAttributes } from \"./types.cjs\";\n\ninterface VCSRulesConfig {\n internalPath?: string;\n internalDirName?: string;\n ignore?: string[];\n attributes?: VCSAttributeRule[];\n}\n\nexport class VCSRules {\n private readonly internalPath: string;\n private readonly ignorePatterns: string[];\n private readonly attributeRules: VCSAttributeRule[];\n\n constructor(config: VCSRulesConfig = {}) {\n this.internalPath = normalizePath(config.internalPath ?? config.internalDirName ?? \"\");\n this.ignorePatterns = [...(config.ignore ?? [])];\n this.attributeRules = [...(config.attributes ?? [])];\n }\n\n isInternalPath(relPath: string): boolean {\n if (!this.internalPath) return false;\n const normalizedPath = normalizePath(relPath);\n if (!normalizedPath) return false;\n return normalizedPath === this.internalPath || normalizedPath.startsWith(`${this.internalPath}/`);\n }\n\n isIgnored(relPath: string): boolean {\n if (this.isInternalPath(relPath)) return true;\n return this.ignorePatterns.some((pattern) => matchVCSPath(pattern, relPath));\n }\n\n shouldEnterDirectory(relPath: string, trackedPaths: Iterable<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (!this.isIgnored(relPath)) return true;\n return hasTrackedPathAtOrBelow(relPath, trackedPaths);\n }\n\n shouldIncludeWorkingFile(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (trackedPaths.has(relPath)) return true;\n return !this.isIgnored(relPath);\n }\n\n shouldIncludeEmptyDirectory(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (trackedPaths.has(relPath)) return true;\n return !this.isIgnored(relPath);\n }\n\n shouldIncludeRestoreScanFile(relPath: string): boolean {\n return !this.isInternalPath(relPath);\n }\n\n shouldPreserveUntrackedIgnored(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (trackedPaths.has(relPath)) return false;\n return this.isIgnored(relPath);\n }\n\n resolveAttributes(relPath: string): VCSResolvedAttributes {\n let binary = false;\n let diff: VCSResolvedAttributes[\"diff\"] = \"text\";\n\n for (const rule of this.attributeRules) {\n if (!matchVCSPath(rule.pattern, relPath)) continue;\n if (rule.binary !== undefined) {\n binary = rule.binary;\n }\n if (rule.diff !== undefined) {\n diff = rule.diff;\n }\n }\n\n if (diff === \"binary\") {\n binary = true;\n }\n\n return { binary, diff };\n }\n}\n\nexport function matchVCSPath(pattern: string, relPath: string): boolean {\n const normalizedPattern = normalizePattern(pattern);\n const normalizedPath = normalizePath(relPath);\n\n if (!normalizedPattern || !normalizedPath) return false;\n\n if (normalizedPattern.mode === \"root-path\") {\n return matchGlobPath(normalizedPattern.pattern, normalizedPath);\n }\n\n if (normalizedPattern.mode === \"root-segment\") {\n const [firstSegment] = normalizedPath.split(\"/\");\n return firstSegment ? matchGlobPath(normalizedPattern.pattern, firstSegment) : false;\n }\n\n if (normalizedPattern.mode === \"root-prefix\") {\n return (\n matchGlobPath(normalizedPattern.pattern, normalizedPath) ||\n matchGlobPath(`${normalizedPattern.pattern}/**`, normalizedPath)\n );\n }\n\n const segments = normalizedPath.split(\"/\");\n return segments.some((segment) => matchGlobPath(normalizedPattern.pattern, segment));\n}\n\nfunction normalizePath(relPath: string): string {\n return relPath.replace(/\\\\/g, \"/\").replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nfunction normalizePattern(pattern: string): {\n pattern: string;\n mode: \"root-path\" | \"root-prefix\" | \"root-segment\" | \"segment\";\n} | null {\n let normalized = pattern.trim();\n if (!normalized) return null;\n\n normalized = normalized.replace(/\\\\/g, \"/\");\n const anchored = normalized.startsWith(\"/\");\n const directoryOnly = normalized.endsWith(\"/\");\n normalized = normalized.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (!normalized) return null;\n\n if (normalized.includes(\"/\")) {\n return {\n pattern: normalized,\n mode: directoryOnly ? \"root-prefix\" : \"root-path\",\n };\n }\n\n if (anchored) {\n return {\n pattern: normalized,\n mode: \"root-segment\",\n };\n }\n\n return {\n pattern: normalized,\n mode: \"segment\",\n };\n}\n\nfunction hasTrackedPathAtOrBelow(relPath: string, trackedPaths: Iterable<string>): boolean {\n const normalizedPath = normalizePath(relPath);\n if (!normalizedPath) return false;\n\n const prefix = normalizedPath + \"/\";\n for (const trackedPath of trackedPaths) {\n const normalizedTrackedPath = normalizePath(trackedPath);\n if (\n normalizedTrackedPath === normalizedPath ||\n normalizedTrackedPath.startsWith(prefix)\n ) {\n return true;\n }\n }\n return false;\n}\n"
5
+ "import { matchGlobPath } from \"./match.cjs\";\nimport type { VCSAttributeRule, VCSResolvedAttributes } from \"./types.cjs\";\n\ninterface VCSRulesConfig {\n internalPath?: string;\n internalDirName?: string;\n ignore?: string[];\n attributes?: VCSAttributeRule[];\n}\n\nexport class VCSRules {\n private readonly internalPath: string;\n private readonly ignorePatterns: string[];\n private readonly attributeRules: VCSAttributeRule[];\n\n constructor(config: VCSRulesConfig = {}) {\n this.internalPath = normalizePath(config.internalPath ?? config.internalDirName ?? \"\");\n this.ignorePatterns = [...(config.ignore ?? [])];\n this.attributeRules = [...(config.attributes ?? [])];\n }\n\n isInternalPath(relPath: string): boolean {\n if (!this.internalPath) return false;\n const normalizedPath = normalizePath(relPath);\n if (!normalizedPath) return false;\n return normalizedPath === this.internalPath || normalizedPath.startsWith(`${this.internalPath}/`);\n }\n\n isIgnored(relPath: string): boolean {\n if (this.isInternalPath(relPath)) return true;\n return this.ignorePatterns.some((pattern) => matchVCSPath(pattern, relPath));\n }\n\n shouldEnterDirectory(relPath: string, trackedPaths: Iterable<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (!this.isIgnored(relPath)) return true;\n return hasTrackedPathAtOrBelow(relPath, trackedPaths);\n }\n\n shouldIncludeWorkingFile(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (trackedPaths.has(relPath)) return true;\n return !this.isIgnored(relPath);\n }\n\n shouldIncludeEmptyDirectory(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (trackedPaths.has(relPath)) return true;\n return !this.isIgnored(relPath);\n }\n\n shouldIncludeRestoreScanFile(relPath: string): boolean {\n return !this.isInternalPath(relPath);\n }\n\n shouldPreserveUntrackedIgnored(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (trackedPaths.has(relPath)) return false;\n return this.isIgnored(relPath);\n }\n\n resolveAttributes(relPath: string): VCSResolvedAttributes {\n let binary: boolean | undefined;\n let diff: VCSResolvedAttributes[\"diff\"];\n\n for (const rule of this.attributeRules) {\n if (!matchVCSPath(rule.pattern, relPath)) continue;\n if (rule.binary !== undefined) {\n binary = rule.binary;\n }\n if (rule.diff !== undefined) {\n diff = rule.diff;\n }\n }\n\n if (diff === \"binary\") {\n binary = true;\n }\n if (diff === \"text\") {\n binary = false;\n }\n\n return { binary, diff };\n }\n}\n\nexport function matchVCSPath(pattern: string, relPath: string): boolean {\n const normalizedPattern = normalizePattern(pattern);\n const normalizedPath = normalizePath(relPath);\n\n if (!normalizedPattern || !normalizedPath) return false;\n\n if (normalizedPattern.mode === \"root-path\") {\n return matchGlobPath(normalizedPattern.pattern, normalizedPath);\n }\n\n if (normalizedPattern.mode === \"root-segment\") {\n const [firstSegment] = normalizedPath.split(\"/\");\n return firstSegment ? matchGlobPath(normalizedPattern.pattern, firstSegment) : false;\n }\n\n if (normalizedPattern.mode === \"root-prefix\") {\n return (\n matchGlobPath(normalizedPattern.pattern, normalizedPath) ||\n matchGlobPath(`${normalizedPattern.pattern}/**`, normalizedPath)\n );\n }\n\n const segments = normalizedPath.split(\"/\");\n return segments.some((segment) => matchGlobPath(normalizedPattern.pattern, segment));\n}\n\nfunction normalizePath(relPath: string): string {\n return relPath.replace(/\\\\/g, \"/\").replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nfunction normalizePattern(pattern: string): {\n pattern: string;\n mode: \"root-path\" | \"root-prefix\" | \"root-segment\" | \"segment\";\n} | null {\n let normalized = pattern.trim();\n if (!normalized) return null;\n\n normalized = normalized.replace(/\\\\/g, \"/\");\n const anchored = normalized.startsWith(\"/\");\n const directoryOnly = normalized.endsWith(\"/\");\n normalized = normalized.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (!normalized) return null;\n\n if (normalized.includes(\"/\")) {\n return {\n pattern: normalized,\n mode: directoryOnly ? \"root-prefix\" : \"root-path\",\n };\n }\n\n if (anchored) {\n return {\n pattern: normalized,\n mode: \"root-segment\",\n };\n }\n\n return {\n pattern: normalized,\n mode: \"segment\",\n };\n}\n\nfunction hasTrackedPathAtOrBelow(relPath: string, trackedPaths: Iterable<string>): boolean {\n const normalizedPath = normalizePath(relPath);\n if (!normalizedPath) return false;\n\n const prefix = normalizedPath + \"/\";\n for (const trackedPath of trackedPaths) {\n const normalizedTrackedPath = normalizePath(trackedPath);\n if (\n normalizedTrackedPath === normalizedPath ||\n normalizedTrackedPath.startsWith(prefix)\n ) {\n return true;\n }\n }\n return false;\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "FD722B600498944364756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "44746568854B06D364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -39,17 +39,20 @@ var __export = (target, all) => {
39
39
  // src/vcs/snapshot.ts
40
40
  var exports_snapshot = {};
41
41
  __export(exports_snapshot, {
42
+ updateIndexForScopedPaths: () => updateIndexForScopedPaths,
42
43
  restoreTree: () => restoreTree,
43
- buildTreeManifest: () => buildTreeManifest,
44
- buildPartialManifest: () => buildPartialManifest
44
+ rebuildIndexForManifest: () => rebuildIndexForManifest,
45
+ buildTreeManifest: () => buildTreeManifest
45
46
  });
46
47
  module.exports = __toCommonJS(exports_snapshot);
48
+ var import_content = require("./content.cjs");
47
49
  var import_rules = require("./rules.cjs");
48
50
  var import_walk = require("./walk.cjs");
49
51
  async function buildTreeManifest(fs, rootPath, options) {
50
52
  const manifest = {};
51
- const rules = options?.rules ?? new import_rules.VCSRules({ internalDirName: ".vcs" });
52
- const trackedPaths = new Set(options?.trackedPaths ?? []);
53
+ const nextIndexEntries = {};
54
+ const rules = options.rules ?? new import_rules.VCSRules({ internalDirName: ".vcs" });
55
+ const trackedPaths = new Set(options.trackedPaths ?? []);
53
56
  const entries = await import_walk.walkTreeEntries(fs, rootPath, {
54
57
  enterDirectory: (relPath) => rules.shouldEnterDirectory(relPath, trackedPaths),
55
58
  includeFile: (relPath) => rules.shouldIncludeWorkingFile(relPath, trackedPaths),
@@ -61,43 +64,37 @@ async function buildTreeManifest(fs, rootPath, options) {
61
64
  continue;
62
65
  }
63
66
  const fullPath = fs.resolve(rootPath, entry.path);
64
- const content = await fs.readFile(fullPath);
65
- const buf = Buffer.from(content);
66
- manifest[entry.path] = {
67
- kind: "file",
68
- content: buf.toString("base64"),
69
- size: buf.length
70
- };
71
- }
72
- return manifest;
73
- }
74
- async function buildPartialManifest(fs, rootPath, paths) {
75
- const manifest = {};
76
- for (const relPath of paths) {
77
- const fullPath = fs.resolve(rootPath, relPath);
78
- if (!await fs.exists(fullPath))
79
- continue;
80
67
  const stat = await fs.stat(fullPath);
81
- if (stat.isDirectory()) {
82
- const entries = await fs.readdir(fullPath);
83
- if (entries.length === 0) {
84
- manifest[relPath] = { kind: "directory", size: 0 };
68
+ const cached = options.indexEntries?.[entry.path];
69
+ if (cached && cached.size === stat.size && cached.mtimeMs === stat.mtimeMs && await options.objectStore.hasBlob(cached.blobId)) {
70
+ const sampleHash = import_content.hashSample(await import_content.readStreamSample(fs.readStream(fullPath)));
71
+ if (sampleHash === cached.sampleHash) {
72
+ manifest[entry.path] = {
73
+ kind: "file",
74
+ blobId: cached.blobId,
75
+ size: cached.size
76
+ };
77
+ nextIndexEntries[entry.path] = cached;
78
+ continue;
85
79
  }
86
- continue;
87
80
  }
88
- if (!stat.isFile())
89
- continue;
90
- const content = await fs.readFile(fullPath);
91
- const buf = Buffer.from(content);
92
- manifest[relPath] = {
81
+ const stored = await options.objectStore.store(fs.readStream(fullPath));
82
+ manifest[entry.path] = {
93
83
  kind: "file",
94
- content: buf.toString("base64"),
95
- size: buf.length
84
+ blobId: stored.blobId,
85
+ size: stored.size
86
+ };
87
+ nextIndexEntries[entry.path] = {
88
+ blobId: stored.blobId,
89
+ size: stored.size,
90
+ mtimeMs: stat.mtimeMs,
91
+ binary: stored.binary,
92
+ sampleHash: stored.sampleHash
96
93
  };
97
94
  }
98
- return manifest;
95
+ return { manifest, indexEntries: nextIndexEntries };
99
96
  }
100
- async function restoreTree(fs, rootPath, manifest, options) {
97
+ async function restoreTree(fs, rootPath, manifest, objectStore, options) {
101
98
  const fullRestore = options?.fullRestore ?? false;
102
99
  const rules = options?.rules ?? new import_rules.VCSRules({ internalDirName: ".vcs" });
103
100
  const trackedPaths = new Set(options?.trackedPaths ?? []);
@@ -132,7 +129,7 @@ async function restoreTree(fs, rootPath, manifest, options) {
132
129
  await ensureDirectoryExists(fs, fs.resolve(rootPath, relPath));
133
130
  continue;
134
131
  }
135
- await writeFileFromEntry(fs, rootPath, relPath, entry);
132
+ await writeFileFromEntry(fs, rootPath, relPath, entry, objectStore);
136
133
  }
137
134
  if (shouldDeleteExtras) {
138
135
  const currentEntries = await import_walk.walkTreeEntries(fs, rootPath, {
@@ -153,12 +150,65 @@ async function restoreTree(fs, rootPath, manifest, options) {
153
150
  }
154
151
  }
155
152
  }
156
- async function writeFileFromEntry(fs, rootPath, relPath, entry) {
153
+ async function rebuildIndexForManifest(fs, rootPath, manifest, objectStore) {
154
+ const entries = {};
155
+ for (const [relPath, entry] of Object.entries(manifest)) {
156
+ if (isDirectoryEntry(entry)) {
157
+ continue;
158
+ }
159
+ const fullPath = fs.resolve(rootPath, relPath);
160
+ const stat = await fs.stat(fullPath);
161
+ entries[relPath] = {
162
+ blobId: entry.blobId,
163
+ size: entry.size,
164
+ mtimeMs: stat.mtimeMs,
165
+ binary: await objectStore.isBinaryBlob(entry.blobId),
166
+ sampleHash: import_content.hashSample(await import_content.readStreamSample(fs.readStream(fullPath)))
167
+ };
168
+ }
169
+ return entries;
170
+ }
171
+ async function updateIndexForScopedPaths(fs, rootPath, manifest, objectStore, existingIndex, patterns) {
172
+ const nextIndex = { ...existingIndex };
173
+ for (const relPath of Object.keys(existingIndex)) {
174
+ if (isPathInScope(relPath, patterns) && !manifest[relPath]) {
175
+ delete nextIndex[relPath];
176
+ }
177
+ }
178
+ for (const [relPath, entry] of Object.entries(manifest)) {
179
+ if (!isPathInScope(relPath, patterns) || isDirectoryEntry(entry)) {
180
+ continue;
181
+ }
182
+ const fullPath = fs.resolve(rootPath, relPath);
183
+ if (!await fs.exists(fullPath)) {
184
+ delete nextIndex[relPath];
185
+ continue;
186
+ }
187
+ const stat = await fs.stat(fullPath);
188
+ nextIndex[relPath] = {
189
+ blobId: entry.blobId,
190
+ size: entry.size,
191
+ mtimeMs: stat.mtimeMs,
192
+ binary: await objectStore.isBinaryBlob(entry.blobId),
193
+ sampleHash: import_content.hashSample(await import_content.readStreamSample(fs.readStream(fullPath)))
194
+ };
195
+ }
196
+ return nextIndex;
197
+ }
198
+ async function writeFileFromEntry(fs, rootPath, relPath, entry, objectStore) {
157
199
  const fullPath = fs.resolve(rootPath, relPath);
158
200
  await ensureDirectoryExists(fs, fs.dirname(fullPath));
159
201
  await removeDirectoryAtPath(fs, fullPath);
160
- const buf = Buffer.from(entry.content, "base64");
161
- await fs.writeFile(fullPath, buf);
202
+ const writer = await fs.writeStream(fullPath);
203
+ try {
204
+ for await (const chunk of objectStore.readBlobStream(entry.blobId)) {
205
+ await writer.write(chunk);
206
+ }
207
+ await writer.close();
208
+ } catch (error) {
209
+ await writer.abort?.(error);
210
+ throw error;
211
+ }
162
212
  }
163
213
  function isDirectoryEntry(entry) {
164
214
  return entry.kind === "directory";
@@ -225,4 +275,4 @@ async function isEmptyDirectory(fs, dirPath) {
225
275
  }
226
276
  }
227
277
 
228
- //# debugId=7E15F1F035E56CC164756E2164756E21
278
+ //# debugId=7BF3A16CF496D89964756E2164756E21