@git-stunts/git-warp 10.1.1

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 (143) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +16 -0
  3. package/README.md +480 -0
  4. package/SECURITY.md +30 -0
  5. package/bin/git-warp +24 -0
  6. package/bin/warp-graph.js +1574 -0
  7. package/index.d.ts +2366 -0
  8. package/index.js +180 -0
  9. package/package.json +129 -0
  10. package/scripts/install-git-warp.sh +258 -0
  11. package/scripts/uninstall-git-warp.sh +139 -0
  12. package/src/domain/WarpGraph.js +3157 -0
  13. package/src/domain/crdt/Dot.js +160 -0
  14. package/src/domain/crdt/LWW.js +154 -0
  15. package/src/domain/crdt/ORSet.js +371 -0
  16. package/src/domain/crdt/VersionVector.js +222 -0
  17. package/src/domain/entities/GraphNode.js +60 -0
  18. package/src/domain/errors/EmptyMessageError.js +47 -0
  19. package/src/domain/errors/ForkError.js +30 -0
  20. package/src/domain/errors/IndexError.js +23 -0
  21. package/src/domain/errors/OperationAbortedError.js +22 -0
  22. package/src/domain/errors/QueryError.js +39 -0
  23. package/src/domain/errors/SchemaUnsupportedError.js +17 -0
  24. package/src/domain/errors/ShardCorruptionError.js +56 -0
  25. package/src/domain/errors/ShardLoadError.js +57 -0
  26. package/src/domain/errors/ShardValidationError.js +61 -0
  27. package/src/domain/errors/StorageError.js +57 -0
  28. package/src/domain/errors/SyncError.js +30 -0
  29. package/src/domain/errors/TraversalError.js +23 -0
  30. package/src/domain/errors/WarpError.js +31 -0
  31. package/src/domain/errors/WormholeError.js +28 -0
  32. package/src/domain/errors/WriterError.js +39 -0
  33. package/src/domain/errors/index.js +21 -0
  34. package/src/domain/services/AnchorMessageCodec.js +99 -0
  35. package/src/domain/services/BitmapIndexBuilder.js +225 -0
  36. package/src/domain/services/BitmapIndexReader.js +435 -0
  37. package/src/domain/services/BoundaryTransitionRecord.js +463 -0
  38. package/src/domain/services/CheckpointMessageCodec.js +147 -0
  39. package/src/domain/services/CheckpointSerializerV5.js +281 -0
  40. package/src/domain/services/CheckpointService.js +384 -0
  41. package/src/domain/services/CommitDagTraversalService.js +156 -0
  42. package/src/domain/services/DagPathFinding.js +712 -0
  43. package/src/domain/services/DagTopology.js +239 -0
  44. package/src/domain/services/DagTraversal.js +245 -0
  45. package/src/domain/services/Frontier.js +108 -0
  46. package/src/domain/services/GCMetrics.js +101 -0
  47. package/src/domain/services/GCPolicy.js +122 -0
  48. package/src/domain/services/GitLogParser.js +205 -0
  49. package/src/domain/services/HealthCheckService.js +246 -0
  50. package/src/domain/services/HookInstaller.js +326 -0
  51. package/src/domain/services/HttpSyncServer.js +262 -0
  52. package/src/domain/services/IndexRebuildService.js +426 -0
  53. package/src/domain/services/IndexStalenessChecker.js +103 -0
  54. package/src/domain/services/JoinReducer.js +582 -0
  55. package/src/domain/services/KeyCodec.js +113 -0
  56. package/src/domain/services/LegacyAnchorDetector.js +67 -0
  57. package/src/domain/services/LogicalTraversal.js +351 -0
  58. package/src/domain/services/MessageCodecInternal.js +132 -0
  59. package/src/domain/services/MessageSchemaDetector.js +145 -0
  60. package/src/domain/services/MigrationService.js +55 -0
  61. package/src/domain/services/ObserverView.js +265 -0
  62. package/src/domain/services/PatchBuilderV2.js +669 -0
  63. package/src/domain/services/PatchMessageCodec.js +140 -0
  64. package/src/domain/services/ProvenanceIndex.js +337 -0
  65. package/src/domain/services/ProvenancePayload.js +242 -0
  66. package/src/domain/services/QueryBuilder.js +835 -0
  67. package/src/domain/services/StateDiff.js +300 -0
  68. package/src/domain/services/StateSerializerV5.js +156 -0
  69. package/src/domain/services/StreamingBitmapIndexBuilder.js +709 -0
  70. package/src/domain/services/SyncProtocol.js +593 -0
  71. package/src/domain/services/TemporalQuery.js +201 -0
  72. package/src/domain/services/TranslationCost.js +221 -0
  73. package/src/domain/services/TraversalService.js +8 -0
  74. package/src/domain/services/WarpMessageCodec.js +29 -0
  75. package/src/domain/services/WarpStateIndexBuilder.js +127 -0
  76. package/src/domain/services/WormholeService.js +353 -0
  77. package/src/domain/types/TickReceipt.js +285 -0
  78. package/src/domain/types/WarpTypes.js +209 -0
  79. package/src/domain/types/WarpTypesV2.js +200 -0
  80. package/src/domain/utils/CachedValue.js +140 -0
  81. package/src/domain/utils/EventId.js +89 -0
  82. package/src/domain/utils/LRUCache.js +112 -0
  83. package/src/domain/utils/MinHeap.js +114 -0
  84. package/src/domain/utils/RefLayout.js +280 -0
  85. package/src/domain/utils/WriterId.js +205 -0
  86. package/src/domain/utils/cancellation.js +33 -0
  87. package/src/domain/utils/canonicalStringify.js +42 -0
  88. package/src/domain/utils/defaultClock.js +20 -0
  89. package/src/domain/utils/defaultCodec.js +51 -0
  90. package/src/domain/utils/nullLogger.js +21 -0
  91. package/src/domain/utils/roaring.js +181 -0
  92. package/src/domain/utils/shardVersion.js +9 -0
  93. package/src/domain/warp/PatchSession.js +217 -0
  94. package/src/domain/warp/Writer.js +181 -0
  95. package/src/hooks/post-merge.sh +60 -0
  96. package/src/infrastructure/adapters/BunHttpAdapter.js +225 -0
  97. package/src/infrastructure/adapters/ClockAdapter.js +57 -0
  98. package/src/infrastructure/adapters/ConsoleLogger.js +150 -0
  99. package/src/infrastructure/adapters/DenoHttpAdapter.js +230 -0
  100. package/src/infrastructure/adapters/GitGraphAdapter.js +787 -0
  101. package/src/infrastructure/adapters/GlobalClockAdapter.js +5 -0
  102. package/src/infrastructure/adapters/NoOpLogger.js +62 -0
  103. package/src/infrastructure/adapters/NodeCryptoAdapter.js +32 -0
  104. package/src/infrastructure/adapters/NodeHttpAdapter.js +98 -0
  105. package/src/infrastructure/adapters/PerformanceClockAdapter.js +5 -0
  106. package/src/infrastructure/adapters/WebCryptoAdapter.js +121 -0
  107. package/src/infrastructure/codecs/CborCodec.js +384 -0
  108. package/src/ports/BlobPort.js +30 -0
  109. package/src/ports/ClockPort.js +25 -0
  110. package/src/ports/CodecPort.js +25 -0
  111. package/src/ports/CommitPort.js +114 -0
  112. package/src/ports/ConfigPort.js +31 -0
  113. package/src/ports/CryptoPort.js +38 -0
  114. package/src/ports/GraphPersistencePort.js +57 -0
  115. package/src/ports/HttpServerPort.js +25 -0
  116. package/src/ports/IndexStoragePort.js +39 -0
  117. package/src/ports/LoggerPort.js +68 -0
  118. package/src/ports/RefPort.js +51 -0
  119. package/src/ports/TreePort.js +51 -0
  120. package/src/visualization/index.js +26 -0
  121. package/src/visualization/layouts/converters.js +75 -0
  122. package/src/visualization/layouts/elkAdapter.js +86 -0
  123. package/src/visualization/layouts/elkLayout.js +95 -0
  124. package/src/visualization/layouts/index.js +29 -0
  125. package/src/visualization/renderers/ascii/box.js +16 -0
  126. package/src/visualization/renderers/ascii/check.js +271 -0
  127. package/src/visualization/renderers/ascii/colors.js +13 -0
  128. package/src/visualization/renderers/ascii/formatters.js +73 -0
  129. package/src/visualization/renderers/ascii/graph.js +344 -0
  130. package/src/visualization/renderers/ascii/history.js +335 -0
  131. package/src/visualization/renderers/ascii/index.js +14 -0
  132. package/src/visualization/renderers/ascii/info.js +245 -0
  133. package/src/visualization/renderers/ascii/materialize.js +255 -0
  134. package/src/visualization/renderers/ascii/path.js +240 -0
  135. package/src/visualization/renderers/ascii/progress.js +32 -0
  136. package/src/visualization/renderers/ascii/symbols.js +33 -0
  137. package/src/visualization/renderers/ascii/table.js +19 -0
  138. package/src/visualization/renderers/browser/index.js +1 -0
  139. package/src/visualization/renderers/svg/index.js +159 -0
  140. package/src/visualization/utils/ansi.js +14 -0
  141. package/src/visualization/utils/time.js +40 -0
  142. package/src/visualization/utils/truncate.js +40 -0
  143. package/src/visualization/utils/unicode.js +52 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * SVG renderer: generates an SVG string from a PositionedGraph.
