@ddtcorex/dsh-maestro-review 0.10.0 → 0.11.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.
Files changed (77) hide show
  1. package/README.md +10 -8
  2. package/cordis.patch.yml +4 -4
  3. package/lib/client.js +484 -0
  4. package/lib/config-store.d.ts +1 -1
  5. package/lib/config-store.d.ts.map +1 -1
  6. package/lib/config-store.js +43 -3
  7. package/lib/config-store.js.map +1 -1
  8. package/lib/govard-lint-detection.d.ts +20 -0
  9. package/lib/govard-lint-detection.d.ts.map +1 -0
  10. package/lib/govard-lint-detection.js +48 -0
  11. package/lib/govard-lint-detection.js.map +1 -0
  12. package/lib/orchestrator.d.ts +45 -9
  13. package/lib/orchestrator.d.ts.map +1 -1
  14. package/lib/orchestrator.js +79 -22
  15. package/lib/orchestrator.js.map +1 -1
  16. package/lib/search-tool.d.ts.map +1 -1
  17. package/lib/search-tool.js.map +1 -1
  18. package/lib/settings-rpc.d.ts +13 -11
  19. package/lib/settings-rpc.d.ts.map +1 -1
  20. package/lib/settings-rpc.js +45 -142
  21. package/lib/settings-rpc.js.map +1 -1
  22. package/lib/types/client/BrandMark.d.ts +22 -0
  23. package/lib/types/client/BrandMark.d.ts.map +1 -0
  24. package/lib/types/client/index.d.ts +12 -0
  25. package/lib/types/client/index.d.ts.map +1 -0
  26. package/lib/types/client/maestro-mark.d.ts +20 -0
  27. package/lib/types/client/maestro-mark.d.ts.map +1 -0
  28. package/lib/types/client/review/ReviewSettings.d.ts +15 -0
  29. package/lib/types/client/review/ReviewSettings.d.ts.map +1 -0
  30. package/lib/types/client/review/styles.d.ts +11 -0
  31. package/lib/types/client/review/styles.d.ts.map +1 -0
  32. package/lib/types/client/settings-nav-icon.d.ts +20 -0
  33. package/lib/types/client/settings-nav-icon.d.ts.map +1 -0
  34. package/lib/vendor/store.d.ts +60 -0
  35. package/lib/vendor/store.d.ts.map +1 -0
  36. package/lib/vendor/store.js +500 -0
  37. package/lib/vendor/store.js.map +1 -0
  38. package/lib/webhook-secret.d.ts +31 -0
  39. package/lib/webhook-secret.d.ts.map +1 -0
  40. package/lib/webhook-secret.js +38 -0
  41. package/lib/webhook-secret.js.map +1 -0
  42. package/package.json +24 -6
  43. package/presets/maestro-auditor.patch.yml +7 -4
  44. package/presets/maestro-coder/agent.cordis.yml +3 -11
  45. package/presets/maestro-coder/preset.yml +1 -1
  46. package/profiles/reviewer-ci/cordis.patch.yml +5 -4
  47. package/profiles/reviewer-ci/package.json +3 -3
  48. package/profiles/reviewer-ci/pnpm-lock.yaml +3524 -3239
  49. package/skills/dsh-native-tools/SKILL.md +5 -5
  50. package/src/client/BrandMark.tsx +42 -0
  51. package/src/client/index.tsx +109 -0
  52. package/src/client/maestro-mark.ts +21 -0
  53. package/src/client/review/ReviewSettings.tsx +236 -0
  54. package/src/client/review/styles.ts +108 -0
  55. package/src/client/settings-nav-icon.ts +68 -0
  56. package/src/host/config-store.ts +42 -3
  57. package/src/host/govard-lint-detection.ts +47 -0
  58. package/src/host/orchestrator.ts +95 -23
  59. package/src/host/search-tool.ts +3 -4
  60. package/src/host/settings-rpc.ts +48 -145
  61. package/src/host/vendor/store.ts +531 -0
  62. package/src/host/webhook-secret.ts +43 -0
  63. package/lib/govard-audit-lint-tool.d.ts +0 -95
  64. package/lib/govard-audit-lint-tool.d.ts.map +0 -1
  65. package/lib/govard-audit-lint-tool.js +0 -286
  66. package/lib/govard-audit-lint-tool.js.map +0 -1
  67. package/lib/govard-tool.d.ts +0 -11
  68. package/lib/govard-tool.d.ts.map +0 -1
  69. package/lib/govard-tool.js +0 -95
  70. package/lib/govard-tool.js.map +0 -1
  71. package/lib/workspace-tool.d.ts +0 -10
  72. package/lib/workspace-tool.d.ts.map +0 -1
  73. package/lib/workspace-tool.js +0 -92
  74. package/lib/workspace-tool.js.map +0 -1
  75. package/src/host/govard-audit-lint-tool.ts +0 -286
  76. package/src/host/govard-tool.ts +0 -114
  77. package/src/host/workspace-tool.ts +0 -108
