diff --git a/.husky/commit-msg b/.husky/commit-msg deleted file mode 100755 index c08309a..0000000 --- a/.husky/commit-msg +++ /dev/null @@ -1 +0,0 @@ -bunx --no -- commitlint --edit "$1" diff --git a/bun.lock b/bun.lock index 50cc13e..b018547 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "bytebell-public", @@ -111,7 +112,6 @@ "@bb/errors": "workspace:*", "@bb/graph-core": "workspace:*", "@bb/graph-db": "workspace:*", - "@bb/ladybug": "workspace:*", "@bb/llm": "workspace:*", "@bb/logger": "workspace:*", "@bb/mongo": "workspace:*", @@ -131,7 +131,6 @@ "@bb/graph-core": "workspace:*", "@bb/graph-db": "workspace:*", "@bb/ingest-core": "workspace:*", - "@bb/ladybug": "workspace:*", "@bb/llm": "workspace:*", "@bb/logger": "workspace:*", "@bb/mcp": "workspace:*", @@ -168,7 +167,6 @@ "@bb/graph-core": "workspace:*", "@bb/graph-db": "workspace:*", "@bb/types": "workspace:*", - "@ladybugdb/core": "^0.16.1", "parquetjs": "^0.11.2", }, "devDependencies": { @@ -350,9 +348,6 @@ "version": "0.0.0", }, }, - "trustedDependencies": [ - "@ladybugdb/core", - ], "packages": { "@alcalzone/ansi-tokenize": ["@alcalzone/ansi-tokenize@0.3.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-p+CMKJ93HFmLkjXKlXiVGlMQEuRb6H0MokBSwUsX+S6BRX8eV5naFZpQJFfJHjRZY0Hmnqy1/r6UWl3x+19zYA=="], @@ -482,20 +477,6 @@ "@ioredis/commands": ["@ioredis/commands@1.5.1", "", {}, "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw=="], - "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], - - "@ladybugdb/core": ["@ladybugdb/core@0.16.1", "", { "dependencies": { "cmake-js": "^8.0.0", "node-addon-api": "^6.0.0" }, "optionalDependencies": { "@ladybugdb/core-darwin-arm64": "0.16.1", "@ladybugdb/core-darwin-x64": "0.16.1", "@ladybugdb/core-linux-arm64": "0.16.1", "@ladybugdb/core-linux-x64": "0.16.1", "@ladybugdb/core-win32-x64": "0.16.1" } }, "sha512-qwuEcR8CVMKb6tNDaHtq7Ux8hT/XbPC0db+vwutX6JxNAejyx7YomHKPSy9XAKURhYK8mezZe3UN8rf+xpHOjQ=="], - - "@ladybugdb/core-darwin-arm64": ["@ladybugdb/core-darwin-arm64@0.16.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Nl+Cf70rD+HaC9IBHv+oeUwqX9plghXD7PN9tyMzMohRVPvcGEbqWPB6YcdJa8rR7qRqCCbmaNMDen5wg4rY2w=="], - - "@ladybugdb/core-darwin-x64": ["@ladybugdb/core-darwin-x64@0.16.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-4eAjfimAAQRSmDfUUkGrl9OhefxcW1ziA9tl0eljBlGoUseE7dL02+RSqjGohYMcQ+lzuHAq1QWb0XRlMA8YTQ=="], - - "@ladybugdb/core-linux-arm64": ["@ladybugdb/core-linux-arm64@0.16.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-zkctksev+hsPFrNxHHdq4lYK5OWdLhWfRdQzjzkgDyaHayHU6yCL2fgD6uPGQ8TRQ6/2DxMErb4p3FzGW85Ubw=="], - - "@ladybugdb/core-linux-x64": ["@ladybugdb/core-linux-x64@0.16.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5rAb9T5vif8WKhHwhobosu2/aiOwJkWb/ViybvUc5GFKunKl8VI6RmZQVeufT9zUzRktUwrxBrxblCxsnamXJw=="], - - "@ladybugdb/core-win32-x64": ["@ladybugdb/core-win32-x64@0.16.1", "", { "os": "win32", "cpu": "x64" }, "sha512-ShOUTrIuZKQ63J95tcRJxKf1cvg8yi2FSYx9kMTSercc1FdQZPV+zxUN0myMq3MTWOl7xDxsVMmdp/t80O29UQ=="], - "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.9", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-RXSxsokhAF/4nWys8An8npsqOI33Ex1Hlzqjw2pZOO+GKtMAR2noGnUdsFiGwsaO/xXI+56mtjTmDA3JXJsvmA=="], @@ -644,8 +625,6 @@ "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], - "cli-boxes": ["cli-boxes@4.0.1", "", {}, "sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw=="], "cli-cursor": ["cli-cursor@4.0.0", "", { "dependencies": { "restore-cursor": "^4.0.0" } }, "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg=="], @@ -656,8 +635,6 @@ "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], - "cmake-js": ["cmake-js@8.0.0", "", { "dependencies": { "debug": "^4.4.3", "fs-extra": "^11.3.3", "node-api-headers": "^1.8.0", "rc": "1.2.8", "semver": "^7.7.3", "tar": "^7.5.6", "url-join": "^4.0.1", "which": "^6.0.0", "yargs": "^17.7.2" }, "bin": { "cmake-js": "bin/cmake-js" } }, "sha512-YbUP88RDwCvoQkZhRtGURYm9RIpWdtvZuhT87fKNoLjk8kIFIFeARpKfuZQGdwfH99GZpUmqSfcDrK62X7lTgg=="], - "code-excerpt": ["code-excerpt@4.0.0", "", { "dependencies": { "convert-to-spaces": "^2.0.1" } }, "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA=="], "color": ["color@5.0.3", "", { "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" } }, "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA=="], @@ -704,8 +681,6 @@ "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], @@ -810,8 +785,6 @@ "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], - "fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], @@ -832,8 +805,6 @@ "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], - "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], "hasown": ["hasown@2.0.3", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="], @@ -860,7 +831,7 @@ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + "ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], "ink": ["ink@7.0.1", "", { "dependencies": { "@alcalzone/ansi-tokenize": "^0.3.0", "ansi-escapes": "^7.3.0", "ansi-styles": "^6.2.3", "auto-bind": "^5.0.1", "chalk": "^5.6.2", "cli-boxes": "^4.0.1", "cli-cursor": "^4.0.0", "cli-truncate": "^6.0.0", "code-excerpt": "^4.0.0", "es-toolkit": "^1.45.1", "indent-string": "^5.0.0", "is-in-ci": "^2.0.0", "patch-console": "^2.0.0", "react-reconciler": "^0.33.0", "scheduler": "^0.27.0", "signal-exit": "^3.0.7", "slice-ansi": "^9.0.0", "stack-utils": "^2.0.6", "string-width": "^8.2.0", "terminal-size": "^4.0.1", "type-fest": "^5.5.0", "widest-line": "^6.0.0", "wrap-ansi": "^10.0.0", "ws": "^8.20.0", "yoga-layout": "~3.2.1" }, "peerDependencies": { "@types/react": ">=19.2.0", "react": ">=19.2.0", "react-devtools-core": ">=6.1.2" }, "optionalPeers": ["@types/react", "react-devtools-core"] }, "sha512-o6LAC268PLawlGVYrXTyaTfke4VtJftEheuwbgkQf7yvSXyWp1nRwBbAyKEkWXFZZsW/la5wrMuNbuBvZK2C1w=="], @@ -912,8 +883,6 @@ "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], - "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], "kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="], @@ -974,10 +943,6 @@ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - - "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], - "moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="], "mongodb": ["mongodb@7.2.0", "", { "dependencies": { "@mongodb-js/saslprep": "^1.3.0", "bson": "^7.2.0", "mongodb-connection-string-url": "^7.0.0" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.806.0", "@mongodb-js/zstd": "^7.0.0", "gcp-metadata": "^7.0.1", "kerberos": "^7.0.0", "mongodb-client-encryption": ">=7.0.0 <7.1.0", "snappy": "^7.3.2", "socks": "^2.8.6" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw=="], @@ -1002,10 +967,6 @@ "node-abort-controller": ["node-abort-controller@3.1.1", "", {}, "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ=="], - "node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="], - - "node-api-headers": ["node-api-headers@1.8.0", "", {}, "sha512-jfnmiKWjRAGbdD1yQS28bknFM1tbHC1oucyuMPjmkEs+kpiu76aRs40WlTmBmyEgzDM76ge1DQ7XJ3R5deiVjQ=="], - "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], @@ -1072,8 +1033,6 @@ "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], - "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], - "react": ["react@19.2.5", "", {}, "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA=="], "react-reconciler": ["react-reconciler@0.33.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA=="], @@ -1150,14 +1109,10 @@ "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], - "synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="], "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], - "tar": ["tar@7.5.15", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ=="], - "terminal-size": ["terminal-size@4.0.1", "", {}, "sha512-avMLDQpUI9I5XFrklECw1ZEUPJhqzcwSWsyyI8blhRLT+8N1jLJWLWWYQpB2q2xthq8xDvjZPISVh53T/+CLYQ=="], "text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="], @@ -1192,14 +1147,10 @@ "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], - "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - "url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="], - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "varint": ["varint@5.0.2", "", {}, "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow=="], @@ -1230,8 +1181,6 @@ "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], @@ -1262,10 +1211,6 @@ "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "cmake-js/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], - - "global-directory/ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], - "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "ink-text-input/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], @@ -1298,8 +1243,6 @@ "cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "cmake-js/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], - "listr2/cli-truncate/slice-ansi": ["slice-ansi@8.0.0", "", { "dependencies": { "ansi-styles": "^6.2.3", "is-fullwidth-code-point": "^5.1.0" } }, "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg=="], "listr2/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], diff --git a/packages/ingest-core/package.json b/packages/ingest-core/package.json index d1b272b..b74f948 100644 --- a/packages/ingest-core/package.json +++ b/packages/ingest-core/package.json @@ -22,7 +22,6 @@ "@bb/errors": "workspace:*", "@bb/graph-core": "workspace:*", "@bb/graph-db": "workspace:*", - "@bb/ladybug": "workspace:*", "@bb/llm": "workspace:*", "@bb/logger": "workspace:*", "@bb/mongo": "workspace:*", diff --git a/packages/ingest-core/src/pipeline/paths.ts b/packages/ingest-core/src/pipeline/paths.ts index 6c0fa18..7534bb4 100644 --- a/packages/ingest-core/src/pipeline/paths.ts +++ b/packages/ingest-core/src/pipeline/paths.ts @@ -117,6 +117,7 @@ async function repoLocationFor(knowledgeId: string, commitHash?: string): Promis provider: "local", orgId, knowledgeId, + branch: kDoc.info.branch ?? "main", commitHash: commitHash ?? kDoc.source.sourcePath, // best-effort fallback when no commit }; } @@ -142,6 +143,7 @@ async function repoLocationFor(knowledgeId: string, commitHash?: string): Promis knowledgeId, owner: parsed.owner, repo: parsed.repo, + branch: kDoc.info.branch ?? "main", commitHash: effectiveCommit, }; } diff --git a/packages/ingest-github/package.json b/packages/ingest-github/package.json index 6f32de6..3675ab1 100644 --- a/packages/ingest-github/package.json +++ b/packages/ingest-github/package.json @@ -26,7 +26,6 @@ "@bb/mongo": "workspace:*", "@bb/sqlite": "workspace:*", "@bb/neo4j": "workspace:*", - "@bb/ladybug": "workspace:*", "@bb/queue": "workspace:*", "@bb/db-core": "workspace:*", "@bb/graph-core": "workspace:*", diff --git a/packages/ingest-github/src/bootstrap.ts b/packages/ingest-github/src/bootstrap.ts index 639b0e5..375e2d8 100644 --- a/packages/ingest-github/src/bootstrap.ts +++ b/packages/ingest-github/src/bootstrap.ts @@ -21,6 +21,16 @@ import "@bb/neo4j"; export interface BootstrapRuntimeOptions { config: unknown; loggerFactory: LoggerFactory; + /** + * Skip the OSS knowledge/concept-graph index bootstrap (`ensureKnowledgeIndexes` + * / `ensureConceptGraphIndexes`). A composition root sets this when it owns the + * Neo4j graph schema itself — e.g. the enterprise ingestion engine, whose + * `ensureIrGraphSchema()` is the sole (branch-scoped) authority for the `:File` + * / `:FileVersion` / … constraints; the OSS branchless `file_unique` here would + * otherwise reject a second branch's file. Connections are still established. + * Default `false` (OSS standalone keeps creating its own indexes). + */ + skipGraphIndexes?: boolean; } export async function bootstrapRuntime(opts: BootstrapRuntimeOptions): Promise { @@ -35,6 +45,9 @@ export async function bootstrapRuntime(opts: BootstrapRuntimeOptions): Promise { source = factoryResult.source; commitHash = factoryResult.commitHash; archiveSink = factoryResult.archiveSink; - location = { provider: "github", orgId, knowledgeId, owner, repo, commitHash }; + location = { provider: "github", orgId, knowledgeId, owner, repo, branch, commitHash }; // The factory has already produced the source tree; meta-output dirs still // need to exist before the strategy writes scan-manifest.json. Idempotent. await ensureCommitDirs(location); @@ -65,7 +65,7 @@ export const resolveGithubIndexSource: IndexSourceResolver = async (input) => { `could not resolve HEAD commit hash for ${owner}/${repo}@${branch} before clone`, ); } - location = { provider: "github", orgId, knowledgeId, owner, repo, commitHash: resolvedSha }; + location = { provider: "github", orgId, knowledgeId, owner, repo, branch, commitHash: resolvedSha }; await ensureCommitDirs(location); const repoDir = pathsFor(location).repositoryDir; const cloneOpts: { repoUrl: string; branch: string; destinationDir: string; gitToken?: string } = { diff --git a/packages/ingest-github/src/pipeline/pull-source-resolver.ts b/packages/ingest-github/src/pipeline/pull-source-resolver.ts index c9d41fd..acebaa2 100644 --- a/packages/ingest-github/src/pipeline/pull-source-resolver.ts +++ b/packages/ingest-github/src/pipeline/pull-source-resolver.ts @@ -52,6 +52,7 @@ export async function resolvePullSource(input: ResolvePullSourceInput): Promise< knowledgeId, owner, repo, + branch, commitHash: factoryResult.targetCommit, }; logger.info( @@ -99,6 +100,7 @@ export async function resolvePullSource(input: ResolvePullSourceInput): Promise< knowledgeId, owner, repo, + branch, commitHash: resolvedTarget, }; await ensureCommitDirs(location); diff --git a/packages/ingest-github/src/pipeline/run-local.ts b/packages/ingest-github/src/pipeline/run-local.ts index 5b39230..5073626 100644 --- a/packages/ingest-github/src/pipeline/run-local.ts +++ b/packages/ingest-github/src/pipeline/run-local.ts @@ -35,7 +35,9 @@ export async function runLocal( // repository/ dir); only meta-output lives under the kube-v2 tree. const commitHash = `local-${startedAt}`; const orgId = resolveOrgId(payload); - const location: RepoLocation = { provider: "local", orgId, knowledgeId, commitHash }; + // Local sources have no git branch; use a stable synthetic segment so the + // branch-scoped layout slot is populated. + const location: RepoLocation = { provider: "local", orgId, knowledgeId, branch: "main", commitHash }; await ensureCommitDirs(location); const metaPaths = pathsFor(location); diff --git a/packages/ladybug/package.json b/packages/ladybug/package.json index f993e80..e11acdf 100644 --- a/packages/ladybug/package.json +++ b/packages/ladybug/package.json @@ -17,7 +17,6 @@ "@bb/graph-core": "workspace:*", "@bb/graph-db": "workspace:*", "@bb/types": "workspace:*", - "@ladybugdb/core": "^0.16.1", "parquetjs": "^0.11.2" }, "devDependencies": { diff --git a/packages/ladybug/src/client.ts b/packages/ladybug/src/client.ts index 0ffbd77..f035f71 100644 --- a/packages/ladybug/src/client.ts +++ b/packages/ladybug/src/client.ts @@ -1,4 +1,4 @@ -import { Database, Connection, PreparedStatement, type LbugValue } from "@ladybugdb/core"; +import { Database, Connection, PreparedStatement, type LbugValue } from "./coreStub.ts"; import { getConfigValue } from "@bb/config"; import { Config } from "@bb/types"; diff --git a/packages/ladybug/src/coreStub.ts b/packages/ladybug/src/coreStub.ts new file mode 100644 index 0000000..8c73251 --- /dev/null +++ b/packages/ladybug/src/coreStub.ts @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: AGPL-3.0-only WITH non-commercial-clause +// +// Local stand-in for the native `@ladybugdb/core` addon. +// +// The native LadybugDB graph provider is NOT part of the ByteBell deployables +// (admin-server / knowledge-server): those use the Neo4j graph provider plus the +// on-disk JSONL ladybug dumps read by `@bytebell/utils`, and never load this +// native binding. `@ladybugdb/core` ships a large per-platform prebuilt native +// tarball that `bun` cannot extract under QEMU during multi-arch +// `docker buildx` on an Apple-Silicon host — which broke `make ecr-publish` +// ("Fail extracting tarball for @ladybugdb/core-linux-x64"). The external dep +// was therefore removed from `@bb/ladybug`'s manifest. +// +// These stubs preserve exactly the type surface `client.ts` / `provider.ts` +// compile against. Constructing or calling any of them throws — the native +// provider is simply unavailable in this build variant. + +export type LbugValue = unknown; + +const UNAVAILABLE = "LadybugDB native provider (@ladybugdb/core) is not available in this build."; + +export interface QueryResult { + getAll(): Promise; +} + +export class Database { + constructor(_path: string) { + throw new Error(UNAVAILABLE); + } +} + +export class PreparedStatement { + isSuccess(): boolean { + throw new Error(UNAVAILABLE); + } + + getErrorMessage(): string { + throw new Error(UNAVAILABLE); + } +} + +export class Connection { + constructor(_db: Database) { + throw new Error(UNAVAILABLE); + } + + query(_query: string): Promise { + throw new Error(UNAVAILABLE); + } + + prepare(_query: string): Promise { + throw new Error(UNAVAILABLE); + } + + execute(_prepared: PreparedStatement, _params: Record): Promise { + throw new Error(UNAVAILABLE); + } +} diff --git a/packages/ladybug/src/provider.ts b/packages/ladybug/src/provider.ts index afd359e..df72667 100644 --- a/packages/ladybug/src/provider.ts +++ b/packages/ladybug/src/provider.ts @@ -14,7 +14,7 @@ import * as guidepostsRepo from "./guideposts.ts"; import { registerGraphProvider } from "@bb/graph-db"; import type { IGraphDatabaseProvider } from "@bb/graph-core"; -import type { LbugValue } from "@ladybugdb/core"; +import type { LbugValue } from "./coreStub.ts"; class LadybugGraphProvider implements IGraphDatabaseProvider { knowledge = { diff --git a/packages/mcp/src/repoFs.ts b/packages/mcp/src/repoFs.ts index 408ba0f..48b39ec 100644 --- a/packages/mcp/src/repoFs.ts +++ b/packages/mcp/src/repoFs.ts @@ -66,6 +66,9 @@ export async function resolveCloneDir(knowledgeId: string): Promise { knowledgeId, owner: parsed.owner, repo: parsed.repo, + // Read-side resolves the branch the KB was indexed under (info.branch is set + // at index time). Multi-branch read selection is a separate MCP-side effort. + branch: kDoc.info.branch ?? "main", commitHash: commitId, }; return repositoryDirFor(getBytebellHome(), loc); diff --git a/packages/mongo/src/index.ts b/packages/mongo/src/index.ts index 19bb5b0..8ceb14c 100644 --- a/packages/mongo/src/index.ts +++ b/packages/mongo/src/index.ts @@ -8,6 +8,7 @@ export { setKnowledgeCommit, setKnowledgeState, setKnowledgeBranch, + setBranchHead, updateKnowledgeProgress, upsertKnowledge, listKnowledge, diff --git a/packages/mongo/src/knowledge.ts b/packages/mongo/src/knowledge.ts index 89aba56..be73f72 100644 --- a/packages/mongo/src/knowledge.ts +++ b/packages/mongo/src/knowledge.ts @@ -1,4 +1,4 @@ -import type { KnowledgeDoc, KnowledgeState } from "@bb/types"; +import { branchIdFor, type KnowledgeDoc, type KnowledgeState } from "@bb/types"; import { KnowledgeNotFoundError } from "@bb/errors"; import { _getDb } from "./client.ts"; import { Collections } from "./collections.ts"; @@ -89,6 +89,74 @@ export async function setKnowledgeBranch(knowledgeId: string, branch: string): P } } +/** + * Records that `branch` is indexed at `commitHash` on this knowledge, under the + * branch-per-KB model (`source.branches[]`). Upserts the branch element: + * advances its `headCommit`, appends `commitHash` to the branch's own deduped + * `commitHashes` history, and (optionally) sets the branch's processing + * `state`. Seeds `source.defaultBranch` on the first branch recorded. Idempotent + * per (branch, commit). Throws `KnowledgeNotFoundError` if the doc is missing. + * + * Callers: the branch-add trigger (state = PROCESSING at enqueue) and the + * worker on completion (state = PROCESSED + token usage). + */ +export async function setBranchHead( + knowledgeId: string, + branch: string, + commitHash: string, + opts: { state?: KnowledgeState; inputTokens?: string; outputTokens?: string; costUsd?: string } = {}, +): Promise { + const db = _getDb(); + const commitEntry = { + hash: commitHash, + inputTokens: opts.inputTokens ?? "", + outputTokens: opts.outputTokens ?? "", + costUsd: opts.costUsd ?? "0", + }; + + // 1. Create the branch element if it doesn't exist yet (first commit seeds its history). + const inserted = await db.collection(Collections.Knowledge).updateOne( + { knowledgeId, "source.branches.name": { $ne: branch } }, + { + $addToSet: { + "source.branches": { + name: branch, + branchId: branchIdFor(branch), + headCommit: commitHash, + commitHashes: [commitEntry], + ...(opts.state !== undefined ? { state: opts.state } : {}), + }, + }, + $set: { updatedAt: new Date() }, + }, + ); + + // 2. Otherwise advance the existing branch's head + append its commit. + if (inserted.modifiedCount === 0) { + const set: Record = { "source.branches.$.headCommit": commitHash, updatedAt: new Date() }; + if (opts.state !== undefined) { + set["source.branches.$.state"] = opts.state; + } + const updated = await db + .collection(Collections.Knowledge) + .updateOne( + { knowledgeId, "source.branches.name": branch }, + { $set: set, $addToSet: { "source.branches.$.commitHashes": commitEntry } }, + ); + if (updated.matchedCount === 0) { + throw new KnowledgeNotFoundError(knowledgeId); + } + } + + // 3. Seed the default branch on the first branch recorded. + await db + .collection(Collections.Knowledge) + .updateOne( + { knowledgeId, "source.defaultBranch": { $exists: false } }, + { $set: { "source.defaultBranch": branch } }, + ); +} + export async function updateKnowledgeProgress( knowledgeId: string, processedFiles: number, diff --git a/packages/path-migration/src/move.ts b/packages/path-migration/src/move.ts index bbd2ae9..b7ad26e 100644 --- a/packages/path-migration/src/move.ts +++ b/packages/path-migration/src/move.ts @@ -123,7 +123,13 @@ export async function migrateOne(input: MigrateOneInput): Promise { if (doc.source.kind === "local") { const syntheticCommit = `migrated-${doc.updatedAt.getTime()}`; - const newLoc: RepoLocation = { provider: "local", orgId, knowledgeId, commitHash: syntheticCommit }; + const newLoc: RepoLocation = { + provider: "local", + orgId, + knowledgeId, + branch: doc.info.branch ?? "main", + commitHash: syntheticCommit, + }; await moveMetaIfPresent(ctx, legacyMetaRoot, newLoc); return; } @@ -149,6 +155,7 @@ export async function migrateOne(input: MigrateOneInput): Promise { knowledgeId, owner: parsed.owner, repo: parsed.repo, + branch: doc.info.branch ?? "main", commitHash: commitId, }; await moveCloneIfPresent(ctx, legacyCloneDir, newLoc); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 8aacbc4..eba7fe1 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -22,6 +22,7 @@ export type { LocalKnowledgeSource, KnowledgeListEntry, CommitHashRecord, + BranchRecord, TokenUsage, UsageGuard, } from "./knowledge.ts"; @@ -54,6 +55,7 @@ export type { EnrichmentFailure, EnrichmentFailureReason } from "./knowledge.ts" export { IngestionStrategyType } from "./config.ts"; export { orgsRootFor, + branchIdFor, commitBaseDirFor, repositoryDirFor, metaOutputRootFor, diff --git a/packages/types/src/knowledge.ts b/packages/types/src/knowledge.ts index b1d0621..6188cfc 100644 --- a/packages/types/src/knowledge.ts +++ b/packages/types/src/knowledge.ts @@ -31,12 +31,34 @@ export interface CommitHashRecord { costUsd: string; } +/** + * One indexed branch of a knowledge base. Branch support lets a single + * `knowledgeId` hold many branches side by side (see + * `code_history/004-branch-support.md`). `branchId` is `branchIdFor(name)` + * (sha256) — the same value used as the on-disk `` path segment and + * the branch-scoped graph key. `commitHashes` is this branch's own indexed + * commit history (per-branch, deduped, oldest → newest); `headCommit` is its + * current head; `state` is this branch's own processing state (a branch can be + * PROCESSING while a sibling is PROCESSED). + */ +export interface BranchRecord { + name: string; + branchId: string; + headCommit?: string; + state?: KnowledgeState; + commitHashes?: (string | CommitHashRecord)[]; +} + export interface GithubKnowledgeSource { kind: "github"; - /** Current head pointer — the most recently indexed commit. */ + /** Current head pointer — the most recently indexed commit (of the default branch). */ commitId?: string; /** Every commit this knowledge has been indexed at, oldest → newest. Pull appends to this list. */ commitHashes?: (string | CommitHashRecord)[]; + /** The branch treated as "current" for default reads. Seeded on first branch indexed. */ + defaultBranch?: string; + /** Per-branch indexed state. One `knowledgeId` may hold many branches. */ + branches?: BranchRecord[]; } export interface LocalKnowledgeSource { diff --git a/packages/types/src/path-layout.ts b/packages/types/src/path-layout.ts index 7e1973c..2015725 100644 --- a/packages/types/src/path-layout.ts +++ b/packages/types/src/path-layout.ts @@ -1,16 +1,23 @@ +import crypto from "node:crypto"; import path from "node:path"; // ───────────────────────────────────────────────────────────────────────────── // Pure-typed on-disk path resolver shared across packages that need to read // or write knowledge artifacts. No I/O, no FS calls — every helper returns -// strings derived from the inputs. Callers compose with their own -// `getBytebellHome()` (the package boundary that holds the home-dir state). +// strings derived from the inputs (a sha256 of a branch name is such a +// derivation; `node:crypto` is a runtime builtin, not a package dependency). +// Callers compose with their own `getBytebellHome()` (the package boundary +// that holds the home-dir state). // -// Layout (per knowledge + provider + commit): -// `//////repository/` -// `//////meta-output/` +// Layout (per knowledge + provider + branch + commit): +// `///////repository/` +// `///////meta-output/` // For local sources the `/` segments collapse: -// `/local///repository/` +// `/local////repository/` +// +// `` is `branchIdFor(loc.branch)` — a sha256 of the branch name, so +// one repo knowledge can hold many indexed branches side by side, each a +// self-contained subtree (see `branchIdFor` for why it is hashed, not raw). // // `` is the per-tenant base directory: // • OSS standalone: `~/.bytebell/` (single-tenant; no org segment) @@ -32,12 +39,14 @@ export type RepoLocation = knowledgeId: string; owner: string; repo: string; + branch: string; commitHash: string; } | { provider: "local"; orgId: string; knowledgeId: string; + branch: string; commitHash: string; }; @@ -70,11 +79,32 @@ export function orgsRootFor(home: string): string { return path.join(home, "orgs"); } +const BRANCH_BACKSLASH_RE = /\\/gu; + +/** + * Deterministic, filesystem-safe id for a git branch name — the `` + * path segment and the `branchId` key on `:Branch`/`:FileVersion`/other + * branch-scoped graph nodes. A single 64-hex SHA-256 component sidesteps every + * branch-name hazard at once: embedded slashes (`feat/x`), length caps, and + * case-insensitive filesystems (`Feature` vs `feature` hash differently, so no + * collision). The human-readable name is kept on Mongo `knowledge.info.branch` + * and the `:Branch` node, never on disk. Mirrors the hashing of + * `@bb/ingest-core`'s `metaId`; kept here in the kernel so every tier can + * derive a branch id without importing upward (same rationale as the + * duplicated `parseGithubOwnerRepo`). Backslashes normalise to `/` so a name + * hashes identically regardless of platform; nothing else is normalised + * (branch names are case-sensitive). + */ +export function branchIdFor(branch: string): string { + return crypto.createHash("sha256").update(branch.replace(BRANCH_BACKSLASH_RE, "/")).digest("hex"); +} + export function commitBaseDirFor(home: string, loc: RepoLocation): string { + const branchId = branchIdFor(loc.branch); if (loc.provider === "github") { - return path.join(home, "github", loc.knowledgeId, loc.owner, loc.repo, loc.commitHash); + return path.join(home, "github", loc.knowledgeId, loc.owner, loc.repo, branchId, loc.commitHash); } - return path.join(home, "local", loc.knowledgeId, loc.commitHash); + return path.join(home, "local", loc.knowledgeId, branchId, loc.commitHash); } export function repositoryDirFor(home: string, loc: RepoLocation): string {