@rubytech/create-maxy 1.0.773 → 1.0.775
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.
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -0
- package/payload/platform/lib/entitlement/PUBKEY-HASH.txt +1 -0
- package/payload/platform/lib/entitlement/dist/canonicalize.d.ts +26 -0
- package/payload/platform/lib/entitlement/dist/canonicalize.d.ts.map +1 -0
- package/payload/platform/lib/entitlement/dist/canonicalize.js +54 -0
- package/payload/platform/lib/entitlement/dist/canonicalize.js.map +1 -0
- package/payload/platform/lib/entitlement/dist/index.d.ts +76 -0
- package/payload/platform/lib/entitlement/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/entitlement/dist/index.js +293 -0
- package/payload/platform/lib/entitlement/dist/index.js.map +1 -0
- package/payload/platform/lib/entitlement/rubytech-pubkey.pem +3 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +32 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +97 -6
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +10 -5
- package/payload/platform/plugins/memory/mcp/dist/lib/semantic-chunker.d.ts +61 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/semantic-chunker.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/semantic-chunker.js +266 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/semantic-chunker.js.map +1 -0
- package/payload/platform/scripts/generate-entitlement-fixture.mjs +152 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/index.d.ts +2 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/index.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/index.js +293 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/index.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/crypto.d.ts +10 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/crypto.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/crypto.js +88 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/crypto.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/loop-api.d.ts +80 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/loop-api.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/loop-api.js +355 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/loop-api.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/neo4j.js +34 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/customer-preferences.d.ts +10 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/customer-preferences.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/customer-preferences.js +24 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/customer-preferences.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback-list.d.ts +6 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback-list.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback-list.js +18 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback-list.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback.d.ts +16 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback.js +35 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-deregister.d.ts +5 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-deregister.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-deregister.js +19 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-deregister.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-list.d.ts +4 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-list.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-list.js +14 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-list.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-register.d.ts +9 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-register.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-register.js +60 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/key-register.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-enquiry.d.ts +13 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-enquiry.js +41 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-enquiry.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-batch.d.ts +9 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-batch.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-batch.js +16 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-batch.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-request.d.ts +15 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-request.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-request.js +11 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-request.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match.d.ts +10 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match.js +39 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-detail.d.ts +9 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-detail.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-detail.js +125 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-detail.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-list.d.ts +7 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-list.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-list.js +16 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-list.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-search.d.ts +18 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-search.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-search.js +87 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-search.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/properties-list.d.ts +7 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/properties-list.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/properties-list.js +19 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/properties-list.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-detail.d.ts +10 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-detail.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-detail.js +82 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-detail.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-listed.d.ts +12 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-listed.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-listed.js +32 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-listed.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-request.d.ts +15 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-request.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-request.js +11 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-request.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-search.d.ts +16 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-search.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-search.js +41 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-search.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/supplier.d.ts +13 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/supplier.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/supplier.js +49 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/supplier.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-availability.d.ts +7 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-availability.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-availability.js +19 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-availability.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-info.d.ts +5 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-info.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-info.js +32 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-info.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-create.d.ts +14 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-create.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-create.js +11 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-create.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-detail.d.ts +9 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-detail.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-detail.js +85 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-detail.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-search.d.ts +13 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-search.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-search.js +44 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-search.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-update.d.ts +14 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-update.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-update.js +18 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-update.js.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewings-list.d.ts +9 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewings-list.d.ts.map +1 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewings-list.js +25 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewings-list.js.map +1 -0
- package/payload/server/chunk-26QT2HEQ.js +9483 -0
- package/payload/server/chunk-2T4RRIJK.js +9462 -0
- package/payload/server/chunk-2W7O63CK.js +3052 -0
- package/payload/server/chunk-32ZHQJNX.js +11395 -0
- package/payload/server/chunk-3KDVGWPQ.js +2920 -0
- package/payload/server/chunk-3RBKKDHC.js +783 -0
- package/payload/server/chunk-3VVHVJK2.js +11405 -0
- package/payload/server/chunk-43JK6WNK.js +3057 -0
- package/payload/server/chunk-57S5JC7G.js +9563 -0
- package/payload/server/chunk-5YIXIF6C.js +726 -0
- package/payload/server/chunk-7ODDM7L4.js +12370 -0
- package/payload/server/chunk-A5K3CFMI.js +12297 -0
- package/payload/server/chunk-AIWWYOBH.js +9439 -0
- package/payload/server/chunk-B54KBAK4.js +72 -0
- package/payload/server/chunk-BIOIXN5A.js +12165 -0
- package/payload/server/chunk-D53LK5YC.js +12171 -0
- package/payload/server/chunk-EIQT6QDH.js +9562 -0
- package/payload/server/chunk-FM5JMRED.js +12033 -0
- package/payload/server/chunk-HPU24BXP.js +12173 -0
- package/payload/server/chunk-HU5FSQYA.js +12186 -0
- package/payload/server/chunk-IAIGB5WN.js +11406 -0
- package/payload/server/chunk-IO2WQEY4.js +9562 -0
- package/payload/server/chunk-JDT3MGUY.js +12165 -0
- package/payload/server/chunk-JLVVVQN7.js +9447 -0
- package/payload/server/chunk-K7GQ5RMN.js +12172 -0
- package/payload/server/chunk-LQ5GSMEW.js +12036 -0
- package/payload/server/chunk-MIP54X7Q.js +3244 -0
- package/payload/server/chunk-MPWGVFU2.js +12340 -0
- package/payload/server/chunk-O2FWENOD.js +11530 -0
- package/payload/server/chunk-PE76FPYP.js +12040 -0
- package/payload/server/chunk-PQ6LDXZ4.js +2997 -0
- package/payload/server/chunk-Q6NDXCM6.js +11448 -0
- package/payload/server/chunk-QXAUMZXQ.js +9512 -0
- package/payload/server/chunk-S3M2NZMA.js +3136 -0
- package/payload/server/chunk-SGBNY4NP.js +9540 -0
- package/payload/server/chunk-SKXO42T6.js +2934 -0
- package/payload/server/chunk-SPTD7L7Z.js +9474 -0
- package/payload/server/chunk-TKYZ7AEB.js +3142 -0
- package/payload/server/chunk-TM3EQSID.js +9800 -0
- package/payload/server/chunk-TXPEEAV6.js +2997 -0
- package/payload/server/chunk-U3W5YIXU.js +11450 -0
- package/payload/server/chunk-U5JPRUYZ.js +12298 -0
- package/payload/server/chunk-UFLV7I6N.js +11678 -0
- package/payload/server/chunk-ULVR2RRY.js +9439 -0
- package/payload/server/chunk-VOD2IZ6J.js +2934 -0
- package/payload/server/chunk-VS7CRH4M.js +9439 -0
- package/payload/server/chunk-W6ZUNLLS.js +9446 -0
- package/payload/server/chunk-WW464F23.js +9512 -0
- package/payload/server/chunk-XHFMXKXI.js +3179 -0
- package/payload/server/chunk-Y57ACANQ.js +12292 -0
- package/payload/server/chunk-ZK3VNR7Y.js +9510 -0
- package/payload/server/chunk-ZL2A4ROK.js +11416 -0
- package/payload/server/client-pool-4MZN42GG.js +28 -0
- package/payload/server/client-pool-5V5GX3UT.js +28 -0
- package/payload/server/client-pool-67NUIL7H.js +28 -0
- package/payload/server/client-pool-CX2MFW75.js +28 -0
- package/payload/server/client-pool-DQBHSKAF.js +28 -0
- package/payload/server/client-pool-I5TCP7WI.js +28 -0
- package/payload/server/client-pool-ISMYJXCU.js +28 -0
- package/payload/server/client-pool-J4ZHJ6Z3.js +28 -0
- package/payload/server/client-pool-SGPHSYLK.js +28 -0
- package/payload/server/client-pool-TCKGDZLE.js +28 -0
- package/payload/server/client-pool-TULUIO6M.js +28 -0
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/public/assets/{Checkbox-DEE8t2QO.js → Checkbox-C_KxaLc-.js} +1 -1
- package/payload/server/public/assets/{admin-C4CTVtBu.js → admin-xbKPR6ZI.js} +30 -30
- package/payload/server/public/assets/data-D23IzpJ2.js +1 -0
- package/payload/server/public/assets/graph-D2AS9zFS.js +1 -0
- package/payload/server/public/assets/{jsx-runtime-DSbkOE76.css → jsx-runtime-BZtBxBng.css} +1 -1
- package/payload/server/public/assets/{page-YUT5e7hL.js → page-CjTfZ3O6.js} +2 -2
- package/payload/server/public/assets/{page-ZATk95ZG.js → page-DEWgk_nR.js} +1 -1
- package/payload/server/public/assets/{public-BLi3J8KU.js → public-CehiL-qZ.js} +1 -1
- package/payload/server/public/assets/{share-2-DS7Pnkkq.js → share-2-BG1VXt3z.js} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-pEHqS1ib.js → useVoiceRecorder-1Dvb-yHn.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +31 -16
- package/payload/server/upgrade-progress-server.js +83 -0
- package/payload/server/public/assets/data-ryPag-T-.js +0 -1
- package/payload/server/public/assets/graph-BPnH-UZB.js +0 -1
- /package/payload/server/public/assets/{jsx-runtime-DeNudFNA.js → jsx-runtime-DrneHL3t.js} +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export interface TextBlock {
|
|
2
|
+
text: string;
|
|
3
|
+
paragraphs: string[];
|
|
4
|
+
headingLine: string | null;
|
|
5
|
+
}
|
|
6
|
+
export interface ChunkedSection {
|
|
7
|
+
title: string;
|
|
8
|
+
chunks: Array<{
|
|
9
|
+
id: number;
|
|
10
|
+
preview: string;
|
|
11
|
+
content: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
export type EmbedFn = (texts: string[]) => Promise<number[][]>;
|
|
15
|
+
export declare function splitIntoParagraphs(text: string): string[];
|
|
16
|
+
export declare function aggregateBlocks(paragraphs: string[], minBytes?: number): TextBlock[];
|
|
17
|
+
export declare function cosine(a: number[], b: number[]): number;
|
|
18
|
+
/**
|
|
19
|
+
* Compute cosine similarity between each consecutive pair of embeddings.
|
|
20
|
+
* Returns array of length (embeddings.length - 1).
|
|
21
|
+
*/
|
|
22
|
+
export declare function similarityCurve(embeddings: number[][]): number[];
|
|
23
|
+
/**
|
|
24
|
+
* Compute valley depth at each position in the similarity curve.
|
|
25
|
+
*
|
|
26
|
+
* depth(i) = (left_peak - curve[i]) + (right_peak - curve[i])
|
|
27
|
+
* where left_peak and right_peak are the nearest local maxima on each side.
|
|
28
|
+
*
|
|
29
|
+
* Deep valleys indicate strong topic transitions.
|
|
30
|
+
*/
|
|
31
|
+
export declare function valleyDepths(curve: number[]): number[];
|
|
32
|
+
/**
|
|
33
|
+
* Select the top N deepest valleys, sorted by position.
|
|
34
|
+
* Skips positions with zero depth (no valley).
|
|
35
|
+
*/
|
|
36
|
+
export declare function selectBoundaries(depths: number[], n: number): number[];
|
|
37
|
+
/**
|
|
38
|
+
* Snap valley-based boundaries to nearby markdown headings.
|
|
39
|
+
* Boundary values represent the first block index of the new section.
|
|
40
|
+
*/
|
|
41
|
+
export declare function snapToHeadings(boundaries: number[], blocks: TextBlock[], window?: number): number[];
|
|
42
|
+
/**
|
|
43
|
+
* Semantic document chunking using embedding-based topic boundary detection.
|
|
44
|
+
*
|
|
45
|
+
* Replaces heading-regex chunking. Works on plain text, PDF output, and
|
|
46
|
+
* markdown. Headings are used as tiebreakers for boundary placement, not
|
|
47
|
+
* as the primary segmentation signal.
|
|
48
|
+
*
|
|
49
|
+
* @param text - Document text to chunk
|
|
50
|
+
* @param embedFn - Batch embedding function (injected for testability)
|
|
51
|
+
* @returns ChunkedSection[] — same shape as the previous heading-regex chunker
|
|
52
|
+
*/
|
|
53
|
+
export declare function chunkText(text: string, embedFn: EmbedFn): Promise<ChunkedSection[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Build ChunkedSection[] from blocks and section boundary positions.
|
|
56
|
+
* Each boundary is a block index where a new section starts.
|
|
57
|
+
* Within each section, paragraphs are grouped into chunks respecting
|
|
58
|
+
* MIN_CHUNK_SIZE (200) and MAX_CHUNK_SIZE (2000) byte constraints.
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildSections(blocks: TextBlock[], boundaries: number[]): ChunkedSection[];
|
|
61
|
+
//# sourceMappingURL=semantic-chunker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-chunker.d.ts","sourceRoot":"","sources":["../../src/lib/semantic-chunker.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAE/D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ1D;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,QAAQ,SAAiB,GAAG,SAAS,EAAE,CA2B5F;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAevD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,CAMhE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAoBtD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAUtE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAAE,EACpB,MAAM,EAAE,SAAS,EAAE,EACnB,MAAM,SAAsB,GAC3B,MAAM,EAAE,CAgBV;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA+DzF;AAWD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAqDzF"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Semantic document chunking — embedding-based topic boundary detection
|
|
3
|
+
//
|
|
4
|
+
// TEXT --> PARAGRAPHS --> BLOCKS --> EMBED --> SIMILARITY --> VALLEYS --> SECTIONS
|
|
5
|
+
//
|
|
6
|
+
// Replaces heading-regex chunking. Works identically on plain text, PDF
|
|
7
|
+
// output, and markdown. Headings are tiebreakers, not drivers.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const MIN_BLOCK_SIZE = 300;
|
|
10
|
+
const PREVIEW_LENGTH = 150;
|
|
11
|
+
const MIN_CHUNK_SIZE = 200;
|
|
12
|
+
const MAX_CHUNK_SIZE = 2000;
|
|
13
|
+
const MAX_SECTIONS = 25;
|
|
14
|
+
const BYTES_PER_SECTION = 4000;
|
|
15
|
+
const HEADING_SNAP_WINDOW = 2;
|
|
16
|
+
const HEADING_RE = /^(#{1,6})\s+(.+)$/m;
|
|
17
|
+
const SENTENCE_RE = /(?<=[.!?])\s+(?=[A-Z])/;
|
|
18
|
+
export function splitIntoParagraphs(text) {
|
|
19
|
+
const paragraphs = text.split(/\n{2,}/).map((p) => p.trim()).filter(Boolean);
|
|
20
|
+
if (paragraphs.length > 1)
|
|
21
|
+
return paragraphs;
|
|
22
|
+
const sentences = text.split(SENTENCE_RE).map((s) => s.trim()).filter(Boolean);
|
|
23
|
+
if (sentences.length > 1)
|
|
24
|
+
return sentences;
|
|
25
|
+
return paragraphs.length > 0 ? paragraphs : [text.trim()];
|
|
26
|
+
}
|
|
27
|
+
export function aggregateBlocks(paragraphs, minBytes = MIN_BLOCK_SIZE) {
|
|
28
|
+
const blocks = [];
|
|
29
|
+
let currentParagraphs = [];
|
|
30
|
+
let currentText = "";
|
|
31
|
+
function flush() {
|
|
32
|
+
if (!currentText)
|
|
33
|
+
return;
|
|
34
|
+
const headingMatch = currentText.match(HEADING_RE);
|
|
35
|
+
blocks.push({
|
|
36
|
+
text: currentText,
|
|
37
|
+
paragraphs: [...currentParagraphs],
|
|
38
|
+
headingLine: headingMatch ? headingMatch[0] : null,
|
|
39
|
+
});
|
|
40
|
+
currentParagraphs = [];
|
|
41
|
+
currentText = "";
|
|
42
|
+
}
|
|
43
|
+
for (const para of paragraphs) {
|
|
44
|
+
if (currentText && currentText.length >= minBytes) {
|
|
45
|
+
flush();
|
|
46
|
+
}
|
|
47
|
+
currentParagraphs.push(para);
|
|
48
|
+
currentText = currentText ? currentText + "\n\n" + para : para;
|
|
49
|
+
}
|
|
50
|
+
flush();
|
|
51
|
+
return blocks;
|
|
52
|
+
}
|
|
53
|
+
export function cosine(a, b) {
|
|
54
|
+
if (a.length !== b.length) {
|
|
55
|
+
throw new Error(`Vector length mismatch: ${a.length} vs ${b.length}`);
|
|
56
|
+
}
|
|
57
|
+
let dot = 0;
|
|
58
|
+
let magA = 0;
|
|
59
|
+
let magB = 0;
|
|
60
|
+
for (let i = 0; i < a.length; i++) {
|
|
61
|
+
dot += a[i] * b[i];
|
|
62
|
+
magA += a[i] * a[i];
|
|
63
|
+
magB += b[i] * b[i];
|
|
64
|
+
}
|
|
65
|
+
const denom = Math.sqrt(magA) * Math.sqrt(magB);
|
|
66
|
+
if (denom === 0)
|
|
67
|
+
return 0;
|
|
68
|
+
return dot / denom;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Compute cosine similarity between each consecutive pair of embeddings.
|
|
72
|
+
* Returns array of length (embeddings.length - 1).
|
|
73
|
+
*/
|
|
74
|
+
export function similarityCurve(embeddings) {
|
|
75
|
+
const curve = [];
|
|
76
|
+
for (let i = 0; i < embeddings.length - 1; i++) {
|
|
77
|
+
curve.push(cosine(embeddings[i], embeddings[i + 1]));
|
|
78
|
+
}
|
|
79
|
+
return curve;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Compute valley depth at each position in the similarity curve.
|
|
83
|
+
*
|
|
84
|
+
* depth(i) = (left_peak - curve[i]) + (right_peak - curve[i])
|
|
85
|
+
* where left_peak and right_peak are the nearest local maxima on each side.
|
|
86
|
+
*
|
|
87
|
+
* Deep valleys indicate strong topic transitions.
|
|
88
|
+
*/
|
|
89
|
+
export function valleyDepths(curve) {
|
|
90
|
+
const depths = new Array(curve.length).fill(0);
|
|
91
|
+
for (let i = 0; i < curve.length; i++) {
|
|
92
|
+
let leftPeak = curve[i];
|
|
93
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
94
|
+
if (curve[j] > leftPeak)
|
|
95
|
+
leftPeak = curve[j];
|
|
96
|
+
else
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
let rightPeak = curve[i];
|
|
100
|
+
for (let j = i + 1; j < curve.length; j++) {
|
|
101
|
+
if (curve[j] > rightPeak)
|
|
102
|
+
rightPeak = curve[j];
|
|
103
|
+
else
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
depths[i] = (leftPeak - curve[i]) + (rightPeak - curve[i]);
|
|
107
|
+
}
|
|
108
|
+
return depths;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Select the top N deepest valleys, sorted by position.
|
|
112
|
+
* Skips positions with zero depth (no valley).
|
|
113
|
+
*/
|
|
114
|
+
export function selectBoundaries(depths, n) {
|
|
115
|
+
const indexed = depths
|
|
116
|
+
.map((d, i) => ({ depth: d, index: i }))
|
|
117
|
+
.filter((v) => v.depth > 0);
|
|
118
|
+
indexed.sort((a, b) => b.depth - a.depth);
|
|
119
|
+
const selected = indexed.slice(0, n).map((v) => v.index);
|
|
120
|
+
selected.sort((a, b) => a - b);
|
|
121
|
+
return selected;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Snap valley-based boundaries to nearby markdown headings.
|
|
125
|
+
* Boundary values represent the first block index of the new section.
|
|
126
|
+
*/
|
|
127
|
+
export function snapToHeadings(boundaries, blocks, window = HEADING_SNAP_WINDOW) {
|
|
128
|
+
return boundaries.map((pos) => {
|
|
129
|
+
const sectionStart = pos + 1;
|
|
130
|
+
let bestDist = Infinity;
|
|
131
|
+
let bestIdx = sectionStart;
|
|
132
|
+
for (let offset = -window; offset <= window; offset++) {
|
|
133
|
+
const idx = sectionStart + offset;
|
|
134
|
+
if (idx < 1 || idx >= blocks.length)
|
|
135
|
+
continue;
|
|
136
|
+
if (blocks[idx].headingLine && Math.abs(offset) < bestDist) {
|
|
137
|
+
bestDist = Math.abs(offset);
|
|
138
|
+
bestIdx = idx;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return bestIdx;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Semantic document chunking using embedding-based topic boundary detection.
|
|
146
|
+
*
|
|
147
|
+
* Replaces heading-regex chunking. Works on plain text, PDF output, and
|
|
148
|
+
* markdown. Headings are used as tiebreakers for boundary placement, not
|
|
149
|
+
* as the primary segmentation signal.
|
|
150
|
+
*
|
|
151
|
+
* @param text - Document text to chunk
|
|
152
|
+
* @param embedFn - Batch embedding function (injected for testability)
|
|
153
|
+
* @returns ChunkedSection[] — same shape as the previous heading-regex chunker
|
|
154
|
+
*/
|
|
155
|
+
export async function chunkText(text, embedFn) {
|
|
156
|
+
const trimmed = text.trim();
|
|
157
|
+
const t0 = Date.now();
|
|
158
|
+
const log = (stage, detail) => console.error(`[semantic-chunker] ${stage}${detail ? ` — ${detail}` : ""} (${Date.now() - t0}ms)`);
|
|
159
|
+
log("start", `${trimmed.length} chars`);
|
|
160
|
+
// Short-circuit: very short documents don't need embedding
|
|
161
|
+
if (trimmed.length < MIN_BLOCK_SIZE) {
|
|
162
|
+
log("short-circuit", "below MIN_BLOCK_SIZE");
|
|
163
|
+
return [{
|
|
164
|
+
title: deriveTitle(trimmed),
|
|
165
|
+
chunks: [{
|
|
166
|
+
id: 0,
|
|
167
|
+
preview: trimmed.slice(0, PREVIEW_LENGTH),
|
|
168
|
+
content: trimmed,
|
|
169
|
+
}],
|
|
170
|
+
}];
|
|
171
|
+
}
|
|
172
|
+
// 1. Split into paragraphs and aggregate into blocks
|
|
173
|
+
const paragraphs = splitIntoParagraphs(trimmed);
|
|
174
|
+
const blocks = aggregateBlocks(paragraphs);
|
|
175
|
+
log("blocks", `${paragraphs.length} paragraphs → ${blocks.length} blocks`);
|
|
176
|
+
// Short-circuit: too few blocks for boundary detection
|
|
177
|
+
if (blocks.length <= 2) {
|
|
178
|
+
log("short-circuit", "≤2 blocks, skipping embedding");
|
|
179
|
+
return buildSections(blocks, []);
|
|
180
|
+
}
|
|
181
|
+
// 2. Batch embed all blocks
|
|
182
|
+
log("embedding", `${blocks.length} blocks via Ollama`);
|
|
183
|
+
const embeddings = await embedFn(blocks.map((b) => b.text));
|
|
184
|
+
log("embedded", `${embeddings.length} vectors (dim=${embeddings[0]?.length ?? 0})`);
|
|
185
|
+
// 3. Compute similarity curve and valley depths
|
|
186
|
+
const curve = similarityCurve(embeddings);
|
|
187
|
+
const depths = valleyDepths(curve);
|
|
188
|
+
// 4. Select top N boundaries (adaptive with ceiling)
|
|
189
|
+
const targetN = Math.min(Math.ceil(trimmed.length / BYTES_PER_SECTION), MAX_SECTIONS, curve.length);
|
|
190
|
+
const rawBoundaries = selectBoundaries(depths, targetN);
|
|
191
|
+
// 5. Snap to nearby headings
|
|
192
|
+
const snappedBoundaries = snapToHeadings(rawBoundaries, blocks);
|
|
193
|
+
// Deduplicate (snapping can cause two boundaries to land on the same block)
|
|
194
|
+
const uniqueBoundaries = [...new Set(snappedBoundaries)].sort((a, b) => a - b);
|
|
195
|
+
log("boundaries", `${uniqueBoundaries.length} section breaks from ${rawBoundaries.length} candidates`);
|
|
196
|
+
// 6. Build sections with chunks
|
|
197
|
+
const sections = buildSections(blocks, uniqueBoundaries);
|
|
198
|
+
const totalChunks = sections.reduce((n, s) => n + s.chunks.length, 0);
|
|
199
|
+
log("done", `${sections.length} sections, ${totalChunks} chunks`);
|
|
200
|
+
return sections;
|
|
201
|
+
}
|
|
202
|
+
function deriveTitle(text) {
|
|
203
|
+
const headingMatch = text.match(HEADING_RE);
|
|
204
|
+
if (headingMatch)
|
|
205
|
+
return headingMatch[2].trim().slice(0, 80);
|
|
206
|
+
const sentenceEnd = text.search(/[.!?]\s/);
|
|
207
|
+
return sentenceEnd > 0 && sentenceEnd < 80
|
|
208
|
+
? text.slice(0, sentenceEnd + 1)
|
|
209
|
+
: text.slice(0, 80);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Build ChunkedSection[] from blocks and section boundary positions.
|
|
213
|
+
* Each boundary is a block index where a new section starts.
|
|
214
|
+
* Within each section, paragraphs are grouped into chunks respecting
|
|
215
|
+
* MIN_CHUNK_SIZE (200) and MAX_CHUNK_SIZE (2000) byte constraints.
|
|
216
|
+
*/
|
|
217
|
+
export function buildSections(blocks, boundaries) {
|
|
218
|
+
const sections = [];
|
|
219
|
+
let chunkId = 0;
|
|
220
|
+
const starts = [0, ...boundaries];
|
|
221
|
+
const ends = [...boundaries, blocks.length];
|
|
222
|
+
for (let s = 0; s < starts.length; s++) {
|
|
223
|
+
const sectionBlocks = blocks.slice(starts[s], ends[s]);
|
|
224
|
+
if (sectionBlocks.length === 0)
|
|
225
|
+
continue;
|
|
226
|
+
const headingBlock = sectionBlocks.find((b) => b.headingLine);
|
|
227
|
+
const title = headingBlock
|
|
228
|
+
? headingBlock.headingLine.replace(/^#+\s+/, "")
|
|
229
|
+
: deriveTitle(sectionBlocks[0].paragraphs[0] || sectionBlocks[0].text);
|
|
230
|
+
const allParagraphs = sectionBlocks.flatMap((b) => b.paragraphs);
|
|
231
|
+
const chunks = [];
|
|
232
|
+
let buffer = "";
|
|
233
|
+
for (const para of allParagraphs) {
|
|
234
|
+
if (buffer && buffer.length + para.length + 2 > MAX_CHUNK_SIZE) {
|
|
235
|
+
chunks.push({
|
|
236
|
+
id: chunkId++,
|
|
237
|
+
preview: buffer.slice(0, PREVIEW_LENGTH),
|
|
238
|
+
content: buffer,
|
|
239
|
+
});
|
|
240
|
+
buffer = para;
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
buffer = buffer ? buffer + "\n\n" + para : para;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (buffer) {
|
|
247
|
+
if (buffer.length < MIN_CHUNK_SIZE && chunks.length > 0) {
|
|
248
|
+
const prev = chunks[chunks.length - 1];
|
|
249
|
+
prev.content = prev.content + "\n\n" + buffer;
|
|
250
|
+
prev.preview = prev.content.slice(0, PREVIEW_LENGTH);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
chunks.push({
|
|
254
|
+
id: chunkId++,
|
|
255
|
+
preview: buffer.slice(0, PREVIEW_LENGTH),
|
|
256
|
+
content: buffer,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (chunks.length > 0) {
|
|
261
|
+
sections.push({ title, chunks });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return sections;
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=semantic-chunker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-chunker.js","sourceRoot":"","sources":["../../src/lib/semantic-chunker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* One-shot Rubytech-side entitlement fixture generator.
|
|
4
|
+
*
|
|
5
|
+
* RUN BY FOUNDER ONCE; NEVER ON CUSTOMER DEVICES.
|
|
6
|
+
*
|
|
7
|
+
* Produces:
|
|
8
|
+
* - platform/lib/entitlement/rubytech-pubkey.pem (vendored, committed)
|
|
9
|
+
* - platform/lib/entitlement/PUBKEY-HASH.txt (sha256 of pubkey, committed)
|
|
10
|
+
* - .secrets/rubytech-private-key.pem (LOCAL ONLY — never commit)
|
|
11
|
+
* - <out-dir>/entitlement.json (signed payload fixture)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node platform/scripts/generate-entitlement-fixture.mjs init
|
|
15
|
+
* → generates a fresh keypair + writes the pubkey + hash
|
|
16
|
+
*
|
|
17
|
+
* node platform/scripts/generate-entitlement-fixture.mjs sign \
|
|
18
|
+
* --account-id <id> --email <email> --tier <solo|family|pro> \
|
|
19
|
+
* --plugins <comma-list> --days <n> --out <path>
|
|
20
|
+
* → signs a payload using the existing private key
|
|
21
|
+
*
|
|
22
|
+
* The verifier at platform/lib/entitlement/src/index.ts has PUBKEY_SHA256
|
|
23
|
+
* baked into source. After running `init` the script prints the new hash —
|
|
24
|
+
* paste it into the verifier and rebuild.
|
|
25
|
+
*
|
|
26
|
+
* For Task 832 (Rubytech-side issuance endpoint), this script will be
|
|
27
|
+
* replaced by a server-side equivalent. Until then, it stands in.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
generateKeyPairSync,
|
|
32
|
+
createPublicKey,
|
|
33
|
+
createPrivateKey,
|
|
34
|
+
createHash,
|
|
35
|
+
sign as cryptoSign,
|
|
36
|
+
} from "node:crypto";
|
|
37
|
+
import { writeFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
38
|
+
import { resolve, dirname } from "node:path";
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
40
|
+
|
|
41
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
42
|
+
const __dirname = dirname(__filename);
|
|
43
|
+
const PLATFORM_ROOT = resolve(__dirname, "..");
|
|
44
|
+
const REPO_ROOT = resolve(PLATFORM_ROOT, "..");
|
|
45
|
+
const PUBKEY_PATH = resolve(PLATFORM_ROOT, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
46
|
+
const HASH_PATH = resolve(PLATFORM_ROOT, "lib", "entitlement", "PUBKEY-HASH.txt");
|
|
47
|
+
const SECRET_DIR = resolve(REPO_ROOT, ".secrets");
|
|
48
|
+
const PRIVKEY_PATH = resolve(SECRET_DIR, "rubytech-private-key.pem");
|
|
49
|
+
|
|
50
|
+
function canonicalize(value) {
|
|
51
|
+
if (value === null) return "null";
|
|
52
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
53
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
54
|
+
if (typeof value === "number") {
|
|
55
|
+
if (!Number.isFinite(value)) throw new Error("non-finite number");
|
|
56
|
+
if (Object.is(value, -0)) throw new Error("negative zero");
|
|
57
|
+
return JSON.stringify(value);
|
|
58
|
+
}
|
|
59
|
+
if (Array.isArray(value)) return "[" + value.map(canonicalize).join(",") + "]";
|
|
60
|
+
if (typeof value === "object") {
|
|
61
|
+
const keys = Object.keys(value).sort();
|
|
62
|
+
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canonicalize(value[k])).join(",") + "}";
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`unsupported value type ${typeof value}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function init() {
|
|
68
|
+
if (existsSync(PRIVKEY_PATH)) {
|
|
69
|
+
console.error(`ABORT: private key already exists at ${PRIVKEY_PATH}.`);
|
|
70
|
+
console.error("Delete it manually if you really want to regenerate (ALL EXISTING SIGNED PAYLOADS WILL BREAK).");
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
74
|
+
const pubPem = publicKey.export({ type: "spki", format: "pem" });
|
|
75
|
+
const privPem = privateKey.export({ type: "pkcs8", format: "pem" });
|
|
76
|
+
|
|
77
|
+
if (!existsSync(SECRET_DIR)) mkdirSync(SECRET_DIR, { recursive: true });
|
|
78
|
+
writeFileSync(PRIVKEY_PATH, privPem, { mode: 0o600 });
|
|
79
|
+
writeFileSync(PUBKEY_PATH, pubPem, "utf-8");
|
|
80
|
+
|
|
81
|
+
const hash = createHash("sha256").update(pubPem).digest("hex");
|
|
82
|
+
writeFileSync(HASH_PATH, hash + "\n", "utf-8");
|
|
83
|
+
|
|
84
|
+
console.log(`Generated keypair.`);
|
|
85
|
+
console.log(` Public key : ${PUBKEY_PATH}`);
|
|
86
|
+
console.log(` Hash file : ${HASH_PATH} (${hash})`);
|
|
87
|
+
console.log(` Private key : ${PRIVKEY_PATH} (DO NOT COMMIT — verify .gitignore)`);
|
|
88
|
+
console.log("");
|
|
89
|
+
console.log(`NEXT: paste the hash into platform/lib/entitlement/src/index.ts:`);
|
|
90
|
+
console.log(` export const PUBKEY_SHA256 = "${hash}";`);
|
|
91
|
+
console.log(`Then run npm --prefix platform run build:lib`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function parseArgs(argv) {
|
|
95
|
+
const out = {};
|
|
96
|
+
for (let i = 0; i < argv.length; i += 2) {
|
|
97
|
+
const key = argv[i].replace(/^--/, "");
|
|
98
|
+
out[key] = argv[i + 1];
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function sign(args) {
|
|
104
|
+
const required = ["account-id", "email", "tier", "out"];
|
|
105
|
+
for (const k of required) {
|
|
106
|
+
if (!args[k]) {
|
|
107
|
+
console.error(`Missing --${k}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!existsSync(PRIVKEY_PATH)) {
|
|
112
|
+
console.error(`Private key missing at ${PRIVKEY_PATH}. Run 'init' first.`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
const days = Number(args.days ?? "365");
|
|
116
|
+
const plugins = (args.plugins ?? "")
|
|
117
|
+
.split(",")
|
|
118
|
+
.map((s) => s.trim())
|
|
119
|
+
.filter(Boolean);
|
|
120
|
+
|
|
121
|
+
const now = Date.now();
|
|
122
|
+
const issued = new Date(now).toISOString();
|
|
123
|
+
const expires = new Date(now + days * 86400 * 1000).toISOString();
|
|
124
|
+
|
|
125
|
+
const payload = {
|
|
126
|
+
accountId: args["account-id"],
|
|
127
|
+
customerEmail: args.email,
|
|
128
|
+
tier: args.tier,
|
|
129
|
+
purchasedPlugins: plugins,
|
|
130
|
+
issued,
|
|
131
|
+
expires,
|
|
132
|
+
};
|
|
133
|
+
const canonical = canonicalize(payload);
|
|
134
|
+
const privKey = createPrivateKey(readFileSync(PRIVKEY_PATH, "utf-8"));
|
|
135
|
+
const sigBuf = cryptoSign(null, Buffer.from(canonical, "utf-8"), privKey);
|
|
136
|
+
const envelope = { payload, signature: sigBuf.toString("base64") };
|
|
137
|
+
writeFileSync(args.out, JSON.stringify(envelope, null, 2) + "\n", "utf-8");
|
|
138
|
+
console.log(`Signed payload written to ${args.out}`);
|
|
139
|
+
console.log(` tier=${payload.tier} plugins=${plugins.length} expires=${expires}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const cmd = process.argv[2];
|
|
143
|
+
if (cmd === "init") {
|
|
144
|
+
init();
|
|
145
|
+
} else if (cmd === "sign") {
|
|
146
|
+
sign(parseArgs(process.argv.slice(3)));
|
|
147
|
+
} else {
|
|
148
|
+
console.error("Usage:");
|
|
149
|
+
console.error(" generate-entitlement-fixture.mjs init");
|
|
150
|
+
console.error(" generate-entitlement-fixture.mjs sign --account-id <id> --email <e> --tier <t> [--plugins a,b] [--days N] --out <path>");
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|