@@ -0,0 +1,500 @@
1
+ // vendored from dsh-maestro-core store, sha256:ca062c527bb30c030c086751be275ee379071f33691568ff7d0eae4372012829
2
+ import { homedir } from 'node:os';
3
+ import { randomBytes } from 'node:crypto';
4
+ import { dirname, join } from 'node:path';
5
+ import { mkdir, open, readFile, rename, unlink, stat, rm, writeFile, link } from 'node:fs/promises';
6
+ import { mkdirSync, readFileSync } from 'node:fs';
7
+ import { watch } from 'node:fs';
8
+ const EMPTY_DOC = { version: 1, domains: {} };
9
+ const domainValidators = new Map();
10
+ const changeCbs = new Set();
11
+ let cached = null;
12
+ async function fileSig(path) {
13
+ try {
14
+ const st = await stat(path);
15
+ return { mtimeMs: st.mtimeMs, ino: st.ino, size: st.size };
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ function sameSig(a, b) {
22
+ return a !== null && b !== null && a.mtimeMs === b.mtimeMs && a.ino === b.ino && a.size === b.size;
23
+ }
24
+ function resolveDshHome(explicit) {
25
+ return explicit ?? process.env.DSH_HOME ?? join(homedir(), '.dsh');
26
+ }
27
+ function storePath(opts) {
28
+ return join(resolveDshHome(opts?.dshHome), 'dsh-maestro-config', 'settings.json');
29
+ }
30
+ /** Register a validator for a domain you own. Writes to it are validated on every set(). */
31
+ export function defineDomain(name, validator) {
32
+ domainValidators.set(name, validator);
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // change notification
36
+ // ---------------------------------------------------------------------------
37
+ /**
38
+ * Every plugin embeds its own copy of this module, so a listener has to hear
39
+ * writes made by another copy (or by another process), not only writes made
40
+ * through the copy that owns it. While at least one listener exists we watch
41
+ * the settings file and compare every domain against `snapshot`; a local write
42
+ * refreshes `snapshot` before it fires the callbacks, so it never fires twice.
43
+ *
44
+ * The watcher resolves DSH_HOME once, when it starts. A store pinned to an
45
+ * explicit `dshHome` therefore stays out of the watched home and neither fires
46
+ * nor receives notifications for writes that go somewhere else.
47
+ */
48
+ const WATCH_DEBOUNCE_MS = 50;
49
+ const POLL_MS = 2_000;
50
+ const FILE_BASENAME = 'settings.json';
51
+ let watcher = null;
52
+ let pollTimer = null;
53
+ let debounceTimer = null;
54
+ let snapshot = {};
55
+ let watchedHome = null;
56
+ let checking = false;
57
+ /** JSON text per domain, so a value change is a cheap string comparison. */
58
+ function fingerprint(doc) {
59
+ const out = {};
60
+ for (const [domain, value] of Object.entries(doc.domains)) {
61
+ out[domain] = JSON.stringify(value) ?? 'undefined';
62
+ }
63
+ return out;
64
+ }
65
+ /**
66
+ * Seed the snapshot synchronously so a write racing `onChange` cannot slip
67
+ * between "listener registered" and "snapshot taken" and go unnoticed.
68
+ */
69
+ function readSnapshotSync(home) {
70
+ try {
71
+ return fingerprint(parseDoc(readFileSync(storePath({ dshHome: home }), 'utf8')));
72
+ }
73
+ catch {
74
+ return {}; // no store on disk yet: every domain is new
75
+ }
76
+ }
77
+ /**
78
+ * Run every listener for one domain. Each callback gets its own try/catch: a
79
+ * throwing listener must neither reject the write that already committed nor
80
+ * hide the change from the listeners registered after it.
81
+ */
82
+ function fire(domain) {
83
+ for (const cb of [...changeCbs]) {
84
+ try {
85
+ cb(domain);
86
+ }
87
+ catch (err) {
88
+ console.warn(`config-lib: onChange callback for '${domain}' threw: ${err instanceof Error ? err.message : String(err)}`);
89
+ }
90
+ }
91
+ }
92
+ async function checkExternal() {
93
+ if (changeCbs.size === 0 || watchedHome === null || checking)
94
+ return;
95
+ checking = true;
96
+ try {
97
+ // load() invalidates its own cache on an mtime change, so this sees other
98
+ // writers' values without an extra stat.
99
+ const next = fingerprint(await load({ dshHome: watchedHome }));
100
+ const changed = [];
101
+ for (const domain of new Set([...Object.keys(snapshot), ...Object.keys(next)])) {
102
+ // A domain that disappeared compares against undefined and counts as changed.
103
+ if (snapshot[domain] !== next[domain])
104
+ changed.push(domain);
105
+ }
106
+ snapshot = next;
107
+ for (const domain of changed)
108
+ fire(domain);
109
+ }
110
+ catch {
111
+ // A transient read failure must never break boot; the next tick retries.
112
+ }
113
+ finally {
114
+ checking = false;
115
+ }
116
+ }
117
+ function scheduleCheck() {
118
+ if (debounceTimer)
119
+ clearTimeout(debounceTimer);
120
+ debounceTimer = setTimeout(() => {
121
+ debounceTimer = null;
122
+ void checkExternal();
123
+ }, WATCH_DEBOUNCE_MS);
124
+ debounceTimer.unref();
125
+ }
126
+ function stopWatching() {
127
+ watcher?.close();
128
+ watcher = null;
129
+ if (pollTimer)
130
+ clearInterval(pollTimer);
131
+ pollTimer = null;
132
+ if (debounceTimer)
133
+ clearTimeout(debounceTimer);
134
+ debounceTimer = null;
135
+ snapshot = {};
136
+ watchedHome = null;
137
+ }
138
+ function startWatching() {
139
+ if (watcher || pollTimer)
140
+ return;
141
+ const home = resolveDshHome();
142
+ const path = storePath({ dshHome: home });
143
+ watchedHome = home;
144
+ snapshot = readSnapshotSync(home);
145
+ try {
146
+ // fs.watch is not recursive, so it only sees the file when its own
147
+ // directory exists; the store is the only writer of that path either way.
148
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
149
+ const w = watch(dirname(path), { persistent: false }, (_event, filename) => {
150
+ if (filename === null || filename === FILE_BASENAME)
151
+ scheduleCheck();
152
+ });
153
+ // An unhandled 'error' event (EMFILE, directory removed, ...) would crash
154
+ // the host. Drop the watcher and let the poll below carry on alone.
155
+ w.on('error', () => {
156
+ try {
157
+ w.close();
158
+ }
159
+ catch { /* already closed */ }
160
+ if (watcher === w)
161
+ watcher = null;
162
+ });
163
+ watcher = w;
164
+ }
165
+ catch {
166
+ watcher = null; // polling below still covers the change
167
+ }
168
+ pollTimer = setInterval(() => void checkExternal(), POLL_MS);
169
+ pollTimer.unref();
170
+ }
171
+ /** Fire callbacks registered through this instance after a successful set(). */
172
+ export function onChange(cb) {
173
+ changeCbs.add(cb);
174
+ startWatching();
175
+ let disposed = false;
176
+ return () => {
177
+ if (disposed)
178
+ return;
179
+ disposed = true;
180
+ changeCbs.delete(cb);
181
+ if (changeCbs.size === 0)
182
+ stopWatching();
183
+ };
184
+ }
185
+ /** Test seam: drop the memoized document and listeners (schemas are kept). */
186
+ export function resetForTests() {
187
+ cached = null;
188
+ changeCbs.clear();
189
+ stopWatching();
190
+ }
191
+ // ---------------------------------------------------------------------------
192
+ // locking + io
193
+ // ---------------------------------------------------------------------------
194
+ /**
195
+ * Lock timing. A lock is only stolen once it is older than STALE_MS, which is
196
+ * deliberately longer than the time a waiter is willing to wait: a live writer
197
+ * that is merely slow must time its waiters out, never get robbed.
198
+ */
199
+ const LOCK_TIMEOUT_MS = 5_000;
200
+ const LOCK_STALE_MS = 30_000;
201
+ /** Settings directory: created 0700, lock file 0600 (the settings file is 0600 too). Modes apply at creation only; existing paths are never chmod-ed. */
202
+ const DIR_MODE = 0o700;
203
+ const FILE_MODE = 0o600;
204
+ /**
205
+ * Move a stale lock aside and delete it. rename() is atomic, so of several
206
+ * waiters only one moves the file. If the moved file turns out not to be the
207
+ * one we judged stale (a new owner took the path between our stat and the
208
+ * rename), it is put back with link(), which refuses to overwrite.
209
+ */
210
+ async function stealStaleLock(lockPath, observedIno) {
211
+ const aside = `${lockPath}.stale-${randomBytes(4).toString('hex')}`;
212
+ try {
213
+ await rename(lockPath, aside);
214
+ }
215
+ catch {
216
+ return; // someone else removed or stole it first
217
+ }
218
+ try {
219
+ const moved = await stat(aside);
220
+ if (moved.ino !== observedIno)
221
+ await link(aside, lockPath).catch(() => { });
222
+ }
223
+ catch {
224
+ /* nothing to restore */
225
+ }
226
+ finally {
227
+ await rm(aside, { force: true }).catch(() => { });
228
+ }
229
+ }
230
+ async function withLock(path, fn) {
231
+ await mkdir(dirname(path), { recursive: true, mode: DIR_MODE }); // the store dir may not exist on first write
232
+ const lockPath = `${path}.lock`;
233
+ const token = `${process.pid}-${randomBytes(8).toString('hex')}`;
234
+ const deadline = Date.now() + LOCK_TIMEOUT_MS;
235
+ for (;;) {
236
+ try {
237
+ const handle = await open(lockPath, 'wx', FILE_MODE);
238
+ try {
239
+ await handle.writeFile(token);
240
+ }
241
+ finally {
242
+ await handle.close();
243
+ }
244
+ break;
245
+ }
246
+ catch (err) {
247
+ if (err?.code !== 'EEXIST')
248
+ throw err;
249
+ // Break stale locks left behind by a crashed writer.
250
+ try {
251
+ const st = await stat(lockPath);
252
+ if (Date.now() - st.mtimeMs > LOCK_STALE_MS) {
253
+ await stealStaleLock(lockPath, st.ino);
254
+ continue;
255
+ }
256
+ }
257
+ catch {
258
+ /* lock vanished between stat and now — just retry */
259
+ }
260
+ if (Date.now() > deadline)
261
+ throw new Error(`config-lib: lock timeout at ${lockPath}`);
262
+ await new Promise((r) => setTimeout(r, 20));
263
+ }
264
+ }
265
+ try {
266
+ return await fn();
267
+ }
268
+ finally {
269
+ // Only release a lock that is still ours: if it was stolen and re-acquired
270
+ // meanwhile, deleting it would break the new owner's mutual exclusion.
271
+ try {
272
+ if ((await readFile(lockPath, 'utf8')) === token)
273
+ await unlink(lockPath);
274
+ }
275
+ catch {
276
+ /* already gone */
277
+ }
278
+ }
279
+ }
280
+ function parseDoc(raw) {
281
+ const parsed = JSON.parse(raw);
282
+ if (typeof parsed !== 'object' || parsed === null || typeof parsed.version !== 'number') {
283
+ throw new Error('config-lib: malformed settings document');
284
+ }
285
+ return { version: 1, domains: parsed.domains ?? {} };
286
+ }
287
+ async function readDoc(path) {
288
+ let raw;
289
+ try {
290
+ raw = await readFile(path, 'utf8');
291
+ }
292
+ catch (err) {
293
+ if (err?.code === 'ENOENT')
294
+ return { ...EMPTY_DOC, domains: {} };
295
+ throw err;
296
+ }
297
+ return parseDoc(raw);
298
+ }
299
+ function deepMerge(base, patch) {
300
+ if (base !== null && typeof base === 'object' && !Array.isArray(base) &&
301
+ patch !== null && typeof patch === 'object' && !Array.isArray(patch)) {
302
+ const out = { ...base };
303
+ for (const [k, v] of Object.entries(patch)) {
304
+ out[k] = k in out ? deepMerge(out[k], v) : v;
305
+ }
306
+ return out;
307
+ }
308
+ return patch;
309
+ }
310
+ async function writeDocLocked(path, doc) {
311
+ await mkdir(dirname(path), { recursive: true, mode: DIR_MODE });
312
+ const tmp = `${path}.tmp-${Math.random().toString(16).slice(2, 10)}`;
313
+ try {
314
+ await writeFile(tmp, JSON.stringify(doc, null, 2) + '\n', { mode: FILE_MODE });
315
+ await rename(tmp, path); // atomic on the same filesystem; rename carries the 600 mode
316
+ }
317
+ finally {
318
+ // After a successful rename the temp name is gone and this is a no-op; after
319
+ // a failed write or rename it removes the orphan instead of leaking one per try.
320
+ await rm(tmp, { force: true }).catch(() => { });
321
+ }
322
+ }
323
+ // ---------------------------------------------------------------------------
324
+ // public API
325
+ // ---------------------------------------------------------------------------
326
+ export async function load(opts) {
327
+ const path = storePath(opts);
328
+ const homeKey = resolveDshHome(opts?.dshHome);
329
+ if (cached && cached.key === homeKey) {
330
+ // One stat per load: out-of-band edits (other processes) must surface
331
+ // without a restart.
332
+ const now = await fileSig(path);
333
+ if (now === null)
334
+ return cached.doc; // stat failed (vanished/locked) — serve stale, never break boot
335
+ if (sameSig(now, cached.sig))
336
+ return cached.doc;
337
+ }
338
+ const doc = await readDoc(path);
339
+ cached = { key: homeKey, doc, sig: await fileSig(path) };
340
+ return doc;
341
+ }
342
+ export async function get(domain, opts) {
343
+ const doc = await load(opts);
344
+ return doc.domains[domain];
345
+ }
346
+ export async function set(domain, patch, opts) {
347
+ const path = storePath(opts);
348
+ const key = resolveDshHome(opts?.dshHome);
349
+ let written;
350
+ await withLock(path, async () => {
351
+ const doc = await readDoc(path);
352
+ const validator = domainValidators.get(domain);
353
+ const merged = deepMerge(doc.domains[domain], patch);
354
+ if (validator) {
355
+ const res = validator.parse(merged);
356
+ if (!res.ok)
357
+ throw new Error(`config-lib: validation failed for '${domain}': ${res.error}`);
358
+ }
359
+ doc.domains[domain] = merged;
360
+ written = merged;
361
+ await writeDocLocked(path, doc);
362
+ cached = { key, doc, sig: await fileSig(path) };
363
+ });
364
+ // Refresh the watched copy first so the watcher sees no diff for this write.
365
+ if (watchedHome === key)
366
+ snapshot[domain] = JSON.stringify(written) ?? 'undefined';
367
+ fire(domain);
368
+ }
369
+ /**
370
+ * Delete one TOP-LEVEL key of a domain — the delete operation `set()` cannot
371
+ * express (a merge patch has no delete signal: `null` persists as null).
372
+ * Dotted paths are rejected to keep the semantics exactly one key. No-op
373
+ * (`false`, no write, no callbacks) when the domain is absent/not an object
374
+ * or the key is absent. Otherwise the resulting domain is validated like a
375
+ * `set()` before the atomic write; `true` means the key is gone.
376
+ */
377
+ export async function unset(domain, key, opts) {
378
+ if (typeof key !== 'string' || key === '' || key.includes('.')) {
379
+ throw new Error(`config-lib: unset key must be a top-level name, got ${JSON.stringify(key)}`);
380
+ }
381
+ const path = storePath(opts);
382
+ const homeKey = resolveDshHome(opts?.dshHome);
383
+ let written;
384
+ const deleted = await withLock(path, async () => {
385
+ const doc = await readDoc(path);
386
+ const bucket = doc.domains[domain];
387
+ if (typeof bucket !== 'object' || bucket === null || Array.isArray(bucket))
388
+ return false;
389
+ if (!(key in bucket))
390
+ return false;
391
+ const next = { ...bucket };
392
+ delete next[key];
393
+ const validator = domainValidators.get(domain);
394
+ if (validator) {
395
+ const res = validator.parse(next);
396
+ if (!res.ok)
397
+ throw new Error(`config-lib: validation failed for '${domain}': ${res.error}`);
398
+ }
399
+ doc.domains[domain] = next;
400
+ written = next;
401
+ await writeDocLocked(path, doc);
402
+ cached = { key: homeKey, doc, sig: await fileSig(path) };
403
+ return true;
404
+ });
405
+ if (deleted) {
406
+ if (watchedHome === homeKey)
407
+ snapshot[domain] = JSON.stringify(written) ?? 'undefined';
408
+ fire(domain);
409
+ }
410
+ return deleted;
411
+ }
412
+ /** Names of domains registered via defineDomain (schema owners). */
413
+ export function definedDomains() {
414
+ return [...domainValidators.keys()];
415
+ }
416
+ // ---------------------------------------------------------------------------
417
+ // flat-key adapter map (live: remote/review/supervisor read through readFlat)
418
+ // ---------------------------------------------------------------------------
419
+ export const DOMAIN_KEY_MAP = {
420
+ gitlabBaseUrl: 'gitlab.baseUrl',
421
+ gitlabToken: 'gitlab.token',
422
+ botUsername: 'gitlab.botUsername',
423
+ webhookSecret: 'gitlab.webhookSecret',
424
+ webhookPort: 'gitlab.webhookPort',
425
+ projectMappings: 'gitlab.projectMappings',
426
+ autoRereviewOnPush: 'gitlab.autoRereviewOnPush',
427
+ autoReviewOnAssign: 'gitlab.autoReviewOnAssign',
428
+ reviewModel: 'review.model',
429
+ agentTimeoutMs: 'review.agentTimeoutMs',
430
+ reviewSessionRetentionDays: 'review.sessionRetentionDays',
431
+ tunnelHostname: 'tunnel.hostname',
432
+ tunnelCredentialsFile: 'tunnel.credentialsFile',
433
+ tunnelId: 'tunnel.id',
434
+ tunnelMode: 'tunnel.mode',
435
+ quickTarget: 'tunnel.quickTarget',
436
+ proxyPort: 'tunnel.proxyPort',
437
+ proxyHost: 'tunnel.proxyHost',
438
+ lanPinEnabled: 'tunnel.lanPinEnabled',
439
+ lanPort: 'tunnel.lanPort',
440
+ lanHost: 'tunnel.lanHost',
441
+ /** Login-cookie lifetime in hours for the remote PIN gate (0 = session cookie). */
442
+ pinSessionTtlHours: 'tunnel.pinSessionTtlHours',
443
+ telegramBotToken: 'notifier.telegram.botToken',
444
+ telegramChatId: 'notifier.telegram.chatId',
445
+ telegramReviewNotifications: 'notifier.policy.reviewNotifications',
446
+ };
447
+ /** Machine runtime state — never settings; owning adapters persist these in their own sidecar. */
448
+ export const RUNTIME_KEYS = ['lastTunnelRunning'];
449
+ function setIn(obj, dotted, value) {
450
+ const parts = dotted.split('.');
451
+ let cur = obj;
452
+ for (const part of parts.slice(0, -1)) {
453
+ if (typeof cur[part] !== 'object' || cur[part] === null)
454
+ cur[part] = {};
455
+ cur = cur[part];
456
+ }
457
+ cur[parts[parts.length - 1]] = value;
458
+ }
459
+ /** Route a flat legacy-keyed patch into per-domain writes; runtime keys are skipped. */
460
+ export function splitLegacyPatch(patch) {
461
+ const byDomain = new Map();
462
+ for (const [key, value] of Object.entries(patch)) {
463
+ if (RUNTIME_KEYS.includes(key))
464
+ continue;
465
+ const dotted = DOMAIN_KEY_MAP[key];
466
+ if (!dotted)
467
+ continue;
468
+ const domain = dotted.split('.')[0];
469
+ const group = byDomain.get(domain) ?? {};
470
+ setIn(group, dotted.slice(domain.length + 1), value);
471
+ byDomain.set(domain, group);
472
+ }
473
+ return [...byDomain].map(([domain, patch]) => ({ domain, patch }));
474
+ }
475
+ /** Write a flat legacy-keyed patch through the domain store (multiple atomic set()s). */
476
+ export async function writeLegacyPatch(patch, opts) {
477
+ for (const { domain, patch: group } of splitLegacyPatch(patch)) {
478
+ await set(domain, group, opts);
479
+ }
480
+ }
481
+ /** Inverse view: domains flattened back into legacy key names (undefined keys omitted). */
482
+ export async function readFlat(opts) {
483
+ const doc = await load(opts);
484
+ const flat = {};
485
+ for (const [key, dotted] of Object.entries(DOMAIN_KEY_MAP)) {
486
+ let cur = doc.domains;
487
+ for (const part of dotted.split('.')) {
488
+ if (cur !== null && typeof cur === 'object')
489
+ cur = cur[part];
490
+ else {
491
+ cur = undefined;
492
+ break;
493
+ }
494
+ }
495
+ if (cur !== undefined)
496
+ flat[key] = cur;
497
+ }
498
+ return flat;
499
+ }
500
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/host/vendor/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Webhook secret generation and the URL an operator pastes into GitLab.
3
+ *
4
+ * Parked at the meta root when the Maestro settings card lost its GitLab tab,
5
+ * and never ported: `review` kept the secret FIELD in its own settings section
6
+ * but had no way to produce a value for it, so the operator had to invent a
7
+ * 32-character base64url string by hand. A pasted secret with a `+`, a `/` or
8
+ * a `=` is a common outcome, and those characters are exactly what GitLab's
9
+ * token comparison and a URL path segment cannot carry.
10
+ */
11
+ /** The merge-request webhook path this plugin serves. */
12
+ export declare const GITLAB_WEBHOOK_PATH = "/hooks/gitlab-mr";
13
+ /**
14
+ * Generate an opaque 256-bit secret suitable for GitLab's webhook token.
15
+ *
16
+ * Each byte contributes 6 bits (`byte & 0b00111111`), so the result is always
17
+ * 32 base64url characters with no padding and no character outside the
18
+ * alphabet — the two properties GitLab's comparison and a URL path segment
19
+ * both need. The randomness source is injectable so the mapping is testable
20
+ * without weakening the production path.
21
+ */
22
+ export declare function generateWebhookSecret(randomValues?: (array: Uint8Array) => Uint8Array): string;
23
+ /**
24
+ * GitLab's merge-request webhook endpoint for the configured public hostname.
25
+ *
26
+ * A user pasting the value back out of the settings field usually brings a
27
+ * scheme and a trailing slash with it, so both are stripped. An absent
28
+ * hostname names itself rather than producing a URL that looks real.
29
+ */
30
+ export declare function gitlabWebhookUrl(hostname?: string): string;
31
+ //# sourceMappingURL=webhook-secret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-secret.d.ts","sourceRoot":"","sources":["../src/host/webhook-secret.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,qBAAqB,CAAA;AAErD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,GAAE,CAAC,KAAK,EAAE,UAAU,KAAK,UAAsE,GAC1G,MAAM,CAGR;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAG1D"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Webhook secret generation and the URL an operator pastes into GitLab.
3
+ *
4
+ * Parked at the meta root when the Maestro settings card lost its GitLab tab,
5
+ * and never ported: `review` kept the secret FIELD in its own settings section
6
+ * but had no way to produce a value for it, so the operator had to invent a
7
+ * 32-character base64url string by hand. A pasted secret with a `+`, a `/` or
8
+ * a `=` is a common outcome, and those characters are exactly what GitLab's
9
+ * token comparison and a URL path segment cannot carry.
10
+ */
11
+ const BASE64URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
12
+ /** The merge-request webhook path this plugin serves. */
13
+ export const GITLAB_WEBHOOK_PATH = '/hooks/gitlab-mr';
14
+ /**
15
+ * Generate an opaque 256-bit secret suitable for GitLab's webhook token.
16
+ *
17
+ * Each byte contributes 6 bits (`byte & 0b00111111`), so the result is always
18
+ * 32 base64url characters with no padding and no character outside the
19
+ * alphabet — the two properties GitLab's comparison and a URL path segment
20
+ * both need. The randomness source is injectable so the mapping is testable
21
+ * without weakening the production path.
22
+ */
23
+ export function generateWebhookSecret(randomValues = globalThis.crypto.getRandomValues.bind(globalThis.crypto)) {
24
+ const bytes = randomValues(new Uint8Array(32));
25
+ return Array.from(bytes, byte => BASE64URL_ALPHABET[byte & 0b00111111]).join('');
26
+ }
27
+ /**
28
+ * GitLab's merge-request webhook endpoint for the configured public hostname.
29
+ *
30
+ * A user pasting the value back out of the settings field usually brings a
31
+ * scheme and a trailing slash with it, so both are stripped. An absent
32
+ * hostname names itself rather than producing a URL that looks real.
33
+ */
34
+ export function gitlabWebhookUrl(hostname) {
35
+ const authority = hostname?.trim().replace(/^https?:\/\//, '').replace(/\/+$/, '') || '<your-hostname>';
36
+ return `https://${authority}${GITLAB_WEBHOOK_PATH}`;
37
+ }
38
+ //# sourceMappingURL=webhook-secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-secret.js","sourceRoot":"","sources":["../src/host/webhook-secret.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,kBAAkB,GAAG,kEAAkE,CAAA;AAE7F,yDAAyD;AACzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAA;AAErD;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,eAAkD,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAE3G,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAClF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAiB;IAChD,MAAM,SAAS,GAAG,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,iBAAiB,CAAA;IACvG,OAAO,WAAW,SAAS,GAAG,mBAAmB,EAAE,CAAA;AACrD,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ddtcorex/dsh-maestro-review",
3
3
  "private": false,
4
- "version": "0.10.0",
4
+ "version": "0.11.0",
5
5
  "description": "Maestro Review — pluggable ReviewProvider (GitLab/GitHub) + orchestrator for automated MR review",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -17,7 +17,11 @@
17
17
  "exports": {
18
18
  ".": "./lib/index.js",
19
19
  "./lib/*": "./lib/*",
20
- "./package.json": "./package.json"
20
+ "./package.json": "./package.json",
21
+ "./client": {
22
+ "types": "./lib/types/client/index.d.ts",
23
+ "default": "./lib/client.js"
24
+ }
21
25
  },
22
26
  "files": [
23
27
  "README.md",
@@ -35,7 +39,6 @@
35
39
  "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.6 || >=0.1.1-rc.0 <0.3.0-0"
36
40
  },
37
41
  "dependencies": {
38
- "@ddtcorex/dsh-maestro-config-lib": "^0.3.0",
39
42
  "@deepseek-ai/schemastery": "~3.18.4"
40
43
  },
41
44
  "devDependencies": {
@@ -50,7 +53,15 @@
50
53
  "@deepseek-ai/dsh-session-title": "0.2.0-rc.2",
51
54
  "@deepseek-ai/dsh-subagent": "0.2.0-rc.2",
52
55
  "@deepseek-ai/dsh-tools": "0.2.0-rc.2",
56
+ "@testing-library/jest-dom": "^7.0.1",
57
+ "@testing-library/react": "^16.3.3",
53
58
  "@types/node": "^22.0.0",
59
+ "@types/react": "~18.3.1",
60
+ "@types/react-dom": "~18.3.0",
61
+ "esbuild": "^0.25.12",
62
+ "jsdom": "^30.0.1",
63
+ "react": "^18.3.1",
64
+ "react-dom": "^18.3.1",
54
65
  "typescript": "^5.8.0",
55
66
  "vitest": "^3.2.4",
56
67
  "yaml": "^2.9.0"
@@ -62,12 +73,19 @@
62
73
  "./presets/maestro-reviewer.patch.yml",
63
74
  "./presets/maestro-auditor.patch.yml"
64
75
  ]
76
+ },
77
+ "client": {
78
+ "platform": "web",
79
+ "inject": [
80
+ "@deepseek-ai/dsh-client-connection",
81
+ "@deepseek-ai/dsh-client-ui-slots"
82
+ ]
65
83
  }
66
84
  },
67
85
  "scripts": {
68
- "build": "tsc",
69
- "test": "vitest run",
70
- "verify": "tsc --noEmit",
86
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.client.json && node scripts/build-client.mjs",
87
+ "test": "NODE_ENV=test vitest run",
88
+ "verify": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
71
89
  "docker:build": "docker build -f docker/Dockerfile -t ddtcorex/maestro-reviewer:0.10.0 -t ddtcorex/maestro-reviewer:latest ."
72
90
  }
73
91
  }