@memberjunction/db-auto-doc 6.2.0-edge.4 → 6.2.0-edge.5

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 (112) hide show
  1. package/README.md +95 -0
  2. package/dist/commands/analyze.d.ts +1 -0
  3. package/dist/commands/analyze.d.ts.map +1 -1
  4. package/dist/commands/analyze.js +6 -0
  5. package/dist/commands/analyze.js.map +1 -1
  6. package/dist/commands/export.d.ts +28 -19
  7. package/dist/commands/export.d.ts.map +1 -1
  8. package/dist/commands/export.js +91 -12
  9. package/dist/commands/export.js.map +1 -1
  10. package/dist/core/AnalysisEngine.d.ts +15 -6
  11. package/dist/core/AnalysisEngine.d.ts.map +1 -1
  12. package/dist/core/AnalysisEngine.js +41 -40
  13. package/dist/core/AnalysisEngine.js.map +1 -1
  14. package/dist/core/AnalysisOrchestrator.d.ts +20 -1
  15. package/dist/core/AnalysisOrchestrator.d.ts.map +1 -1
  16. package/dist/core/AnalysisOrchestrator.js +131 -27
  17. package/dist/core/AnalysisOrchestrator.js.map +1 -1
  18. package/dist/core/PKProposalGate.d.ts +22 -0
  19. package/dist/core/PKProposalGate.d.ts.map +1 -0
  20. package/dist/core/PKProposalGate.js +52 -0
  21. package/dist/core/PKProposalGate.js.map +1 -0
  22. package/dist/database/Database.d.ts +8 -0
  23. package/dist/database/Database.d.ts.map +1 -1
  24. package/dist/database/Database.js +23 -1
  25. package/dist/database/Database.js.map +1 -1
  26. package/dist/discovery/EnumCandidateGate.d.ts +19 -0
  27. package/dist/discovery/EnumCandidateGate.d.ts.map +1 -1
  28. package/dist/discovery/EnumCandidateGate.js +47 -5
  29. package/dist/discovery/EnumCandidateGate.js.map +1 -1
  30. package/dist/discovery/FKGraphWalker.d.ts +35 -0
  31. package/dist/discovery/FKGraphWalker.d.ts.map +1 -1
  32. package/dist/discovery/FKGraphWalker.js +113 -12
  33. package/dist/discovery/FKGraphWalker.js.map +1 -1
  34. package/dist/discovery/LLMDiscoveryValidator.d.ts +2 -0
  35. package/dist/discovery/LLMDiscoveryValidator.d.ts.map +1 -1
  36. package/dist/discovery/LLMDiscoveryValidator.js +20 -9
  37. package/dist/discovery/LLMDiscoveryValidator.js.map +1 -1
  38. package/dist/discovery/OrganicKeyDetector.d.ts.map +1 -1
  39. package/dist/discovery/OrganicKeyDetector.js +8 -2
  40. package/dist/discovery/OrganicKeyDetector.js.map +1 -1
  41. package/dist/discovery/StructuralPhase.d.ts +27 -5
  42. package/dist/discovery/StructuralPhase.d.ts.map +1 -1
  43. package/dist/discovery/StructuralPhase.js +42 -9
  44. package/dist/discovery/StructuralPhase.js.map +1 -1
  45. package/dist/discovery/TransitiveBridgeDetector.d.ts +5 -1
  46. package/dist/discovery/TransitiveBridgeDetector.d.ts.map +1 -1
  47. package/dist/discovery/TransitiveBridgeDetector.js +25 -3
  48. package/dist/discovery/TransitiveBridgeDetector.js.map +1 -1
  49. package/dist/drivers/BaseAutoDocDriver.d.ts.map +1 -1
  50. package/dist/drivers/BaseAutoDocDriver.js +3 -5
  51. package/dist/drivers/BaseAutoDocDriver.js.map +1 -1
  52. package/dist/drivers/PostgreSQLDriver.d.ts +9 -1
  53. package/dist/drivers/PostgreSQLDriver.d.ts.map +1 -1
  54. package/dist/drivers/PostgreSQLDriver.js +41 -19
  55. package/dist/drivers/PostgreSQLDriver.js.map +1 -1
  56. package/dist/drivers/SQLServerDriver.d.ts.map +1 -1
  57. package/dist/drivers/SQLServerDriver.js +2 -1
  58. package/dist/drivers/SQLServerDriver.js.map +1 -1
  59. package/dist/generators/AdditionalSchemaInfoGenerator.d.ts +34 -0
  60. package/dist/generators/AdditionalSchemaInfoGenerator.d.ts.map +1 -1
  61. package/dist/generators/AdditionalSchemaInfoGenerator.js +85 -4
  62. package/dist/generators/AdditionalSchemaInfoGenerator.js.map +1 -1
  63. package/dist/generators/ErdClusterGenerator.d.ts +44 -0
  64. package/dist/generators/ErdClusterGenerator.d.ts.map +1 -0
  65. package/dist/generators/ErdClusterGenerator.js +216 -0
  66. package/dist/generators/ErdClusterGenerator.js.map +1 -0
  67. package/dist/generators/ErdClusterer.d.ts +130 -0
  68. package/dist/generators/ErdClusterer.d.ts.map +1 -0
  69. package/dist/generators/ErdClusterer.js +308 -0
  70. package/dist/generators/ErdClusterer.js.map +1 -0
  71. package/dist/generators/HTMLGenerator.d.ts +6 -0
  72. package/dist/generators/HTMLGenerator.d.ts.map +1 -1
  73. package/dist/generators/HTMLGenerator.js +41 -6
  74. package/dist/generators/HTMLGenerator.js.map +1 -1
  75. package/dist/generators/MermaidGenerator.d.ts +3 -0
  76. package/dist/generators/MermaidGenerator.d.ts.map +1 -1
  77. package/dist/generators/MermaidGenerator.js +4 -0
  78. package/dist/generators/MermaidGenerator.js.map +1 -1
  79. package/dist/generators/index.d.ts +2 -0
  80. package/dist/generators/index.d.ts.map +1 -1
  81. package/dist/generators/index.js +2 -0
  82. package/dist/generators/index.js.map +1 -1
  83. package/dist/types/analysis.d.ts +2 -0
  84. package/dist/types/analysis.d.ts.map +1 -1
  85. package/dist/types/config.d.ts +46 -0
  86. package/dist/types/config.d.ts.map +1 -1
  87. package/dist/types/config.js +7 -1
  88. package/dist/types/config.js.map +1 -1
  89. package/dist/types/discovery.d.ts +2 -0
  90. package/dist/types/discovery.d.ts.map +1 -1
  91. package/dist/types/state.d.ts +27 -0
  92. package/dist/types/state.d.ts.map +1 -1
  93. package/dist/utils/config-loader.d.ts +5 -0
  94. package/dist/utils/config-loader.d.ts.map +1 -1
  95. package/dist/utils/config-loader.js +37 -0
  96. package/dist/utils/config-loader.js.map +1 -1
  97. package/dist/utils/index-hints.d.ts +36 -0
  98. package/dist/utils/index-hints.d.ts.map +1 -0
  99. package/dist/utils/index-hints.js +65 -0
  100. package/dist/utils/index-hints.js.map +1 -0
  101. package/dist/utils/index.d.ts +1 -0
  102. package/dist/utils/index.d.ts.map +1 -1
  103. package/dist/utils/index.js +1 -0
  104. package/dist/utils/index.js.map +1 -1
  105. package/dist/utils/llm-factory.d.ts +1 -0
  106. package/dist/utils/llm-factory.d.ts.map +1 -1
  107. package/dist/utils/llm-factory.js +6 -1
  108. package/dist/utils/llm-factory.js.map +1 -1
  109. package/package.json +5 -5
  110. package/prompts/fk-pruning-table.md +13 -1
  111. package/prompts/pk-pruning-table.md +10 -0
  112. package/prompts/table-analysis.md +11 -0
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Existing indexes as evidence for the LLM passes.
3
+ *
4
+ * Databases "in the wild" often declare no primary or foreign keys but still have indexes on the
5
+ * columns people join and filter on. A unique index on non-null columns usually marks a primary or
6
+ * alternate key, and a non-unique index led by an ID-like column often marks a foreign key. These
7
+ * helpers turn the indexes stored on a table (`TableDefinition.indexes`) into prompt context.
8
+ */
9
+ import type { AutoDocIndex } from '../types/driver.js';
10
+ import type { TableDefinition } from '../types/state.js';
11
+ /** One existing index, trimmed to what a prompt needs. */
12
+ export interface IndexHint {
13
+ Columns: string[];
14
+ IncludeColumns: string[];
15
+ IsUnique: boolean;
16
+ IsPrimaryKey: boolean;
17
+ /** Partial-index predicate, when the index covers only some rows. */
18
+ Filter?: string;
19
+ }
20
+ /** Most indexes a single table contributes to a prompt. */
21
+ export declare const MAX_INDEX_HINTS_PER_TABLE = 25;
22
+ /**
23
+ * The table's indexes as prompt hints, primary key first, then unique, then the rest, capped at
24
+ * `max`. Returns an empty array when the table has none or they were not loaded.
25
+ */
26
+ export declare function BuildIndexHints(table: Pick<TableDefinition, 'indexes'> | undefined, max?: number): IndexHint[];
27
+ /** One line per hint, e.g. `UNIQUE (Code) INCLUDE (Name) WHERE (Active = 1)`. */
28
+ export declare function FormatIndexHint(hint: IndexHint): string;
29
+ /**
30
+ * True when the column alone is the key of a primary-key or unique, unfiltered index on the table,
31
+ * i.e. the database already guarantees its values are distinct. Undefined when indexes were not loaded.
32
+ */
33
+ export declare function IsUniquelyIndexed(table: Pick<TableDefinition, 'indexes'> | undefined, column: string): boolean | undefined;
34
+ /** Attaches catalog indexes to the matching tables (exact name first, then case-insensitive). */
35
+ export declare function AttachIndexesToTables(tables: TableDefinition[], indexes: AutoDocIndex[]): void;
36
+ //# sourceMappingURL=index-hints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-hints.d.ts","sourceRoot":"","sources":["../../src/utils/index-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,2DAA2D;AAC3D,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,SAAS,EAAE,GAAG,SAA4B,GAAG,SAAS,EAAE,CAYjI;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAKvD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAQ1H;AAED,iGAAiG;AACjG,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,CAc9F"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Existing indexes as evidence for the LLM passes.
3
+ *
4
+ * Databases "in the wild" often declare no primary or foreign keys but still have indexes on the
5
+ * columns people join and filter on. A unique index on non-null columns usually marks a primary or
6
+ * alternate key, and a non-unique index led by an ID-like column often marks a foreign key. These
7
+ * helpers turn the indexes stored on a table (`TableDefinition.indexes`) into prompt context.
8
+ */
9
+ /** Most indexes a single table contributes to a prompt. */
10
+ export const MAX_INDEX_HINTS_PER_TABLE = 25;
11
+ /**
12
+ * The table's indexes as prompt hints, primary key first, then unique, then the rest, capped at
13
+ * `max`. Returns an empty array when the table has none or they were not loaded.
14
+ */
15
+ export function BuildIndexHints(table, max = MAX_INDEX_HINTS_PER_TABLE) {
16
+ const indexes = table?.indexes ?? [];
17
+ return [...indexes]
18
+ .sort((a, b) => hintRank(a) - hintRank(b))
19
+ .slice(0, max)
20
+ .map((ix) => ({
21
+ Columns: ix.Columns,
22
+ IncludeColumns: ix.IncludeColumns,
23
+ IsUnique: ix.IsUnique || ix.IsPrimaryKey,
24
+ IsPrimaryKey: ix.IsPrimaryKey,
25
+ Filter: ix.FilterDefinition || undefined
26
+ }));
27
+ }
28
+ /** One line per hint, e.g. `UNIQUE (Code) INCLUDE (Name) WHERE (Active = 1)`. */
29
+ export function FormatIndexHint(hint) {
30
+ const kind = hint.IsPrimaryKey ? 'PRIMARY KEY' : hint.IsUnique ? 'UNIQUE' : 'INDEX';
31
+ const include = hint.IncludeColumns.length ? ` INCLUDE (${hint.IncludeColumns.join(', ')})` : '';
32
+ const filter = hint.Filter ? ` WHERE ${hint.Filter}` : '';
33
+ return `${kind} (${hint.Columns.join(', ')})${include}${filter}`;
34
+ }
35
+ /**
36
+ * True when the column alone is the key of a primary-key or unique, unfiltered index on the table,
37
+ * i.e. the database already guarantees its values are distinct. Undefined when indexes were not loaded.
38
+ */
39
+ export function IsUniquelyIndexed(table, column) {
40
+ if (!table?.indexes) {
41
+ return undefined;
42
+ }
43
+ const target = column.toLowerCase();
44
+ return table.indexes.some((ix) => (ix.IsUnique || ix.IsPrimaryKey) && !ix.FilterDefinition && ix.Columns.length === 1 && ix.Columns[0].toLowerCase() === target);
45
+ }
46
+ /** Attaches catalog indexes to the matching tables (exact name first, then case-insensitive). */
47
+ export function AttachIndexesToTables(tables, indexes) {
48
+ const exact = new Map();
49
+ for (const ix of indexes) {
50
+ const list = exact.get(ix.TableName) ?? [];
51
+ list.push(ix);
52
+ exact.set(ix.TableName, list);
53
+ }
54
+ const folded = new Map();
55
+ for (const [name, list] of exact) {
56
+ folded.set(name.toLowerCase(), [...(folded.get(name.toLowerCase()) ?? []), ...list]);
57
+ }
58
+ for (const table of tables) {
59
+ table.indexes = exact.get(table.name) ?? folded.get(table.name.toLowerCase()) ?? [];
60
+ }
61
+ }
62
+ function hintRank(ix) {
63
+ return ix.IsPrimaryKey ? 0 : ix.IsUnique ? 1 : 2;
64
+ }
65
+ //# sourceMappingURL=index-hints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-hints.js","sourceRoot":"","sources":["../../src/utils/index-hints.ts"],"names":[],"mappings":"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"}
@@ -2,4 +2,5 @@
2
2
  * Exports for utils module
