@oimdb/mcp 2.0.0 → 3.0.0

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/bin/cdp.cjs DELETED
@@ -1,98 +0,0 @@
1
- /**
2
- * One-shot CDP inspector: connects to Chrome, evaluates __OIMDB_DEV__.inspect(),
3
- * prints JSON to stdout. Pipe to jq or paste into an AI prompt.
4
- *
5
- * Requirements:
6
- * Launch Chrome with: --remote-debugging-port=9222
7
- * (or set CDP_URL env var to point to a different address)
8
- *
9
- * Usage:
10
- * npx @oimdb/mcp cdp
11
- * OIMDB_CDP_URL=http://localhost:9222 npx @oimdb/mcp cdp
12
- * npx @oimdb/mcp cdp | jq .collections
13
- */
14
-
15
- const cdpBase = process.env.OIMDB_CDP_URL || 'http://localhost:9222';
16
-
17
- async function run() {
18
- // 1. List open tabs
19
- let tabs;
20
- try {
21
- const res = await fetch(`${cdpBase}/json/list`);
22
- tabs = await res.json();
23
- } catch {
24
- process.stderr.write(
25
- `[OIMDB CDP] Cannot reach Chrome at ${cdpBase}\n` +
26
- `Launch Chrome with: --remote-debugging-port=9222\n`
27
- );
28
- process.exit(1);
29
- }
30
-
31
- // Find first tab that has a debugger URL
32
- const tab = tabs.find((t) => t.webSocketDebuggerUrl);
33
- if (!tab) {
34
- process.stderr.write('[OIMDB CDP] No debuggable tabs found.\n');
35
- process.exit(1);
36
- }
37
-
38
- process.stderr.write(`[OIMDB CDP] Connected to: ${tab.title} (${tab.url})\n`);
39
-
40
- // 2. Open CDP WebSocket
41
- const { WebSocket } = await import('ws');
42
- const ws = new WebSocket(tab.webSocketDebuggerUrl);
43
-
44
- await new Promise((resolve, reject) => {
45
- const timeout = setTimeout(() => {
46
- ws.close();
47
- reject(new Error('CDP timeout (5s)'));
48
- }, 5000);
49
-
50
- ws.once('open', () => {
51
- ws.send(JSON.stringify({
52
- id: 1,
53
- method: 'Runtime.evaluate',
54
- params: {
55
- expression: [
56
- '(function(){',
57
- ' if(!window.__OIMDB_DEV__) return null;',
58
- ' return JSON.parse(JSON.stringify(window.__OIMDB_DEV__.inspect()));',
59
- '})()',
60
- ].join(''),
61
- returnByValue: true,
62
- awaitPromise: false,
63
- },
64
- }));
65
- });
66
-
67
- ws.on('message', (raw) => {
68
- const msg = JSON.parse(raw.toString());
69
- if (msg.id !== 1) return;
70
- clearTimeout(timeout);
71
- ws.close();
72
-
73
- const val = msg.result?.result?.value;
74
- if (val === null || val === undefined) {
75
- process.stderr.write(
76
- '[OIMDB CDP] __OIMDB_DEV__ not found on this page.\n' +
77
- 'Make sure debug.ts sets: window.__OIMDB_DEV__ = oimDevRegistry\n'
78
- );
79
- process.exit(1);
80
- }
81
- process.stdout.write(JSON.stringify(val, null, 2) + '\n');
82
- resolve(undefined);
83
- });
84
-
85
- ws.once('error', (err) => {
86
- clearTimeout(timeout);
87
- reject(err);
88
- });
89
- });
90
- }
91
-
92
- /** Run the one-shot CDP snapshot (`cdp` subcommand). */
93
- module.exports = function runCdp() {
94
- run().catch((err) => {
95
- process.stderr.write('[OIMDB CDP] Error: ' + err.message + '\n');
96
- process.exit(1);
97
- });
98
- };
package/bin/devtools.cjs DELETED
@@ -1,26 +0,0 @@
1
- const path = require('path');
2
- const { OIMDevUIServer } = require('../dist/index.cjs');
3
-
4
- /** Start the standalone DevTools UI server (`devtools` subcommand). */
5
- module.exports = function runDevtools() {
6
- const wsPort = process.env.OIMDB_WS_PORT
7
- ? Number(process.env.OIMDB_WS_PORT)
8
- : 7432;
9
- const uiPort = process.env.OIMDB_UI_PORT
10
- ? Number(process.env.OIMDB_UI_PORT)
11
- : 7433;
12
- const noOpen = process.argv.includes('--no-open');
13
- const uiDir = path.join(__dirname, '../ui');
14
- // Loopback unless told otherwise. This port hands out the application's
15
- // whole data model, so binding every interface — which is what happens when
16
- // no host is given — puts it on the café Wi-Fi.
17
- const host = process.env.OIMDB_HOST || '127.0.0.1';
18
- // Exact page origins, comma-separated. Never '*'.
19
- const allowedOrigins = (process.env.OIMDB_ALLOWED_ORIGINS || '')
20
- .split(',')
21
- .map(s => s.trim())
22
- .filter(Boolean);
23
-
24
- const server = new OIMDevUIServer({ wsPort, uiPort, uiDir, open: !noOpen, host, allowedOrigins });
25
- server.start();
26
- };
package/ui/app.css DELETED
@@ -1,323 +0,0 @@
1
- *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
2
-
3
- :root {
4
- --bg: #1e1e1e;
5
- --bg-panel: #252526;
6
- --bg-row: #2a2a2a;
7
- --bg-hover: #2e2e2e;
8
- --bg-input: #3c3c3c;
9
- --border: #3e3e42;
10
- --text: #d4d4d4;
11
- --text-dim: #808080;
12
- --text-hi: #f0f0f0;
13
- --accent: #4fc3f7;
14
- --green: #4caf50;
15
- --yellow: #ffb74d;
16
- --red: #ef5350;
17
- --gray: #616161;
18
- --tag-bg: #2d3f4a;
19
- --tag-warn: #4a2d2d;
20
- --radius: 4px;
21
- --mono: 'Menlo', 'Consolas', 'DejaVu Sans Mono', monospace;
22
- --toolbar-h: 40px;
23
- }
24
-
25
- html, body {
26
- height: 100%;
27
- background: var(--bg);
28
- color: var(--text);
29
- font: 13px/1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
30
- overflow: hidden;
31
- }
32
-
33
- /* ── Toolbar ──────────────────────────────────── */
34
-
35
- #toolbar {
36
- display: flex;
37
- align-items: center;
38
- gap: 16px;
39
- height: var(--toolbar-h);
40
- padding: 0 16px;
41
- background: var(--bg-panel);
42
- border-bottom: 1px solid var(--border);
43
- flex-shrink: 0;
44
- }
45
-
46
- .toolbar-brand { display: flex; align-items: baseline; gap: 6px; }
47
- .brand-name { font-weight: 700; font-size: 15px; color: var(--accent); letter-spacing: -0.3px; }
48
- .brand-sub { font-size: 11px; color: var(--text-dim); }
49
-
50
- .toolbar-status { display: flex; align-items: center; gap: 7px; flex: 1; }
51
-
52
- .conn-dot {
53
- width: 8px; height: 8px; border-radius: 50%;
54
- background: var(--gray); flex-shrink: 0;
55
- transition: background 0.3s;
56
- }
57
- .conn-dot.connected { background: var(--green); }
58
- .conn-dot.disconnected { background: var(--gray); }
59
-
60
- #conn-label { font-size: 12px; color: var(--text-dim); }
61
-
62
- .toolbar-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }
63
- #last-updated { font-size: 11px; color: var(--text-dim); }
64
-
65
- #btn-refresh {
66
- background: none; border: 1px solid var(--border); border-radius: var(--radius);
67
- color: var(--text); cursor: pointer; font-size: 16px; line-height: 1;
68
- padding: 2px 8px; transition: background 0.15s;
69
- }
70
- #btn-refresh:hover { background: var(--bg-input); }
71
-
72
- .auto-label {
73
- display: flex; align-items: center; gap: 5px;
74
- font-size: 12px; color: var(--text-dim); cursor: pointer; user-select: none;
75
- }
76
-
77
- /* ── Screens ──────────────────────────────────── */
78
-
79
- .hidden { display: none !important; }
80
-
81
- #screen-waiting {
82
- height: calc(100vh - var(--toolbar-h));
83
- display: flex; align-items: center; justify-content: center;
84
- }
85
-
86
- .waiting-card {
87
- max-width: 420px; padding: 28px 32px;
88
- background: var(--bg-panel); border: 1px solid var(--border);
89
- border-radius: 8px; text-align: center;
90
- }
91
- .waiting-title { font-size: 18px; font-weight: 600; color: var(--accent); margin-bottom: 14px; }
92
- .waiting-card p { color: var(--text-dim); margin-bottom: 10px; line-height: 1.6; }
93
- .waiting-card code {
94
- font-family: var(--mono); background: var(--bg-input);
95
- padding: 2px 6px; border-radius: 3px; color: var(--accent);
96
- }
97
- .waiting-card pre {
98
- font-family: var(--mono); font-size: 12px;
99
- background: var(--bg-row); border: 1px solid var(--border);
100
- border-radius: var(--radius); padding: 10px 14px;
101
- margin: 10px 0; text-align: left; color: var(--text);
102
- }
103
- .waiting-hint { font-size: 12px !important; }
104
-
105
- /* ── Two-column main ──────────────────────────── */
106
-
107
- #screen-main {
108
- display: flex;
109
- height: calc(100vh - var(--toolbar-h));
110
- }
111
-
112
- .col {
113
- flex: 1; display: flex; flex-direction: column;
114
- min-width: 0; overflow: hidden;
115
- border-right: 1px solid var(--border);
116
- }
117
- .col:last-child { border-right: none; }
118
-
119
- /* Right column split into computeds + history */
120
- #col-right { flex-direction: column; }
121
-
122
- .col-section {
123
- display: flex; flex-direction: column;
124
- flex: 1; min-height: 0; overflow: hidden;
125
- border-bottom: 1px solid var(--border);
126
- }
127
- .col-section:last-child { border-bottom: none; }
128
-
129
- .col-section-history { flex: 0 0 220px; }
130
-
131
- .col-body-flex { flex: 1; min-height: 0; overflow-y: auto; }
132
-
133
- .col-header {
134
- display: flex; align-items: center; gap: 7px;
135
- height: 32px; padding: 0 14px; flex-shrink: 0;
136
- background: var(--bg-panel); border-bottom: 1px solid var(--border);
137
- font-size: 11px; font-weight: 700; text-transform: uppercase;
138
- letter-spacing: 0.06em; color: var(--text-dim);
139
- }
140
-
141
- .badge {
142
- background: var(--bg-input); color: var(--text-dim);
143
- border-radius: 10px; padding: 0 7px;
144
- font-size: 10px; font-weight: 700; letter-spacing: 0;
145
- }
146
-
147
- .col-body { overflow-y: auto; flex: 1; }
148
-
149
- /* ── Collection rows ──────────────────────────── */
150
-
151
- .c-row { border-bottom: 1px solid var(--border); }
152
-
153
- .c-summary {
154
- display: flex; align-items: center; gap: 8px;
155
- padding: 7px 14px; cursor: pointer; user-select: none;
156
- background: var(--bg-row); transition: background 0.1s;
157
- }
158
- .c-summary:hover { background: var(--bg-hover); }
159
-
160
- .c-arrow {
161
- font-size: 9px; color: var(--text-dim); width: 10px;
162
- transition: transform 0.15s; flex-shrink: 0;
163
- }
164
- .c-arrow.open { transform: rotate(90deg); }
165
-
166
- .c-name {
167
- font-family: var(--mono); font-size: 13px;
168
- font-weight: 600; color: var(--text-hi); flex: 1;
169
- }
170
-
171
- .c-count { font-size: 11px; color: var(--text-dim); }
172
-
173
- .c-detail {
174
- display: none; padding: 8px 14px 0 32px;
175
- background: var(--bg); border-top: 1px solid var(--border);
176
- font-size: 11px; font-family: var(--mono);
177
- }
178
- .c-detail.open { display: block; }
179
-
180
- .d-row {
181
- display: flex; gap: 8px; margin-bottom: 4px;
182
- flex-wrap: wrap; align-items: flex-start;
183
- }
184
- .d-label { color: var(--text-dim); min-width: 72px; flex-shrink: 0; }
185
-
186
- .tag {
187
- display: inline-block; background: var(--tag-bg);
188
- color: var(--text); border-radius: 3px;
189
- padding: 1px 7px; margin: 1px 2px 1px 0; font-size: 11px;
190
- }
191
- .tag-warn { background: var(--tag-warn); color: #ffaa80; }
192
- .tag-rel-arrow { color: var(--accent); margin: 0 3px; }
193
-
194
- /* ── Entity table ─────────────────────────────── */
195
-
196
- .entity-wrap {
197
- margin: 8px 0 0 -18px;
198
- border-top: 1px solid var(--border);
199
- padding: 8px 0 10px 0;
200
- }
201
-
202
- .entity-table-wrap {
203
- overflow-x: auto;
204
- max-height: 280px;
205
- overflow-y: auto;
206
- }
207
-
208
- .entity-table {
209
- width: 100%;
210
- border-collapse: collapse;
211
- font-size: 11px;
212
- font-family: var(--mono);
213
- }
214
-
215
- .entity-table th {
216
- position: sticky; top: 0;
217
- background: var(--bg-panel);
218
- color: var(--text-dim);
219
- font-weight: 600;
220
- text-align: left;
221
- padding: 4px 10px;
222
- border-bottom: 1px solid var(--border);
223
- white-space: nowrap;
224
- }
225
-
226
- .entity-table td {
227
- padding: 3px 10px;
228
- border-bottom: 1px solid rgba(255,255,255,0.04);
229
- color: var(--text);
230
- white-space: nowrap;
231
- max-width: 200px;
232
- overflow: hidden;
233
- text-overflow: ellipsis;
234
- }
235
-
236
- .entity-table tbody tr:hover td { background: var(--bg-hover); }
237
-
238
- .entity-note {
239
- padding: 4px 10px;
240
- font-size: 10px;
241
- color: var(--text-dim);
242
- }
243
-
244
- /* ── Computed rows ────────────────────────────── */
245
-
246
- .comp-row {
247
- padding: 8px 14px; border-bottom: 1px solid var(--border);
248
- background: var(--bg-row); transition: background 0.1s;
249
- }
250
- .comp-row:hover { background: var(--bg-hover); }
251
-
252
- .comp-top { display: flex; align-items: center; gap: 8px; }
253
-
254
- .status-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
255
- .status-dot.fresh { background: var(--green); }
256
- .status-dot.stale { background: var(--yellow); }
257
- .status-dot.pending { background: var(--gray); }
258
-
259
- .comp-name {
260
- font-family: var(--mono); font-size: 13px;
261
- font-weight: 600; color: var(--text-hi); flex: 1;
262
- min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
263
- }
264
-
265
- .status-pill {
266
- font-size: 10px; font-weight: 700; letter-spacing: 0.06em;
267
- padding: 1px 8px; border-radius: 10px; flex-shrink: 0;
268
- }
269
- .status-pill.fresh { background: #1a3a1c; color: #81c784; }
270
- .status-pill.stale { background: #3a2a10; color: #ffcc80; }
271
- .status-pill.pending { background: #2a2a2a; color: #90a4ae; }
272
-
273
- .comp-value {
274
- font-family: var(--mono); font-size: 12px; color: var(--accent);
275
- max-width: 200px; overflow: hidden; text-overflow: ellipsis;
276
- white-space: nowrap; cursor: default;
277
- }
278
-
279
- .comp-deps {
280
- display: flex; flex-wrap: wrap; align-items: center;
281
- gap: 3px; margin-top: 5px; padding-left: 17px;
282
- }
283
- .comp-deps-label { font-size: 11px; color: var(--text-dim); margin-right: 4px; }
284
-
285
- /* ── Flush history ────────────────────────────── */
286
-
287
- .flush-row {
288
- display: flex; align-items: center; gap: 8px;
289
- padding: 4px 14px; border-bottom: 1px solid rgba(255,255,255,0.04);
290
- font-size: 11px; font-family: var(--mono);
291
- }
292
- .flush-row:hover { background: var(--bg-hover); }
293
-
294
- .flush-time { color: var(--text-dim); flex-shrink: 0; }
295
-
296
- .flush-tags { display: flex; flex-wrap: wrap; gap: 4px; }
297
-
298
- .flush-tag {
299
- padding: 1px 6px; border-radius: 3px;
300
- background: var(--bg-input); color: var(--text-dim);
301
- font-size: 10px;
302
- }
303
- .flush-add { background: #1a3a1c; color: #81c784; }
304
- .flush-del { background: #3a1a1a; color: #ef9a9a; }
305
- .flush-no-change { color: var(--text-dim); background: none; }
306
-
307
- /* ── Scrollbar ────────────────────────────────── */
308
-
309
- ::-webkit-scrollbar { width: 6px; height: 6px; }
310
- ::-webkit-scrollbar-track { background: var(--bg); }
311
- ::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
312
- ::-webkit-scrollbar-thumb:hover { background: #555; }
313
-
314
- /* ── Empty states ─────────────────────────────── */
315
-
316
- .empty {
317
- padding: 20px 16px; color: var(--text-dim);
318
- font-size: 12px; text-align: center; line-height: 1.7;
319
- }
320
- .empty code {
321
- font-family: var(--mono); background: var(--bg-input);
322
- padding: 1px 5px; border-radius: 3px; color: var(--accent);
323
- }