3
+ *
4
+ * No jsdom or D3 dependency — pure string templating.
5
+ */
6
+
7
+ const PADDING = 40;
8
+
9
+ const PALETTE = {
10
+ bg: '#1e1e2e',
11
+ nodeFill: '#313244',
12
+ nodeStroke: '#89b4fa',
13
+ nodeText: '#cdd6f4',
14
+ edgeStroke: '#a6adc8',
15
+ edgeLabel: '#bac2de',
16
+ arrowFill: '#a6adc8',
17
+ };
18
+
19
+ function escapeXml(str) {
20
+ return String(str)
21
+ .replace(/&/g, '&')
22
+ .replace(/</g, '&lt;')
23
+ .replace(/>/g, '&gt;')
24
+ .replace(/"/g, '&quot;');
25
+ }
26
+
27
+ function renderDefs() {
28
+ return [
29
+ '<defs>',
30
+ ' <marker id="arrowhead" markerWidth="10" markerHeight="7"',
31
+ ` refX="10" refY="3.5" orient="auto" fill="${PALETTE.arrowFill}">`,
32
+ ' <polygon points="0 0, 10 3.5, 0 7"/>',
33
+ ' </marker>',
34
+ '</defs>',
35
+ ].join('\n');
36
+ }
37
+
38
+ function renderStyle() {
39
+ return [
40
+ '<style>',
41
+ ` .node rect { fill: ${PALETTE.nodeFill}; stroke: ${PALETTE.nodeStroke}; stroke-width: 2; rx: 6; }`,
42
+ ` .node text { fill: ${PALETTE.nodeText}; font-family: monospace; font-size: 13px; dominant-baseline: central; text-anchor: middle; }`,
43
+ ` .edge polyline { fill: none; stroke: ${PALETTE.edgeStroke}; stroke-width: 1.5; marker-end: url(#arrowhead); }`,
44
+ ` .edge-label { fill: ${PALETTE.edgeLabel}; font-family: monospace; font-size: 11px; text-anchor: middle; }`,
45
+ '</style>',
46
+ ].join('\n');
47
+ }
48
+
49
+ function renderNode(node) {
50
+ const { x, y, width, height } = node;
51
+ const label = escapeXml(node.label ?? node.id);
52
+ const cx = x + width / 2;
53
+ const cy = y + height / 2;
54
+ return [
55
+ `<g class="node">`,
56
+ ` <rect x="${x}" y="${y}" width="${width}" height="${height}"/>`,
57
+ ` <text x="${cx}" y="${cy}">${label}</text>`,
58
+ '</g>',
59
+ ].join('\n');
60
+ }
61
+
62
+ function sectionToPoints(section) {
63
+ const pts = [];
64
+ if (section.startPoint) {
65
+ pts.push(section.startPoint);
66
+ }
67
+ if (section.bendPoints) {
68
+ pts.push(...section.bendPoints);
69
+ }
70
+ if (section.endPoint) {
71
+ pts.push(section.endPoint);
72
+ }
73
+ return pts;
74
+ }
75
+
76
+ function renderEdge(edge) {
77
+ const { sections } = edge;
78
+ if (!sections || sections.length === 0) {
79
+ return '';
80
+ }
81
+
82
+ const allPoints = [];
83
+ for (const s of sections) {
84
+ allPoints.push(...sectionToPoints(s));
85
+ }
86
+
87
+ if (allPoints.length < 2) {
88
+ return '';
89
+ }
90
+
91
+ const pointsStr = allPoints
92
+ .map((p) => `${p.x},${p.y}`)
93
+ .join(' ');
94
+
95
+ const lines = [
96
+ '<g class="edge">',
97
+ ` <polyline points="${pointsStr}"/>`,
98
+ ];
99
+
100
+ if (edge.label) {
101
+ const midIdx = Math.floor((allPoints.length - 1) / 2);
102
+ const a = allPoints[midIdx];
103
+ const b = allPoints[Math.min(midIdx + 1, allPoints.length - 1)];
104
+ const midX = (a.x + b.x) / 2;
105
+ const midY = (a.y + b.y) / 2;
106
+ lines.push(
107
+ ` <text class="edge-label" x="${midX}" y="${midY - 6}">${escapeXml(edge.label)}</text>`,
108
+ );
109
+ }
110
+
111
+ lines.push('</g>');
112
+ return lines.join('\n');
113
+ }
114
+
115
+ /**
116
+ * Renders a PositionedGraph as an SVG string.
117
+ *
118
+ * @param {Object} positionedGraph - PositionedGraph from runLayout()
119
+ * @param {{ title?: string }} [options]
120
+ * @returns {string} Complete SVG markup
121
+ */
122
+ export function renderSvg(positionedGraph, options = {}) {
123
+ const { nodes = [], edges = [] } = positionedGraph;
124
+ const w = (positionedGraph.width ?? 400) + PADDING * 2;
125
+ const h = (positionedGraph.height ?? 300) + PADDING * 2;
126
+
127
+ const parts = [
128
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${w} ${h}" width="${w}" height="${h}">`,
129
+ ];
130
+
131
+ if (options.title) {
132
+ parts.push(`<title>${escapeXml(options.title)}</title>`);
133
+ }
134
+
135
+ parts.push(`<rect width="100%" height="100%" fill="${PALETTE.bg}"/>`);
136
+ parts.push(renderDefs());
137
+ parts.push(renderStyle());
138
+
139
+ // Translate content to account for padding
140
+ parts.push(`<g transform="translate(${PADDING},${PADDING})">`);
141
+
142
+ // Edges first (behind nodes)
143
+ for (const edge of edges) {
144
+ const rendered = renderEdge(edge);
145
+ if (rendered) {
146
+ parts.push(rendered);
147
+ }
148
+ }
149
+
150
+ // Nodes on top
151
+ for (const node of nodes) {
152
+ parts.push(renderNode(node));
153
+ }
154
+
155
+ parts.push('</g>');
156
+ parts.push('</svg>');
157
+
158
+ return parts.join('\n');
159
+ }
@@ -0,0 +1,14 @@
1
+ import stripAnsiLib from 'strip-ansi';
2
+
3
+ /**
4
+ * Strips ANSI escape codes from a string.
5
+ * Used primarily for snapshot testing to get deterministic output.
6
+ *
7
+ * @param {string} str - The string potentially containing ANSI escape codes
8
+ * @returns {string} The string with all ANSI codes removed
9
+ */
10
+ export function stripAnsi(str) {
11
+ return stripAnsiLib(str);
12
+ }
13
+
14
+ export default { stripAnsi };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Formats a date as a human-readable relative time string (e.g. "5m ago", "3d ago").
3
+ *
4
+ * @param {string|number|Date} date - The date to format (any value accepted by `new Date()`)
5
+ * @returns {string} Relative time string, or 'unknown' if the date is invalid
6
+ */
7
+ export function timeAgo(date) {
8
+ const ts = new Date(date).getTime();
9
+ if (isNaN(ts)) {
10
+ return 'unknown';
11
+ }
12
+ const seconds = Math.max(0, Math.floor((Date.now() - ts) / 1000));
13
+
14
+ if (seconds < 60) {return `${seconds}s ago`;}
15
+ const minutes = Math.floor(seconds / 60);
16
+ if (minutes < 60) {return `${minutes}m ago`;}
17
+ const hours = Math.floor(minutes / 60);
18
+ if (hours < 24) {return `${hours}h ago`;}
19
+ const days = Math.floor(hours / 24);
20
+ return `${days}d ago`;
21
+ }
22
+
23
+ /**
24
+ * Formats a duration in milliseconds as a human-readable string (e.g. "150ms", "3s", "2m 30s").
25
+ *
26
+ * @param {number} ms - Duration in milliseconds
27
+ * @returns {string} Formatted duration string
28
+ */
29
+ export function formatDuration(ms) {
30
+ if (typeof ms !== 'number' || Number.isNaN(ms) || ms < 0) { return 'unknown'; }
31
+ if (ms < 1000) { return `${ms}ms`; }
32
+ const seconds = Math.floor(ms / 1000);
33
+ if (seconds < 60) { return `${seconds}s`; }
34
+ const minutes = Math.floor(seconds / 60);
35
+ if (minutes < 60) { return `${minutes}m ${seconds % 60}s`; }
36
+ const hours = Math.floor(minutes / 60);
37
+ return `${hours}h ${minutes % 60}m`;
38
+ }
39
+
40
+ export default { timeAgo, formatDuration };
@@ -0,0 +1,40 @@
1
+ import stringWidth from 'string-width';
2
+
3
+ /**
4
+ * Truncates a string to a maximum display width, appending an ellipsis if needed.
5
+ * Handles wide characters (CJK, emoji) correctly via string-width.
6
+ *
7
+ * @param {string} str - The string to truncate
8
+ * @param {number} maxWidth - Maximum display width in columns
9
+ * @param {string} [ellipsis='…'] - The ellipsis character(s) to append when truncating
10
+ * @returns {string} The truncated string, or original if it fits within maxWidth
11
+ */
12
+ export function truncate(str, maxWidth, ellipsis = '…') {
13
+ const ellipsisWidth = stringWidth(ellipsis);
14
+
15
+ // Guard degenerate cases
16
+ if (maxWidth <= 0) {
17
+ return '';
18
+ }
19
+ if (maxWidth <= ellipsisWidth) {
20
+ return ellipsis.slice(0, maxWidth);
21
+ }
22
+
23
+ if (stringWidth(str) <= maxWidth) {
24
+ return str;
25
+ }
26
+
27
+ let result = '';
28
+ let width = 0;
29
+
30
+ for (const char of str) {
31
+ const charWidth = stringWidth(char);
32
+ if (width + charWidth + ellipsisWidth > maxWidth) {break;}
33
+ result += char;
34
+ width += charWidth;
35
+ }
36
+
37
+ return result + ellipsis;
38
+ }
39
+
40
+ export default { truncate };
@@ -0,0 +1,52 @@
1
+ import stringWidth from 'string-width';
2
+
3
+ /**
4
+ * Right-pads a string to a target display width.
5
+ * Handles wide characters correctly via string-width.
6
+ *
7
+ * @param {string} str - The string to pad
8
+ * @param {number} width - Target display width in columns
9
+ * @param {string} [char=' '] - The padding character
10
+ * @returns {string} The padded string, or original if already >= width
11
+ */
12
+ export function padRight(str, width, char = ' ') {
13
+ const currentWidth = stringWidth(str);
14
+ if (currentWidth >= width) {return str;}
15
+ return str + char.repeat(width - currentWidth);
16
+ }
17
+
18
+ /**
19
+ * Left-pads a string to a target display width.
20
+ * Handles wide characters correctly via string-width.
21
+ *
22
+ * @param {string} str - The string to pad
23
+ * @param {number} width - Target display width in columns
24
+ * @param {string} [char=' '] - The padding character
25
+ * @returns {string} The padded string, or original if already >= width
26
+ */
27
+ export function padLeft(str, width, char = ' ') {
28
+ const currentWidth = stringWidth(str);
29
+ if (currentWidth >= width) {return str;}
30
+ return char.repeat(width - currentWidth) + str;
31
+ }
32
+
33
+ /**
34
+ * Centers a string within a target display width.
35
+ * Handles wide characters correctly via string-width.
36
+ * Extra padding goes to the right when the total padding is odd.
37
+ *
38
+ * @param {string} str - The string to center
39
+ * @param {number} width - Target display width in columns
40
+ * @param {string} [char=' '] - The padding character
41
+ * @returns {string} The centered string, or original if already >= width
42
+ */
43
+ export function center(str, width, char = ' ') {
44
+ const currentWidth = stringWidth(str);
45
+ if (currentWidth >= width) {return str;}
46
+ const padding = width - currentWidth;
47
+ const left = Math.floor(padding / 2);
48
+ const right = padding - left;
49
+ return char.repeat(left) + str + char.repeat(right);
50
+ }
51
+
52
+ export default { padRight, padLeft, center, stringWidth };