3
3
  */
4
4
  export { ConfigLoader } from './config-loader.js';
5
+ export * from './index-hints.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,cAAc,kBAAkB,CAAC"}
@@ -2,4 +2,5 @@
2
2
  * Exports for utils module
3
3
  */
4
4
  export { ConfigLoader } from './config-loader.js';
5
+ export * from './index-hints.js';
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,cAAc,kBAAkB,CAAC"}
@@ -5,6 +5,7 @@
5
5
  * across PromptEngine and LLMSanityChecker.
6
6
  */
7
7
  import { BaseLLM } from '@memberjunction/ai';
8
+ import '@memberjunction/server-bootstrap-lite/mj-class-registrations';
8
9
  /**
9
10
  * Create an LLM instance from a provider name
10
11
  *
@@ -1 +1 @@
1
- {"version":3,"file":"llm-factory.d.ts","sourceRoot":"","sources":["../../src/utils/llm-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAoB7C;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAuB3E;AAED,iDAAiD;AACjD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED,kDAAkD;AAClD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,qDAAqD;AACrD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD"}
1
+ {"version":3,"file":"llm-factory.d.ts","sourceRoot":"","sources":["../../src/utils/llm-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI7C,OAAO,8DAA8D,CAAC;AAmBtE;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAyB3E;AAED,iDAAiD;AACjD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED,kDAAkD;AAClD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,qDAAqD;AACrD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD"}
@@ -6,6 +6,9 @@
6
6
  */
