@x12i/memorix-service 3.7.1 → 3.7.7

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 (169) hide show
  1. package/dist/activity-ring.d.ts +185 -0
  2. package/dist/activity-ring.d.ts.map +1 -0
  3. package/dist/activity-ring.js +249 -0
  4. package/dist/activity-ring.js.map +1 -0
  5. package/dist/activity-routes.d.ts +3 -0
  6. package/dist/activity-routes.d.ts.map +1 -0
  7. package/dist/activity-routes.js +47 -0
  8. package/dist/activity-routes.js.map +1 -0
  9. package/dist/activity-ui.d.ts +3 -0
  10. package/dist/activity-ui.d.ts.map +1 -0
  11. package/dist/activity-ui.js +1105 -0
  12. package/dist/activity-ui.js.map +1 -0
  13. package/dist/app.d.ts.map +1 -1
  14. package/dist/app.js +21 -2
  15. package/dist/app.js.map +1 -1
  16. package/dist/caller-identity.d.ts +3 -2
  17. package/dist/caller-identity.d.ts.map +1 -1
  18. package/dist/caller-identity.js.map +1 -1
  19. package/dist/catalog-bridge.d.ts.map +1 -1
  20. package/dist/catalog-bridge.js +7 -1
  21. package/dist/catalog-bridge.js.map +1 -1
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +12 -0
  24. package/dist/cli.js.map +1 -1
  25. package/dist/connector-catalog.d.ts +1 -1
  26. package/dist/connector-ops/attempt-store.d.ts.map +1 -1
  27. package/dist/connector-ops/attempt-store.js +1 -3
  28. package/dist/connector-ops/attempt-store.js.map +1 -1
  29. package/dist/connector-ops/checkpoint-store.d.ts.map +1 -1
  30. package/dist/connector-ops/checkpoint-store.js +1 -3
  31. package/dist/connector-ops/checkpoint-store.js.map +1 -1
  32. package/dist/connector-ops/override-store.d.ts.map +1 -1
  33. package/dist/connector-ops/override-store.js +1 -3
  34. package/dist/connector-ops/override-store.js.map +1 -1
  35. package/dist/connector-ops/run-store.d.ts.map +1 -1
  36. package/dist/connector-ops/run-store.js +1 -3
  37. package/dist/connector-ops/run-store.js.map +1 -1
  38. package/dist/connector-ops/schedule-lease-store.d.ts.map +1 -1
  39. package/dist/connector-ops/schedule-lease-store.js +1 -3
  40. package/dist/connector-ops/schedule-lease-store.js.map +1 -1
  41. package/dist/data-changes-routes.d.ts +7 -0
  42. package/dist/data-changes-routes.d.ts.map +1 -0
  43. package/dist/data-changes-routes.js +27 -0
  44. package/dist/data-changes-routes.js.map +1 -0
  45. package/dist/data-changes-ui.d.ts +3 -0
  46. package/dist/data-changes-ui.d.ts.map +1 -0
  47. package/dist/data-changes-ui.js +239 -0
  48. package/dist/data-changes-ui.js.map +1 -0
  49. package/dist/data-changes.d.ts +51 -0
  50. package/dist/data-changes.d.ts.map +1 -0
  51. package/dist/data-changes.js +218 -0
  52. package/dist/data-changes.js.map +1 -0
  53. package/dist/errors.d.ts +3 -0
  54. package/dist/errors.d.ts.map +1 -1
  55. package/dist/errors.js +36 -3
  56. package/dist/errors.js.map +1 -1
  57. package/dist/graph-ui.d.ts +3 -0
  58. package/dist/graph-ui.d.ts.map +1 -0
  59. package/dist/graph-ui.js +676 -0
  60. package/dist/graph-ui.js.map +1 -0
  61. package/dist/identity-alias.d.ts +12 -0
  62. package/dist/identity-alias.d.ts.map +1 -0
  63. package/dist/identity-alias.js +22 -0
  64. package/dist/identity-alias.js.map +1 -0
  65. package/dist/incremental-state/state-store.d.ts.map +1 -1
  66. package/dist/incremental-state/state-store.js +1 -3
  67. package/dist/incremental-state/state-store.js.map +1 -1
  68. package/dist/integrations/instance-store.d.ts.map +1 -1
  69. package/dist/integrations/instance-store.js +1 -3
  70. package/dist/integrations/instance-store.js.map +1 -1
  71. package/dist/isolation.d.ts.map +1 -1
  72. package/dist/isolation.js +3 -2
  73. package/dist/isolation.js.map +1 -1
  74. package/dist/knowledge-upstream.d.ts +13 -0
  75. package/dist/knowledge-upstream.d.ts.map +1 -0
  76. package/dist/knowledge-upstream.js +38 -0
  77. package/dist/knowledge-upstream.js.map +1 -0
  78. package/dist/land-v2-guards.d.ts +22 -0
  79. package/dist/land-v2-guards.d.ts.map +1 -0
  80. package/dist/land-v2-guards.js +57 -0
  81. package/dist/land-v2-guards.js.map +1 -0
  82. package/dist/live-ops-nav.d.ts +2 -0
  83. package/dist/live-ops-nav.d.ts.map +1 -0
  84. package/dist/live-ops-nav.js +53 -0
  85. package/dist/live-ops-nav.js.map +1 -0
  86. package/dist/live.d.ts.map +1 -1
  87. package/dist/mcp/nexum-tools.d.ts +28 -0
  88. package/dist/mcp/nexum-tools.d.ts.map +1 -0
  89. package/dist/mcp/nexum-tools.js +257 -0
  90. package/dist/mcp/nexum-tools.js.map +1 -0
  91. package/dist/mcp/service-public-url.d.ts +7 -0
  92. package/dist/mcp/service-public-url.d.ts.map +1 -0
  93. package/dist/mcp/service-public-url.js +19 -0
  94. package/dist/mcp/service-public-url.js.map +1 -0
  95. package/dist/nexum-analysis/backfill.d.ts +59 -0
  96. package/dist/nexum-analysis/backfill.d.ts.map +1 -0
  97. package/dist/nexum-analysis/backfill.js +199 -0
  98. package/dist/nexum-analysis/backfill.js.map +1 -0
  99. package/dist/nexum-analysis/enqueue.d.ts +29 -0
  100. package/dist/nexum-analysis/enqueue.d.ts.map +1 -0
  101. package/dist/nexum-analysis/enqueue.js +190 -0
  102. package/dist/nexum-analysis/enqueue.js.map +1 -0
  103. package/dist/nexum-analysis/outbox.d.ts +44 -0
  104. package/dist/nexum-analysis/outbox.d.ts.map +1 -0
  105. package/dist/nexum-analysis/outbox.js +176 -0
  106. package/dist/nexum-analysis/outbox.js.map +1 -0
  107. package/dist/nexum-analysis/policy.d.ts +48 -0
  108. package/dist/nexum-analysis/policy.d.ts.map +1 -0
  109. package/dist/nexum-analysis/policy.js +165 -0
  110. package/dist/nexum-analysis/policy.js.map +1 -0
  111. package/dist/nexum-analysis/reconcile.d.ts +8 -0
  112. package/dist/nexum-analysis/reconcile.d.ts.map +1 -0
  113. package/dist/nexum-analysis/reconcile.js +37 -0
  114. package/dist/nexum-analysis/reconcile.js.map +1 -0
  115. package/dist/openapi/openapi.json +591 -4
  116. package/dist/operational-db.d.ts +6 -0
  117. package/dist/operational-db.d.ts.map +1 -0
  118. package/dist/operational-db.js +22 -0
  119. package/dist/operational-db.js.map +1 -0
  120. package/dist/platform.d.ts +4 -1
  121. package/dist/platform.d.ts.map +1 -1
  122. package/dist/platform.js +67 -14
  123. package/dist/platform.js.map +1 -1
  124. package/dist/request-countex.d.ts +25 -0
  125. package/dist/request-countex.d.ts.map +1 -1
  126. package/dist/request-countex.js +103 -18
  127. package/dist/request-countex.js.map +1 -1
  128. package/dist/restricted-store/object-store.d.ts.map +1 -1
  129. package/dist/restricted-store/object-store.js +1 -3
  130. package/dist/restricted-store/object-store.js.map +1 -1
  131. package/dist/routes/connector-invocations.d.ts.map +1 -1
  132. package/dist/routes/connector-invocations.js +7 -1
  133. package/dist/routes/connector-invocations.js.map +1 -1
  134. package/dist/routes/data.d.ts.map +1 -1
  135. package/dist/routes/data.js +113 -14
  136. package/dist/routes/data.js.map +1 -1
  137. package/dist/routes/knowledge.d.ts +8 -0
  138. package/dist/routes/knowledge.d.ts.map +1 -0
  139. package/dist/routes/knowledge.js +86 -0
  140. package/dist/routes/knowledge.js.map +1 -0
  141. package/dist/routes/memory.d.ts.map +1 -1
  142. package/dist/routes/memory.js +33 -9
  143. package/dist/routes/memory.js.map +1 -1
  144. package/dist/routes/metadata.d.ts.map +1 -1
  145. package/dist/routes/metadata.js +102 -1
  146. package/dist/routes/metadata.js.map +1 -1
  147. package/dist/routes/mgc-landing.d.ts.map +1 -1
  148. package/dist/routes/mgc-landing.js +90 -1
  149. package/dist/routes/mgc-landing.js.map +1 -1
  150. package/dist/routes/nexum-mcp.d.ts +9 -0
  151. package/dist/routes/nexum-mcp.d.ts.map +1 -0
  152. package/dist/routes/nexum-mcp.js +95 -0
  153. package/dist/routes/nexum-mcp.js.map +1 -0
  154. package/dist/routes/operations.d.ts.map +1 -1
  155. package/dist/routes/operations.js +39 -2
  156. package/dist/routes/operations.js.map +1 -1
  157. package/dist/routes/publications.d.ts +4 -0
  158. package/dist/routes/publications.d.ts.map +1 -0
  159. package/dist/routes/publications.js +111 -0
  160. package/dist/routes/publications.js.map +1 -0
  161. package/dist/routes/workflow.d.ts.map +1 -1
  162. package/dist/routes/workflow.js +18 -9
  163. package/dist/routes/workflow.js.map +1 -1
  164. package/dist/safe-query.d.ts +28 -0
  165. package/dist/safe-query.d.ts.map +1 -0
  166. package/dist/safe-query.js +104 -0
  167. package/dist/safe-query.js.map +1 -0
  168. package/openapi/openapi.json +591 -4
  169. package/package.json +5 -5