7
7
  import { BaseLLM } from '@memberjunction/ai';
8
8
  import { MJGlobal } from '@memberjunction/global';
9
+ // The LLM drivers register with MJGlobal.ClassFactory as a side effect of this manifest; without it a
10
+ // standalone CLI process has no provider classes to instantiate.
11
+ import '@memberjunction/server-bootstrap-lite/mj-class-registrations';
9
12
  /**
10
13
  * Provider name to LLM driver class name mapping
11
14
  */
@@ -37,7 +40,9 @@ export function CreateLLMInstance(provider, apiKey) {
37
40
  throw new Error(`Unknown provider: ${provider}. Supported providers: ${supportedProviders}`);
38
41
  }
39
42
  const llm = MJGlobal.Instance.ClassFactory.CreateInstance(BaseLLM, driverClass, apiKey);
40
- if (!llm) {
43
+ // The ClassFactory falls back to the base class when nothing is registered under the key, and a bare
44
+ // BaseLLM fails on every call, so treat that as "not installed" too.
45
+ if (!llm || Object.getPrototypeOf(llm) === BaseLLM.prototype) {
41
46
  throw new Error(`Failed to create LLM instance for provider: ${provider} (driver class: ${driverClass}). Check that the provider is installed.`);
42
47
  }
43
48
  return llm;
@@ -1 +1 @@
1
- {"version":3,"file":"llm-factory.js","sourceRoot":"","sources":["../../src/utils/llm-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD;;GAEG;AACH,MAAM,wBAAwB,GAA2B;IACvD,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,cAAc;IAC3B,MAAM,EAAE,SAAS;IACjB,SAAS,EAAE,YAAY;IACvB,QAAQ,EAAE,WAAW;IACrB,OAAO,EAAE,UAAU;IACnB,UAAU,EAAE,aAAa;IACzB,YAAY,EAAE,eAAe;IAC7B,KAAK,EAAE,QAAQ;IACf,SAAS,EAAE,YAAY;CACxB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IAChE,MAAM,WAAW,GAAG,wBAAwB,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAErE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,kBAAkB,GAAG,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5E,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,0BAA0B,kBAAkB,EAAE,CAC5E,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,cAAc,CACvD,OAAO,EACP,WAAW,EACX,MAAM,CACP,CAAC;IAEF,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,+CAA+C,QAAQ,mBAAmB,WAAW,0CAA0C,CAChI,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IAChE,OAAO,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,wBAAwB,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AAC/C,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,qBAAqB;IACnC,OAAO,qBAAqB,EAAE,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"llm-factory.js","sourceRoot":"","sources":["../../src/utils/llm-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,sGAAsG;AACtG,iEAAiE;AACjE,OAAO,8DAA8D,CAAC;AAEtE;;GAEG;AACH,MAAM,wBAAwB,GAA2B;IACvD,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,cAAc;IAC3B,MAAM,EAAE,SAAS;IACjB,SAAS,EAAE,YAAY;IACvB,QAAQ,EAAE,WAAW;IACrB,OAAO,EAAE,UAAU;IACnB,UAAU,EAAE,aAAa;IACzB,YAAY,EAAE,eAAe;IAC7B,KAAK,EAAE,QAAQ;IACf,SAAS,EAAE,YAAY;CACxB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IAChE,MAAM,WAAW,GAAG,wBAAwB,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAErE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,kBAAkB,GAAG,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5E,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,0BAA0B,kBAAkB,EAAE,CAC5E,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,cAAc,CACvD,OAAO,EACP,WAAW,EACX,MAAM,CACP,CAAC;IAEF,qGAAqG;IACrG,qEAAqE;IACrE,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CACb,+CAA+C,QAAQ,mBAAmB,WAAW,0CAA0C,CAChI,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IAChE,OAAO,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,wBAAwB,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AAC/C,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,qBAAqB;IACnC,OAAO,qBAAqB,EAAE,CAAC;AACjC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@memberjunction/db-auto-doc",
3
3
  "type": "module",
4
- "version": "6.2.0-edge.4",
4
+ "version": "6.2.0-edge.5",
5
5
  "description": "AI-powered database documentation generator for SQL Server, MySQL, and PostgreSQL. Analyzes your database structure, uses AI to generate comprehensive descriptions, and saves them as metadata. Works standalone - no MemberJunction runtime required.",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -64,10 +64,10 @@
64
64
  },
65
65
  "dependencies": {
66
66
  "@inquirer/prompts": "^8.2.0",
67
- "@memberjunction/ai": "6.2.0-edge.4",
68
- "@memberjunction/server-bootstrap-lite": "6.2.0-edge.4",
69
- "@memberjunction/core": "6.2.0-edge.4",
70
- "@memberjunction/global": "6.2.0-edge.4",
67
+ "@memberjunction/ai": "6.2.0-edge.5",
68
+ "@memberjunction/server-bootstrap-lite": "6.2.0-edge.5",
69
+ "@memberjunction/core": "6.2.0-edge.5",
70
+ "@memberjunction/global": "6.2.0-edge.5",
71
71
  "@oclif/core": "^3.27.0",
72
72
  "@oclif/plugin-help": "^6.2.37",
73
73
  "chalk": "^5.6.2",
@@ -14,9 +14,21 @@ These FKs were identified by statistical analysis and/or LLM analysis. Some are
14
14
  **NOTE**: FKs marked as **[LOCKED]** have very high confidence and CANNOT be removed. Only evaluate the unlocked ones.
15
15
 
16
16
  {% for fk in candidates %}
17
- {{ loop.index }}. {% if fk.locked %}**[LOCKED]** {% endif %}**{{ fk.sourceColumn }}** → {{ fk.targetSchema }}.{{ fk.targetTable }}.{{ fk.targetColumn }} (confidence: {{ fk.confidence }}%)
17
+ {{ loop.index }}. {% if fk.locked %}**[LOCKED]** {% endif %}**{{ fk.sourceColumn }}** → {{ fk.targetSchema }}.{{ fk.targetTable }}.{{ fk.targetColumn }} (confidence: {{ fk.confidence }}%{% if fk.targetUniquelyIndexed === true %}; target column has a unique index{% elif fk.targetUniquelyIndexed === false %}; target column has no unique index{% endif %})
18
18
  {% endfor %}
19
19
 
20
+ {% if existingIndexes and existingIndexes.length > 0 %}
21
+ ## Existing Indexes
22
+ These indexes exist on this table in the database. Developers index the columns they join and filter on, so indexes are clues to keys even when none are declared:
23
+ {% for ix in existingIndexes %}
24
+ - {{ ix }}
25
+ {% endfor %}
26
+
27
+ *A UNIQUE index or PRIMARY KEY on non-null columns is strong evidence of the primary key (or an alternate key). A non-unique index led by an ID- or code-like column often marks a foreign key. Indexes are evidence, not proof — weigh them with names, statistics and value overlap. "(expression)" is a computed key part.*
28
+ {% endif %}
29
+
30
+ *A real FK target is normally unique. A target column with a unique index or primary key supports the FK; one without is weaker evidence (but the database may simply not declare it).*
31
+
20
32
  ## What to look for when proposing removals:
21
33
 
22
34
  1. **Reverse direction**: FK goes from parent→child instead of child→parent. Example: `Department.DepartmentID → EmployeeDepartmentHistory.DepartmentID` is backwards — the history table should reference Department, not the other way around.
@@ -8,6 +8,16 @@ You are evaluating primary key candidates for a database table.
8
8
  {{ loop.index }}. Columns: {{ pk.columns | join(", ") }} (confidence: {{ pk.confidence }}%{% if pk.locked %}, LOCKED - do not modify{% endif %})
9
9
  {% endfor %}
10
10
 
11
+ {% if existingIndexes and existingIndexes.length > 0 %}
12
+ ## Existing Indexes
13
+ These indexes exist on this table in the database. Developers index the columns they join and filter on, so indexes are clues to keys even when no primary or foreign key is declared:
14
+ {% for ix in existingIndexes %}
15
+ - {{ ix }}
16
+ {% endfor %}
17
+
18
+ *A UNIQUE index or PRIMARY KEY on non-null columns is strong evidence of the primary key (or an alternate key). A non-unique index led by an ID- or code-like column often marks a foreign key. Indexes are evidence, not proof — weigh them with names, statistics and value overlap. "(expression)" is a computed key part.*
19
+ {% endif %}
20
+
11
21
  ## All Database Tables (for context):
12
22
  {% for tbl in allTables %}
13
23
  - {{ tbl.schema }}.{{ tbl.name }}{% if tbl.pk %} (PK: {{ tbl.pk }}){% endif %}
@@ -96,6 +96,16 @@ The following columns in this table were identified as potential foreign keys by
96
96
  *Value overlap = % of source values that exist in the target column. 100% = strong FK evidence. Cardinality ratio = source distinct / target distinct — values > 1 suggest child→parent direction.*
97
97
  {% endif %}
98
98
 
99
+ {% if existingIndexes and existingIndexes.length > 0 %}
100
+ ## Existing Indexes
101
+ These indexes exist on this table in the database. Developers index the columns they join and filter on, so indexes are clues to keys even when no primary or foreign key is declared:
102
+ {% for ix in existingIndexes %}
103
+ - {{ ix }}
104
+ {% endfor %}
105
+
106
+ *A UNIQUE index or PRIMARY KEY on non-null columns is strong evidence of the primary key (or an alternate key). A non-unique index led by an ID- or code-like column often marks a foreign key. Indexes are evidence, not proof — weigh them with names, statistics and value overlap. "(expression)" is a computed key part.*
107
+ {% endif %}
108
+
99
109
  {% if allTables %}
100
110
  ## All Database Tables
101
111
  **IMPORTANT**: When referring to foreign key relationships, you MUST use one of these exact table names:
@@ -168,6 +178,7 @@ Based on the evidence above, generate a JSON response with this exact structure:
168
178
  - Use `"columns": ["Col1", "Col2"]` for composite keys
169
179
  - Confidence should reflect how certain you are (0-1 scale)
170
180
  - If a PK is already marked in the column list above, you may confirm it or propose a different one
181
+ - A UNIQUE index on non-null column(s) under "Existing Indexes" is strong evidence for those columns as the key
171
182
  6. **Foreign Keys**: **CRITICAL** - Use structured format for ALL foreign key relationships:
172
183
  - Include EVERY column that references another table
173
184
  - Use EXACT schema and table names from the "All Database Tables" list above