@@ -0,0 +1,676 @@
1
+ /** HTML for GET /_live/graph — browse stored knowledge-graph subjects. */
2
+ export function graphHtml() {
3
+ return `<!DOCTYPE html>
4
+ <html lang="en">
5
+ <head>
6
+ <meta charset="utf-8" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+ <title>Memorix · Graph</title>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
11
+ <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet" />
12
+ <style>
13
+ :root {
14
+ --bg: #0a0c10; --bg-elev: #10141b; --bg-row: #141922; --line: #242b38;
15
+ --text: #e8ebe6; --muted: #8a9288; --dim: #5c645c;
16
+ --ok: #3dba7a; --bad: #e25a5a; --accent: #c8f082; --accent-ink: #0a0c10;
17
+ --api: #7eb8d4;
18
+ --sans: "IBM Plex Sans", system-ui, sans-serif;
19
+ --mono: "IBM Plex Mono", ui-monospace, monospace;
20
+ }
21
+ * { box-sizing: border-box; }
22
+ html, body { height: 100%; margin: 0; }
23
+ body {
24
+ font-family: var(--sans);
25
+ background:
26
+ radial-gradient(1200px 600px at 10% -10%, #1a2214 0%, transparent 55%),
27
+ radial-gradient(900px 500px at 100% 0%, #121820 0%, transparent 50%),
28
+ var(--bg);
29
+ color: var(--text); font-size: 14px; line-height: 1.45;
30
+ }
31
+ a { color: var(--accent); }
32
+ .shell { max-width: 1280px; margin: 0 auto; padding: 36px 28px 64px; }
33
+ header {
34
+ display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;
35
+ margin-bottom: 22px; padding-bottom: 18px; border-bottom: 1px solid var(--line);
36
+ }
37
+ .brand { font-size: 26px; font-weight: 700; letter-spacing: -0.03em; }
38
+ .brand span { color: var(--accent); }
39
+ .sub { margin-top: 8px; color: var(--muted); font-size: 13px; max-width: 72ch; }
40
+ .meta { text-align: right; font-family: var(--mono); font-size: 11px; color: var(--dim); display: grid; gap: 4px; }
41
+ .scope, .filters {
42
+ display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
43
+ margin-bottom: 14px; padding: 12px 14px;
44
+ background: var(--bg-elev); border: 1px solid var(--line);
45
+ }
46
+ .scope label, .filters label {
47
+ display: flex; flex-direction: column; gap: 4px;
48
+ font-family: var(--mono); font-size: 10px; letter-spacing: 0.06em;
49
+ text-transform: uppercase; color: var(--dim);
50
+ }
51
+ .scope input, .filters input {
52
+ appearance: none; border: 1px solid var(--line); background: var(--bg-row); color: var(--text);
53
+ font: 500 12px/1.2 var(--sans); padding: 8px 10px; border-radius: 2px; min-width: 140px;
54
+ }
55
+ .filters input { min-width: 180px; }
56
+ .btn {
57
+ appearance: none; border: 1px solid var(--line); background: var(--bg-row); color: var(--text);
58
+ font: 500 12px/1 var(--sans); padding: 10px 16px; cursor: pointer; border-radius: 2px;
59
+ }
60
+ .btn:hover { border-color: var(--accent); }
61
+ .btn.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
62
+ .status-bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 14px; }
63
+ .summary { font-family: var(--mono); font-size: 12px; color: var(--muted); }
64
+ .summary strong { color: var(--text); font-weight: 500; }
65
+ .table-scroll {
66
+ max-height: min(62vh, 720px); overflow: auto; border: 1px solid var(--line);
67
+ }
68
+ table.list {
69
+ width: 100%; table-layout: fixed; border-collapse: collapse; background: var(--bg-elev); border: 0;
70
+ }
71
+ table.list th, table.list td {
72
+ text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line);
73
+ vertical-align: middle; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
74
+ }
75
+ th {
76
+ font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
77
+ color: var(--dim); font-weight: 500; background: #0d1016;
78
+ }
79
+ tr:hover td { background: var(--bg-row); }
80
+ tr.clickable { cursor: pointer; }
81
+ .mono { font-family: var(--mono); font-size: 12px; color: var(--muted); }
82
+ .empty { color: var(--muted); padding: 24px 0; }
83
+ .err { color: var(--bad); padding: 12px 0; font-family: var(--mono); font-size: 12px; }
84
+ footer { margin-top: 28px; color: var(--dim); font-size: 12px; }
85
+ footer a { margin-right: 12px; }
86
+ .dialog-back {
87
+ position: fixed; inset: 0; z-index: 30;
88
+ background: rgba(6, 8, 10, 0.72);
89
+ display: flex; align-items: flex-start; justify-content: center;
90
+ padding: 40px 20px; overflow: auto;
91
+ }
92
+ .dialog-back[hidden] { display: none; }
93
+ .dialog {
94
+ width: min(960px, 100%);
95
+ background: var(--bg-elev); border: 1px solid var(--line);
96
+ padding: 14px 18px 20px;
97
+ }
98
+ .dialog-bar {
99
+ display: flex; align-items: center; justify-content: space-between; gap: 12px;
100
+ margin-bottom: 8px;
101
+ }
102
+ .dialog-bar strong {
103
+ font-size: 13px; letter-spacing: 0.04em; text-transform: uppercase;
104
+ }
105
+ .detail {
106
+ font-family: var(--mono); font-size: 11px; color: var(--muted);
107
+ }
108
+ .detail h3 {
109
+ margin: 14px 0 8px; font-size: 12px; color: var(--text); font-weight: 600;
110
+ letter-spacing: 0.04em; text-transform: uppercase;
111
+ }
112
+ .detail h3:first-child { margin-top: 0; }
113
+ .edge-list, .ref-list, .rel-list { margin: 0; padding-left: 18px; }
114
+ .edge-list li, .ref-list li, .rel-list li { margin: 2px 0; }
115
+ .graph-svg {
116
+ width: 100%; height: 280px; margin-top: 10px;
117
+ background: #0a0c10; border: 1px solid var(--line);
118
+ }
119
+ .graph-svg text { fill: var(--muted); font-family: var(--mono); font-size: 10px; }
120
+ .graph-svg circle { fill: var(--accent); stroke: #2a3218; stroke-width: 1; }
121
+ .graph-svg line { stroke: var(--api); stroke-width: 1.2; opacity: 0.85; }
122
+ .ref-link { color: var(--accent); cursor: pointer; text-decoration: underline; background: none; border: 0; padding: 0; font: inherit; }
123
+ </style>
124
+ </head>
125
+ <body>
126
+ <div class="shell">
127
+ <header>
128
+ <div>
129
+ <div class="brand">Memorix <span>graph</span></div>
130
+ <p class="sub">Browse stored Nexum knowledge-graph subjects (<span class="mono">content/snapshots</span>, <span class="mono">data.kind=knowledge-graph</span>). Open a row to see the proposed graph and Memorix relationship links for its source.</p>
131
+ </div>
132
+ <div class="meta">
133
+ <div><strong>UI</strong> /_live/graph</div>
134
+ <div><a href="/_live">← live view</a> · <a href="/_live/activity">activity</a> · <a href="/_live/changes">data changes</a></div>
135
+ </div>
136
+ </header>
137
+
138
+ <div class="scope" id="scope">
139
+ <label>Org
140
+ <input id="s-org" type="text" autocomplete="off" />
141
+ </label>
142
+ <label>Agents
143
+ <input id="s-agents" type="text" placeholder="opx,network-synapix" autocomplete="off" />
144
+ </label>
145
+ <label>Caller
146
+ <input id="s-caller" type="text" autocomplete="off" />
147
+ </label>
148
+ <button class="btn primary" id="s-apply" type="button">Load graphs</button>
149
+ </div>
150
+
151
+ <div class="filters">
152
+ <label>Search
153
+ <input id="f-q" type="search" placeholder="record, source, node…" />
154
+ </label>
155
+ <label>Source record
156
+ <input id="f-source" type="search" placeholder="working/…" />
157
+ </label>
158
+ <button class="btn" id="f-clear" type="button">Clear filters</button>
159
+ </div>
160
+
161
+ <div class="status-bar">
162
+ <div class="summary" id="summary">Set scope and load.</div>
163
+ <button class="btn" id="more" type="button" hidden>Load more</button>
164
+ </div>
165
+ <div class="table-scroll" id="table-scroll"></div>
166
+ <footer>
167
+ <a href="/_live">/_live</a>
168
+ <a href="/_live/activity">/_live/activity</a>
169
+ <a href="/_live/changes">/_live/changes</a>
170
+ Reads <span class="mono">GET /api/data/content</span> and <span class="mono">GET /api/relationships/query</span>.
171
+ </footer>
172
+ </div>
173
+
174
+ <div class="dialog-back" id="dialog-back" hidden>
175
+ <div class="dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-title">
176
+ <div class="dialog-bar">
177
+ <strong id="dialog-title">Graph</strong>
178
+ <button class="btn" id="dialog-close" type="button">Close</button>
179
+ </div>
180
+ <div id="dialog-body" class="detail"></div>
181
+ </div>
182
+ </div>
183
+
184
+ <script>
185
+ const $ = (id) => document.getElementById(id);
186
+ const STORE_KEY = "memorix-live-graph-scope";
187
+ const DEFAULT_SCOPE = {
188
+ orgId: "tgi",
189
+ agentIds: "opx,network-synapix",
190
+ caller: "memorix-ops",
191
+ };
192
+
193
+ let allRows = [];
194
+ let nextCursor = null;
195
+ let loading = false;
196
+ let filterState = { q: "", source: "" };
197
+
198
+ function escapeHtml(s) {
199
+ return String(s ?? "").replace(/[&<>"']/g, (c) => ({
200
+ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;"
201
+ })[c]);
202
+ }
203
+
204
+ function loadScope() {
205
+ try {
206
+ const raw = localStorage.getItem(STORE_KEY);
207
+ if (raw) return { ...DEFAULT_SCOPE, ...JSON.parse(raw) };
208
+ } catch {}
209
+ return { ...DEFAULT_SCOPE };
210
+ }
211
+
212
+ function saveScope(scope) {
213
+ try { localStorage.setItem(STORE_KEY, JSON.stringify(scope)); } catch {}
214
+ }
215
+
216
+ function readScopeForm() {
217
+ return {
218
+ orgId: $("s-org").value.trim() || DEFAULT_SCOPE.orgId,
219
+ agentIds: $("s-agents").value.trim() || DEFAULT_SCOPE.agentIds,
220
+ caller: $("s-caller").value.trim() || DEFAULT_SCOPE.caller,
221
+ };
222
+ }
223
+
224
+ function applyScopeToForm(scope) {
225
+ $("s-org").value = scope.orgId;
226
+ $("s-agents").value = scope.agentIds;
227
+ $("s-caller").value = scope.caller;
228
+ }
229
+
230
+ function scopeHeaders() {
231
+ const s = readScopeForm();
232
+ return {
233
+ "x-memorix-org-id": s.orgId,
234
+ "x-memorix-agent-ids": s.agentIds,
235
+ "x-memorix-caller": s.caller,
236
+ };
237
+ }
238
+
239
+ function asRecord(v) {
240
+ return v && typeof v === "object" && !Array.isArray(v) ? v : null;
241
+ }
242
+
243
+ function recordData(rec) {
244
+ return asRecord(rec && rec.data) || {};
245
+ }
246
+
247
+ function isKnowledgeGraph(rec) {
248
+ return recordData(rec).kind === "knowledge-graph";
249
+ }
250
+
251
+ function sourceRefsOf(rec) {
252
+ const refs = recordData(rec).sourceRefs;
253
+ return Array.isArray(refs)
254
+ ? refs.filter((x) => typeof x === "string" && x.trim()).map((x) => x.trim())
255
+ : [];
256
+ }
257
+
258
+ function titleOf(rec) {
259
+ const concept = asRecord(rec.concept);
260
+ if (concept && typeof concept.title === "string" && concept.title.trim()) {
261
+ return concept.title.trim();
262
+ }
263
+ const data = recordData(rec);
264
+ const pg = asRecord(data.proposedGraph);
265
+ const nodes = Array.isArray(pg && pg.nodes) ? pg.nodes : [];
266
+ for (const raw of nodes) {
267
+ const n = asRecord(raw);
268
+ if (!n) continue;
269
+ const label = String(n.label ?? n.title ?? "").trim();
270
+ if (label) return label;
271
+ }
272
+ return rec.recordId || "Knowledge graph";
273
+ }
274
+
275
+ function countsOf(rec) {
276
+ const data = recordData(rec);
277
+ const pg = asRecord(data.proposedGraph);
278
+ const nodes = Array.isArray(pg && pg.nodes) ? pg.nodes : [];
279
+ const edges = Array.isArray(pg && pg.edges) ? pg.edges : [];
280
+ return {
281
+ nodes: typeof data.nodeCount === "number" ? data.nodeCount : nodes.length,
282
+ edges: typeof data.edgeCount === "number" ? data.edgeCount : edges.length,
283
+ };
284
+ }
285
+
286
+ function parseNode(raw, index) {
287
+ const o = asRecord(raw);
288
+ if (!o) return { id: "n" + index, label: "n" + index };
289
+ const id = String(o.id ?? o.recordId ?? ("n" + index)).trim() || ("n" + index);
290
+ const label = String(o.label ?? o.title ?? id).trim() || id;
291
+ return { id, label };
292
+ }
293
+
294
+ function parseEdge(raw) {
295
+ const o = asRecord(raw);
296
+ if (!o) return null;
297
+ const from = String(o.from ?? o.source ?? o.fromRecordId ?? o.src ?? "").trim();
298
+ const to = String(o.to ?? o.target ?? o.toRecordId ?? o.dst ?? "").trim();
299
+ if (!from || !to) return null;
300
+ const labelRaw = o.label ?? o.type ?? o.kind;
301
+ const label = typeof labelRaw === "string" && labelRaw.trim() ? labelRaw.trim() : undefined;
302
+ return label ? { from, to, label } : { from, to };
303
+ }
304
+
305
+ function layoutNodes(nodes) {
306
+ const n = Math.max(nodes.length, 1);
307
+ const cx = 480, cy = 140, r = Math.min(120, 50 + n * 5);
308
+ return nodes.map((node, i) => {
309
+ const ang = (Math.PI * 2 * i) / n - Math.PI / 2;
310
+ return {
311
+ ...node,
312
+ x: cx + r * Math.cos(ang),
313
+ y: cy + r * Math.sin(ang),
314
+ };
315
+ });
316
+ }
317
+
318
+ function renderGraphSvg(rec) {
319
+ const data = recordData(rec);
320
+ const pg = asRecord(data.proposedGraph);
321
+ const nodes = (Array.isArray(pg && pg.nodes) ? pg.nodes : []).map(parseNode);
322
+ const edges = (Array.isArray(pg && pg.edges) ? pg.edges : [])
323
+ .map(parseEdge)
324
+ .filter(Boolean);
325
+ if (!nodes.length) {
326
+ return "<p class='empty'>No nodes in proposedGraph.</p>";
327
+ }
328
+ const positions = layoutNodes(nodes);
329
+ const byKey = new Map();
330
+ for (const p of positions) {
331
+ byKey.set(p.id, p);
332
+ if (!byKey.has(p.label)) byKey.set(p.label, p);
333
+ }
334
+ let lines = "";
335
+ for (const e of edges) {
336
+ const a = byKey.get(e.from);
337
+ const b = byKey.get(e.to);
338
+ if (!a || !b) continue;
339
+ lines += '<line x1="' + a.x + '" y1="' + a.y + '" x2="' + b.x + '" y2="' + b.y + '" />';
340
+ }
341
+ let dots = "";
342
+ for (const p of positions) {
343
+ const short = p.label.length > 22 ? p.label.slice(0, 20) + "…" : p.label;
344
+ dots += '<circle cx="' + p.x + '" cy="' + p.y + '" r="7" />';
345
+ dots += '<text x="' + p.x + '" y="' + (p.y + 20) + '" text-anchor="middle">' + escapeHtml(short) + "</text>";
346
+ }
347
+ return '<svg class="graph-svg" viewBox="0 0 960 280" xmlns="http://www.w3.org/2000/svg">' +
348
+ lines + dots + "</svg>";
349
+ }
350
+
351
+ function filteredRows() {
352
+ return allRows.filter((rec) => {
353
+ const refs = sourceRefsOf(rec);
354
+ if (filterState.source) {
355
+ const needle = filterState.source.toLowerCase();
356
+ if (!refs.some((r) => r.toLowerCase().includes(needle))) return false;
357
+ }
358
+ if (filterState.q) {
359
+ const counts = countsOf(rec);
360
+ const data = recordData(rec);
361
+ const pg = asRecord(data.proposedGraph);
362
+ const labels = (Array.isArray(pg && pg.nodes) ? pg.nodes : [])
363
+ .map((n, i) => parseNode(n, i).label)
364
+ .join(" ");
365
+ const hay = [
366
+ rec.recordId, titleOf(rec), refs.join(" "), labels,
367
+ String(counts.nodes), String(counts.edges),
368
+ ].join(" ").toLowerCase();
369
+ if (!hay.includes(filterState.q)) return false;
370
+ }
371
+ return true;
372
+ });
373
+ }
374
+
375
+ function updateSummary() {
376
+ const shown = filteredRows();
377
+ $("summary").innerHTML =
378
+ "showing <strong>" + shown.length + "</strong> of <strong>" + allRows.length +
379
+ "</strong> knowledge-graph subjects" +
380
+ (nextCursor ? " · more available" : "");
381
+ $("more").hidden = !nextCursor;
382
+ }
383
+
384
+ function renderList() {
385
+ const shown = filteredRows();
386
+ const sc = $("table-scroll");
387
+ updateSummary();
388
+ if (!shown.length) {
389
+ sc.innerHTML = "<p class='empty'>" +
390
+ (allRows.length ? "No graphs match these filters." : "No knowledge-graph subjects loaded yet.") +
391
+ "</p>";
392
+ return;
393
+ }
394
+ let html = '<table class="list"><colgroup>' +
395
+ '<col style="width:28%"><col style="width:34%"><col style="width:26%"><col style="width:6%"><col style="width:6%">' +
396
+ "</colgroup><thead><tr>" +
397
+ "<th>Record</th><th>Title</th><th>Sources</th><th>Nodes</th><th>Edges</th>" +
398
+ "</tr></thead><tbody>";
399
+ shown.forEach((rec, i) => {
400
+ const counts = countsOf(rec);
401
+ const refs = sourceRefsOf(rec);
402
+ const tip = [rec.recordId, titleOf(rec), refs.join(", ")].join(" · ");
403
+ html += '<tr class="clickable" data-i="' + i + '" title="' + escapeHtml(tip) + '">' +
404
+ '<td class="mono">' + escapeHtml(rec.recordId || "—") + "</td>" +
405
+ "<td>" + escapeHtml(titleOf(rec)) + "</td>" +
406
+ '<td class="mono">' + escapeHtml(refs.slice(0, 3).join(", ") + (refs.length > 3 ? "…" : "") || "—") + "</td>" +
407
+ "<td>" + escapeHtml(counts.nodes) + "</td>" +
408
+ "<td>" + escapeHtml(counts.edges) + "</td>" +
409
+ "</tr>";
410
+ });
411
+ html += "</tbody></table>";
412
+ sc.innerHTML = html;
413
+ sc.querySelectorAll("tr.clickable").forEach((tr) => {
414
+ tr.addEventListener("click", () => {
415
+ const i = Number(tr.getAttribute("data-i"));
416
+ const rec = shown[i];
417
+ if (rec) openDialog(rec);
418
+ });
419
+ });
420
+ }
421
+
422
+ function renderEdgesList(rec) {
423
+ const data = recordData(rec);
424
+ const pg = asRecord(data.proposedGraph);
425
+ const edges = (Array.isArray(pg && pg.edges) ? pg.edges : [])
426
+ .map(parseEdge)
427
+ .filter(Boolean);
428
+ if (!edges.length) return "<p>No edges in proposedGraph.</p>";
429
+ let html = "<ul class='edge-list'>";
430
+ for (const e of edges.slice(0, 60)) {
431
+ html += "<li>" + escapeHtml(e.from) + " → " + escapeHtml(e.to) +
432
+ (e.label ? " <span class='mono'>(" + escapeHtml(e.label) + ")</span>" : "") +
433
+ "</li>";
434
+ }
435
+ if (edges.length > 60) {
436
+ html += "<li class='mono'>…and " + (edges.length - 60) + " more</li>";
437
+ }
438
+ html += "</ul>";
439
+ return html;
440
+ }
441
+
442
+ function renderSourceRefs(rec) {
443
+ const refs = sourceRefsOf(rec);
444
+ if (!refs.length) return "<p>No sourceRefs on this subject.</p>";
445
+ let html = "<ul class='ref-list'>";
446
+ for (const ref of refs) {
447
+ html += "<li><button type='button' class='ref-link' data-ref='" + escapeHtml(ref) + "'>" +
448
+ escapeHtml(ref) + "</button></li>";
449
+ }
450
+ html += "</ul>";
451
+ return html;
452
+ }
453
+
454
+ function renderRelLinks(links, emptyMsg) {
455
+ if (!links || !links.length) return "<p>" + escapeHtml(emptyMsg) + "</p>";
456
+ let html = "<ul class='rel-list'>";
457
+ for (const link of links.slice(0, 40)) {
458
+ const from = link.fromRecordId || (link.from && link.from.recordId) || "?";
459
+ const to = link.toRecordId || (link.to && link.to.recordId) ||
460
+ link.targetRecordId || "?";
461
+ const def = link.definitionId || link.type || "";
462
+ html += "<li><span class='mono'>" + escapeHtml(from) + "</span> → <span class='mono'>" +
463
+ escapeHtml(to) + "</span>" +
464
+ (def ? " <span class='mono'>(" + escapeHtml(def) + ")</span>" : "") +
465
+ "</li>";
466
+ }
467
+ if (links.length > 40) {
468
+ html += "<li class='mono'>…and " + (links.length - 40) + " more</li>";
469
+ }
470
+ html += "</ul>";
471
+ return html;
472
+ }
473
+
474
+ async function fetchRelationships(recordId, direction) {
475
+ const url = "/api/relationships/query?recordId=" + encodeURIComponent(recordId) +
476
+ "&direction=" + encodeURIComponent(direction) + "&limit=50";
477
+ const res = await fetch(url, { headers: scopeHeaders() });
478
+ const body = await res.json().catch(() => ({}));
479
+ if (!res.ok) {
480
+ const msg = (body.error && body.error.message) || ("HTTP " + res.status);
481
+ return { error: msg, links: [] };
482
+ }
483
+ return { links: body.links || [], error: null };
484
+ }
485
+
486
+ async function openDialog(rec) {
487
+ const counts = countsOf(rec);
488
+ $("dialog-title").textContent = titleOf(rec);
489
+ let html = "<h3>Stored graph</h3>";
490
+ html += '<div>record <span class="mono">' + escapeHtml(rec.recordId || "") + "</span></div>";
491
+ html += "<div>nodes <strong>" + escapeHtml(counts.nodes) +
492
+ "</strong> · edges <strong>" + escapeHtml(counts.edges) + "</strong></div>";
493
+ html += renderGraphSvg(rec);
494
+ html += "<h3>Edges</h3>" + renderEdgesList(rec);
495
+ html += "<h3>Source refs</h3>" + renderSourceRefs(rec);
496
+ html += "<h3>Memorix relationships</h3>";
497
+ html += "<p id='rel-status' class='mono'>Loading relationship links…</p>";
498
+ html += "<div id='rel-forward'></div><div id='rel-inverse'></div>";
499
+ $("dialog-body").innerHTML = html;
500
+ $("dialog-back").hidden = false;
501
+
502
+ $("dialog-body").querySelectorAll(".ref-link").forEach((btn) => {
503
+ btn.addEventListener("click", async () => {
504
+ const ref = btn.getAttribute("data-ref");
505
+ if (!ref) return;
506
+ try {
507
+ const loaded = await getGraphByRecordId(ref);
508
+ if (loaded) openDialog(loaded);
509
+ else {
510
+ filterState.source = ref;
511
+ $("f-source").value = ref;
512
+ renderList();
513
+ closeDialog();
514
+ }
515
+ } catch (err) {
516
+ $("rel-status").textContent = err.message || String(err);
517
+ }
518
+ });
519
+ });
520
+
521
+ const refs = sourceRefsOf(rec);
522
+ const subject = refs[0] || "";
523
+ const status = $("rel-status");
524
+ const fwdEl = $("rel-forward");
525
+ const invEl = $("rel-inverse");
526
+ if (!subject) {
527
+ status.textContent = "No sourceRefs — relationship query skipped.";
528
+ return;
529
+ }
530
+ try {
531
+ const [fwd, inv] = await Promise.all([
532
+ fetchRelationships(subject, "forward"),
533
+ fetchRelationships(subject, "inverse"),
534
+ ]);
535
+ status.innerHTML = 'For source <span class="mono">' + escapeHtml(subject) + "</span>";
536
+ fwdEl.innerHTML = "<h3>Forward</h3>" +
537
+ (fwd.error
538
+ ? "<p class='err'>" + escapeHtml(fwd.error) + "</p>"
539
+ : renderRelLinks(fwd.links, "No forward relationship links."));
540
+ invEl.innerHTML = "<h3>Inverse</h3>" +
541
+ (inv.error
542
+ ? "<p class='err'>" + escapeHtml(inv.error) + "</p>"
543
+ : renderRelLinks(inv.links, "No inverse relationship links."));
544
+ } catch (err) {
545
+ status.textContent = err.message || String(err);
546
+ }
547
+ }
548
+
549
+ function closeDialog() {
550
+ $("dialog-back").hidden = true;
551
+ $("dialog-body").innerHTML = "";
552
+ }
553
+
554
+ async function listPage(cursor) {
555
+ let url = "/api/data/content?objectType=content&contentType=snapshots&limit=200";
556
+ if (cursor) url += "&cursor=" + encodeURIComponent(cursor);
557
+ const res = await fetch(url, { headers: scopeHeaders() });
558
+ const body = await res.json().catch(() => ({}));
559
+ if (!res.ok) {
560
+ const msg = (body.error && body.error.message) || ("HTTP " + res.status);
561
+ throw new Error(msg);
562
+ }
563
+ const records = Array.isArray(body.records) ? body.records : [];
564
+ return {
565
+ records: records.filter(isKnowledgeGraph),
566
+ nextCursor: body.pageInfo && body.pageInfo.nextCursor
567
+ ? body.pageInfo.nextCursor
568
+ : null,
569
+ };
570
+ }
571
+
572
+ async function getGraphByRecordId(recordId) {
573
+ const url = "/api/data/content?objectType=content&contentType=snapshots&recordId=" +
574
+ encodeURIComponent(recordId);
575
+ const res = await fetch(url, { headers: scopeHeaders() });
576
+ if (res.status === 404) return null;
577
+ const body = await res.json().catch(() => ({}));
578
+ if (!res.ok) {
579
+ const msg = (body.error && body.error.message) || ("HTTP " + res.status);
580
+ throw new Error(msg);
581
+ }
582
+ const rec = body.record || null;
583
+ if (!rec || !isKnowledgeGraph(rec)) return null;
584
+ return rec;
585
+ }
586
+
587
+ async function load(reset) {
588
+ if (loading) return;
589
+ loading = true;
590
+ const sc = $("table-scroll");
591
+ try {
592
+ if (reset) {
593
+ allRows = [];
594
+ nextCursor = null;
595
+ sc.innerHTML = "<p class='empty'>Loading…</p>";
596
+ }
597
+ const page = await listPage(reset ? null : nextCursor);
598
+ const seen = new Set(allRows.map((r) => r.recordId));
599
+ for (const rec of page.records) {
600
+ if (rec.recordId && seen.has(rec.recordId)) continue;
601
+ if (rec.recordId) seen.add(rec.recordId);
602
+ allRows.push(rec);
603
+ }
604
+ nextCursor = page.nextCursor;
605
+ saveScope(readScopeForm());
606
+ renderList();
607
+ } catch (err) {
608
+ sc.innerHTML = "<p class='err'>" + escapeHtml(err.message || String(err)) + "</p>";
609
+ $("summary").textContent = "Load failed";
610
+ $("more").hidden = true;
611
+ } finally {
612
+ loading = false;
613
+ }
614
+ }
615
+
616
+ function readUrlFilters() {
617
+ const params = new URLSearchParams(location.search);
618
+ const source = params.get("source") || "";
619
+ const recordId = params.get("recordId") || "";
620
+ if (source) {
621
+ filterState.source = source;
622
+ $("f-source").value = source;
623
+ }
624
+ return recordId;
625
+ }
626
+
627
+ applyScopeToForm(loadScope());
628
+ const openRecordId = readUrlFilters();
629
+
630
+ $("s-apply").onclick = () => load(true);
631
+ $("more").onclick = () => load(false);
632
+ $("f-clear").onclick = () => {
633
+ filterState = { q: "", source: "" };
634
+ $("f-q").value = "";
635
+ $("f-source").value = "";
636
+ renderList();
637
+ };
638
+ ["f-q", "f-source"].forEach((id) => {
639
+ $(id).addEventListener("input", () => {
640
+ filterState = {
641
+ q: $("f-q").value.trim().toLowerCase(),
642
+ source: $("f-source").value.trim(),
643
+ };
644
+ renderList();
645
+ });
646
+ });
647
+ $("dialog-close").onclick = () => closeDialog();
648
+ $("dialog-back").addEventListener("click", (ev) => {
649
+ if (ev.target === $("dialog-back")) closeDialog();
650
+ });
651
+ document.addEventListener("keydown", (ev) => {
652
+ if (ev.key === "Escape" && !$("dialog-back").hidden) closeDialog();
653
+ });
654
+
655
+ (async () => {
656
+ await load(true);
657
+ if (openRecordId) {
658
+ try {
659
+ const rec = await getGraphByRecordId(openRecordId);
660
+ if (rec) openDialog(rec);
661
+ else {
662
+ const found = allRows.find((r) => r.recordId === openRecordId);
663
+ if (found) openDialog(found);
664
+ }
665
+ } catch (err) {
666
+ $("summary").innerHTML =
667
+ $("summary").innerHTML +
668
+ ' · <span class="err">' + escapeHtml(err.message || String(err)) + "</span>";
669
+ }
670
+ }
671
+ })();
672
+ </script>
673
+ </body>
674
+ </html>`;
675
+ }
676
+ //# sourceMappingURL=graph-ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-ui.js","sourceRoot":"","sources":["../src/graph-ui.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,MAAM,UAAU,SAAS;IACvB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA+pBD,CAAC;AACT,CAAC"}