@useorgx/openclaw-plugin 0.4.3 → 0.4.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.
@@ -9,12 +9,12 @@
9
9
  <meta name="googlebot" content="noindex, nofollow, noarchive, nosnippet, noimageindex" />
10
10
  <meta name="copyright" content="OrgX. All rights reserved." />
11
11
  <title>OrgX Live Dashboard</title>
12
- <script type="module" crossorigin src="/orgx/live/assets/X6IcjS74.js"></script>
12
+ <script type="module" crossorigin src="/orgx/live/assets/DNjbmawF.js"></script>
13
13
  <link rel="modulepreload" crossorigin href="/orgx/live/assets/C-KIc3Wc.js">
14
- <link rel="modulepreload" crossorigin href="/orgx/live/assets/Cpr7n8fE.js">
15
- <link rel="modulepreload" crossorigin href="/orgx/live/assets/BqukHQH-.js">
16
- <link rel="modulepreload" crossorigin href="/orgx/live/assets/CE5pVdev.js">
17
- <link rel="stylesheet" crossorigin href="/orgx/live/assets/jyFhCND-.css">
14
+ <link rel="modulepreload" crossorigin href="/orgx/live/assets/BZZ-fiJx.js">
15
+ <link rel="modulepreload" crossorigin href="/orgx/live/assets/DD1jv1Hd.js">
16
+ <link rel="modulepreload" crossorigin href="/orgx/live/assets/BoXlCHKa.js">
17
+ <link rel="stylesheet" crossorigin href="/orgx/live/assets/Bq9x_Xyh.css">
18
18
  </head>
19
19
  <body class="bg-[#080808] text-white antialiased">
20
20
  <div id="root"></div>
@@ -201,16 +201,36 @@ export class OrgXClient {
201
201
  // Spawn Guard (Quality Gate + Model Routing)
202
202
  // ===========================================================================
203
203
  async checkSpawnGuard(domain, taskId) {
204
- return this.post("/api/client/spawn", {
204
+ const response = await this.post("/api/client/spawn", {
205
205
  domain,
206
206
  taskId,
207
207
  });
208
+ // Newer servers wrap responses in { ok, data } while older clients expect the
209
+ // SpawnGuardResult fields at top-level.
210
+ if (response &&
211
+ typeof response === "object" &&
212
+ "data" in response &&
213
+ response.data) {
214
+ return response.data;
215
+ }
216
+ return response;
208
217
  }
209
218
  // ===========================================================================
210
219
  // Quality Scores
211
220
  // ===========================================================================
212
221
  async recordQuality(score) {
213
- return this.post("/api/client/quality", score);
222
+ const response = await this.post("/api/client/quality", score);
223
+ // Backwards-compatible: accept either { success: true } or { ok: true, data: ... }.
224
+ if (response &&
225
+ typeof response === "object" &&
226
+ "success" in response &&
227
+ typeof response.success === "boolean") {
228
+ return response;
229
+ }
230
+ if (response && typeof response === "object" && "ok" in response) {
231
+ return { success: Boolean(response.ok) };
232
+ }
233
+ return { success: true };
214
234
  }
215
235
  // ===========================================================================
216
236
  // Entity CRUD
@@ -2214,13 +2214,22 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
2214
2214
  type: "progress",
2215
2215
  timestamp,
2216
2216
  payload: {
2217
- phase: input.phase,
2217
+ // Keep this payload aligned with OrgXClient.emitActivity input
2218
+ // so outbox replay can forward it without shape translation.
2219
+ initiative_id: initiativeId,
2220
+ run_id: input.runId?.trim() || undefined,
2221
+ correlation_id: input.runId
2222
+ ? undefined
2223
+ : (input.correlationId?.trim() || `openclaw-${Date.now()}`),
2224
+ source_client: "openclaw",
2218
2225
  message,
2226
+ phase: input.phase,
2227
+ progress_pct: typeof input.progressPct === "number" && Number.isFinite(input.progressPct)
2228
+ ? Math.max(0, Math.min(100, Math.round(input.progressPct)))
2229
+ : undefined,
2219
2230
  level: input.level ?? "info",
2220
- runId,
2221
- initiativeId,
2222
- nextStep: input.nextStep ?? null,
2223
- metadata: input.metadata ?? null,
2231
+ next_step: input.nextStep ?? undefined,
2232
+ metadata: input.metadata ?? undefined,
2224
2233
  },
2225
2234
  activityItem,
2226
2235
  });
package/dist/index.js CHANGED
@@ -22,6 +22,10 @@ import { clearPersistedSnapshot, readPersistedSnapshot, writePersistedSnapshot,
22
22
  import { appendToOutbox, readOutbox, readOutboxSummary, replaceOutbox, } from "./outbox.js";
23
23
  import { extractProgressOutboxMessage } from "./reporting/outbox-replay.js";
24
24
  import { ensureGatewayWatchdog } from "./gateway-watchdog.js";
25
+ import { createMcpHttpHandler } from "./mcp-http-handler.js";
26
+ import { autoConfigureDetectedMcpClients } from "./mcp-client-setup.js";
27
+ import { readOpenClawGatewayPort, readOpenClawSettingsSnapshot } from "./openclaw-settings.js";
28
+ import { posthogCapture } from "./telemetry/posthog.js";
25
29
  export { OrgXClient } from "./api.js";
26
30
  const DEFAULT_BASE_URL = "https://www.useorgx.com";
27
31
  const DEFAULT_DOCS_URL = "https://orgx.mintlify.site/guides/openclaw-plugin-setup";
@@ -325,6 +329,19 @@ export default function register(api) {
325
329
  api.log?.info?.("[orgx] Plugin disabled");
326
330
  return;
327
331
  }
332
+ void posthogCapture({
333
+ event: "openclaw_plugin_loaded",
334
+ distinctId: config.installationId,
335
+ properties: {
336
+ plugin_version: config.pluginVersion,
337
+ dashboard_enabled: config.dashboardEnabled,
338
+ has_api_key: Boolean(config.apiKey),
339
+ api_key_source: config.apiKeySource,
340
+ base_url: config.baseUrl,
341
+ },
342
+ }).catch(() => {
343
+ // best effort
344
+ });
328
345
  if (!config.apiKey) {
329
346
  api.log?.warn?.("[orgx] No API key. Set plugins.entries.orgx.config.apiKey, ORGX_API_KEY env, or ~/Code/orgx/orgx/.env.local");
330
347
  }
@@ -350,14 +367,14 @@ export default function register(api) {
350
367
  const defaultReportingCorrelationId = pickNonEmptyString(process.env.ORGX_CORRELATION_ID) ??
351
368
  `openclaw-${config.installationId}`;
352
369
  function resolveReportingContext(input) {
353
- const initiativeId = pickNonEmptyString(input.initiative_id, process.env.ORGX_INITIATIVE_ID);
370
+ const initiativeId = pickNonEmptyString(input.initiative_id, input.initiativeId, process.env.ORGX_INITIATIVE_ID);
354
371
  if (!initiativeId || !isUuid(initiativeId)) {
355
372
  return {
356
373
  ok: false,
357
374
  error: "initiative_id is required (set ORGX_INITIATIVE_ID or pass initiative_id).",
358
375
  };
359
376
  }
360
- const sourceCandidate = pickNonEmptyString(input.source_client, process.env.ORGX_SOURCE_CLIENT, "openclaw");
377
+ const sourceCandidate = pickNonEmptyString(input.source_client, input.sourceClient, process.env.ORGX_SOURCE_CLIENT, "openclaw");
361
378
  const sourceClient = sourceCandidate === "codex" ||
362
379
  sourceCandidate === "claude-code" ||
363
380
  sourceCandidate === "api" ||
@@ -368,7 +385,10 @@ export default function register(api) {
368
385
  const runId = isUuid(runIdCandidate) ? runIdCandidate : undefined;
369
386
  const correlationId = runId
370
387
  ? undefined
371
- : pickNonEmptyString(input.correlation_id, defaultReportingCorrelationId, `openclaw-${Date.now()}`);
388
+ : pickNonEmptyString(input.correlation_id, input.correlationId,
389
+ // Legacy: some buffered payloads only stored a local `runId` which is
390
+ // better treated as a correlation key than a server-backed run_id.
391
+ input.runId, defaultReportingCorrelationId, `openclaw-${Date.now()}`);
372
392
  return {
373
393
  ok: true,
374
394
  value: {
@@ -391,6 +411,140 @@ export default function register(api) {
391
411
  return err.message;
392
412
  return typeof err === "string" ? err : "Unexpected error";
393
413
  }
414
+ const registerTool = api.registerTool.bind(api);
415
+ api.registerTool = (tool, options) => {
416
+ const toolName = tool.name;
417
+ const optional = Boolean(options?.optional);
418
+ registerTool({
419
+ ...tool,
420
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
421
+ execute: async (callId, params) => {
422
+ const startedAt = Date.now();
423
+ void posthogCapture({
424
+ event: "openclaw_tool_called",
425
+ distinctId: config.installationId,
426
+ properties: {
427
+ tool_name: toolName,
428
+ tool_optional: optional,
429
+ call_id: callId,
430
+ plugin_version: config.pluginVersion,
431
+ },
432
+ }).catch(() => {
433
+ // best effort
434
+ });
435
+ try {
436
+ const result = await tool.execute(callId, params);
437
+ const durationMs = Date.now() - startedAt;
438
+ void posthogCapture({
439
+ event: "openclaw_tool_succeeded",
440
+ distinctId: config.installationId,
441
+ properties: {
442
+ tool_name: toolName,
443
+ tool_optional: optional,
444
+ call_id: callId,
445
+ duration_ms: durationMs,
446
+ plugin_version: config.pluginVersion,
447
+ },
448
+ }).catch(() => {
449
+ // best effort
450
+ });
451
+ return result;
452
+ }
453
+ catch (err) {
454
+ const durationMs = Date.now() - startedAt;
455
+ void posthogCapture({
456
+ event: "openclaw_tool_failed",
457
+ distinctId: config.installationId,
458
+ properties: {
459
+ tool_name: toolName,
460
+ tool_optional: optional,
461
+ call_id: callId,
462
+ duration_ms: durationMs,
463
+ plugin_version: config.pluginVersion,
464
+ error: toErrorMessage(err),
465
+ },
466
+ }).catch(() => {
467
+ // best effort
468
+ });
469
+ throw err;
470
+ }
471
+ },
472
+ }, options);
473
+ };
474
+ const registerService = api.registerService.bind(api);
475
+ api.registerService = (service) => {
476
+ registerService({
477
+ ...service,
478
+ start: async () => {
479
+ const startedAt = Date.now();
480
+ try {
481
+ await service.start();
482
+ const durationMs = Date.now() - startedAt;
483
+ void posthogCapture({
484
+ event: "openclaw_service_started",
485
+ distinctId: config.installationId,
486
+ properties: {
487
+ service_id: service.id,
488
+ duration_ms: durationMs,
489
+ plugin_version: config.pluginVersion,
490
+ },
491
+ }).catch(() => {
492
+ // best effort
493
+ });
494
+ }
495
+ catch (err) {
496
+ const durationMs = Date.now() - startedAt;
497
+ void posthogCapture({
498
+ event: "openclaw_service_start_failed",
499
+ distinctId: config.installationId,
500
+ properties: {
501
+ service_id: service.id,
502
+ duration_ms: durationMs,
503
+ plugin_version: config.pluginVersion,
504
+ error: toErrorMessage(err),
505
+ },
506
+ }).catch(() => {
507
+ // best effort
508
+ });
509
+ throw err;
510
+ }
511
+ },
512
+ stop: async () => {
513
+ const startedAt = Date.now();
514
+ try {
515
+ await service.stop();
516
+ const durationMs = Date.now() - startedAt;
517
+ void posthogCapture({
518
+ event: "openclaw_service_stopped",
519
+ distinctId: config.installationId,
520
+ properties: {
521
+ service_id: service.id,
522
+ duration_ms: durationMs,
523
+ plugin_version: config.pluginVersion,
524
+ },
525
+ }).catch(() => {
526
+ // best effort
527
+ });
528
+ }
529
+ catch (err) {
530
+ const durationMs = Date.now() - startedAt;
531
+ void posthogCapture({
532
+ event: "openclaw_service_stop_failed",
533
+ distinctId: config.installationId,
534
+ properties: {
535
+ service_id: service.id,
536
+ duration_ms: durationMs,
537
+ plugin_version: config.pluginVersion,
538
+ error: toErrorMessage(err),
539
+ },
540
+ }).catch(() => {
541
+ // best effort
542
+ });
543
+ throw err;
544
+ }
545
+ },
546
+ });
547
+ };
394
548
  function clearPairingState() {
395
549
  activePairing = null;
396
550
  updateOnboardingState({
@@ -474,6 +628,23 @@ export default function register(api) {
474
628
  installationId: config.installationId,
475
629
  workspaceName: input.workspaceName ?? onboardingState.workspaceName,
476
630
  });
631
+ if (input.source === "browser_pairing" &&
632
+ process.env.ORGX_DISABLE_MCP_CLIENT_AUTOCONFIG !== "1") {
633
+ try {
634
+ const snapshot = readOpenClawSettingsSnapshot();
635
+ const port = readOpenClawGatewayPort(snapshot.raw);
636
+ const localMcpUrl = `http://127.0.0.1:${port}/orgx/mcp`;
637
+ void autoConfigureDetectedMcpClients({
638
+ localMcpUrl,
639
+ logger: api.log ?? {},
640
+ }).catch(() => {
641
+ // best effort
642
+ });
643
+ }
644
+ catch {
645
+ // best effort
646
+ }
647
+ }
477
648
  }
478
649
  // ---------------------------------------------------------------------------
479
650
  // 1. Background Sync Service
@@ -481,7 +652,6 @@ export default function register(api) {
481
652
  let syncTimer = null;
482
653
  let syncInFlight = null;
483
654
  let syncServiceRunning = false;
484
- const outboxQueues = ["progress", "decisions", "artifacts"];
485
655
  let outboxReplayState = {
486
656
  status: "idle",
487
657
  lastReplayAttemptAt: null,
@@ -661,7 +831,11 @@ export default function register(api) {
661
831
  throw new Error(context.error);
662
832
  }
663
833
  const rawPhase = pickStringField(payload, "phase") ?? "implementing";
664
- const progressPct = typeof payload.progress_pct === "number" ? payload.progress_pct : undefined;
834
+ const progressPct = typeof payload.progress_pct === "number"
835
+ ? payload.progress_pct
836
+ : typeof payload.progressPct === "number"
837
+ ? payload.progressPct
838
+ : undefined;
665
839
  const phase = rawPhase === "intent" ||
666
840
  rawPhase === "execution" ||
667
841
  rawPhase === "blocked" ||
@@ -670,7 +844,11 @@ export default function register(api) {
670
844
  rawPhase === "completed"
671
845
  ? rawPhase
672
846
  : toReportingPhase(rawPhase, progressPct);
673
- await client.emitActivity({
847
+ const metaRaw = payload.metadata;
848
+ const meta = metaRaw && typeof metaRaw === "object" && !Array.isArray(metaRaw)
849
+ ? metaRaw
850
+ : {};
851
+ const emitPayload = {
674
852
  initiative_id: context.value.initiativeId,
675
853
  run_id: context.value.runId,
676
854
  correlation_id: context.value.correlationId,
@@ -679,12 +857,44 @@ export default function register(api) {
679
857
  phase,
680
858
  progress_pct: progressPct,
681
859
  level: pickStringField(payload, "level"),
682
- next_step: pickStringField(payload, "next_step") ?? undefined,
860
+ next_step: pickStringField(payload, "next_step") ??
861
+ pickStringField(payload, "nextStep") ??
862
+ undefined,
683
863
  metadata: {
864
+ ...meta,
684
865
  source: "orgx_openclaw_outbox_replay",
685
866
  outbox_event_id: event.id,
686
867
  },
687
- });
868
+ };
869
+ try {
870
+ await client.emitActivity(emitPayload);
871
+ }
872
+ catch (err) {
873
+ // Some locally-buffered events carry a UUID that *looks* like an OrgX run_id
874
+ // but was only ever used as a local correlation/grouping key. If OrgX
875
+ // doesn't recognize it, retry by treating it as correlation_id so OrgX can
876
+ // create/attach a run deterministically.
877
+ const msg = toErrorMessage(err);
878
+ if (emitPayload.run_id &&
879
+ /^404\\b/.test(msg) &&
880
+ /\\brun\\b/i.test(msg) &&
881
+ /not found/i.test(msg)) {
882
+ await client.emitActivity({
883
+ ...emitPayload,
884
+ run_id: undefined,
885
+ // Avoid passing a bare UUID as correlation_id since some server
886
+ // paths may interpret UUIDs as run_id lookups.
887
+ correlation_id: `openclaw:${emitPayload.run_id}`,
888
+ metadata: {
889
+ ...emitPayload.metadata,
890
+ replay_run_id_as_correlation: true,
891
+ },
892
+ });
893
+ }
894
+ else {
895
+ throw err;
896
+ }
897
+ }
688
898
  return;
689
899
  }
690
900
  if (event.type === "decision") {
@@ -770,7 +980,14 @@ export default function register(api) {
770
980
  };
771
981
  let hadReplayFailure = false;
772
982
  let lastReplayError = null;
773
- for (const queue of outboxQueues) {
983
+ // Outbox files are keyed by *session id* (e.g. initiative/run correlation),
984
+ // not by event type.
985
+ const outboxSummary = await readOutboxSummary();
986
+ const queues = Object.entries(outboxSummary.pendingByQueue)
987
+ .filter(([, count]) => typeof count === "number" && count > 0)
988
+ .map(([queueId]) => queueId)
989
+ .sort();
990
+ for (const queue of queues) {
774
991
  const pending = await readOutbox(queue);
775
992
  if (pending.length === 0) {
776
993
  continue;
@@ -1215,8 +1432,13 @@ export default function register(api) {
1215
1432
  // ---------------------------------------------------------------------------
1216
1433
  // 2. MCP Tools (Model Context Protocol compatible)
1217
1434
  // ---------------------------------------------------------------------------
1435
+ const mcpToolRegistry = new Map();
1436
+ const registerMcpTool = (tool, options) => {
1437
+ mcpToolRegistry.set(tool.name, tool);
1438
+ api.registerTool(tool, options);
1439
+ };
1218
1440
  // --- orgx_status ---
1219
- api.registerTool({
1441
+ registerMcpTool({
1220
1442
  name: "orgx_status",
1221
1443
  description: "Get current OrgX org status: active initiatives, agent states, pending decisions, active tasks.",
1222
1444
  parameters: {
@@ -1236,7 +1458,7 @@ export default function register(api) {
1236
1458
  },
1237
1459
  }, { optional: true });
1238
1460
  // --- orgx_sync ---
1239
- api.registerTool({
1461
+ registerMcpTool({
1240
1462
  name: "orgx_sync",
1241
1463
  description: "Push/pull memory sync with OrgX. Send local memory/daily log; receive initiatives, tasks, decisions, model routing policy.",
1242
1464
  parameters: {
@@ -1266,7 +1488,7 @@ export default function register(api) {
1266
1488
  },
1267
1489
  }, { optional: true });
1268
1490
  // --- orgx_delegation_preflight ---
1269
- api.registerTool({
1491
+ registerMcpTool({
1270
1492
  name: "orgx_delegation_preflight",
1271
1493
  description: "Run delegation preflight to score scope quality, estimate ETA/cost, and suggest a split before autonomous execution.",
1272
1494
  parameters: {
@@ -1317,7 +1539,7 @@ export default function register(api) {
1317
1539
  },
1318
1540
  }, { optional: true });
1319
1541
  // --- orgx_run_action ---
1320
- api.registerTool({
1542
+ registerMcpTool({
1321
1543
  name: "orgx_run_action",
1322
1544
  description: "Apply a control action to a run: pause, resume, cancel, or rollback (rollback requires checkpointId).",
1323
1545
  parameters: {
@@ -1361,7 +1583,7 @@ export default function register(api) {
1361
1583
  },
1362
1584
  }, { optional: true });
1363
1585
  // --- orgx_checkpoints_list ---
1364
- api.registerTool({
1586
+ registerMcpTool({
1365
1587
  name: "orgx_checkpoints_list",
1366
1588
  description: "List checkpoints for a run.",
1367
1589
  parameters: {
@@ -1386,7 +1608,7 @@ export default function register(api) {
1386
1608
  },
1387
1609
  }, { optional: true });
1388
1610
  // --- orgx_checkpoint_restore ---
1389
- api.registerTool({
1611
+ registerMcpTool({
1390
1612
  name: "orgx_checkpoint_restore",
1391
1613
  description: "Restore a run to a specific checkpoint.",
1392
1614
  parameters: {
@@ -1425,7 +1647,7 @@ export default function register(api) {
1425
1647
  },
1426
1648
  }, { optional: true });
1427
1649
  // --- orgx_spawn_check ---
1428
- api.registerTool({
1650
+ registerMcpTool({
1429
1651
  name: "orgx_spawn_check",
1430
1652
  description: "Check quality gate + get model routing before spawning a sub-agent. Returns allowed/denied, model tier, and check details.",
1431
1653
  parameters: {
@@ -1454,7 +1676,7 @@ export default function register(api) {
1454
1676
  },
1455
1677
  }, { optional: true });
1456
1678
  // --- orgx_quality_score ---
1457
- api.registerTool({
1679
+ registerMcpTool({
1458
1680
  name: "orgx_quality_score",
1459
1681
  description: "Record a quality score (1-5) for completed agent work. Used to gate future spawns and track performance.",
1460
1682
  parameters: {
@@ -1492,7 +1714,7 @@ export default function register(api) {
1492
1714
  },
1493
1715
  }, { optional: true });
1494
1716
  // --- orgx_create_entity ---
1495
- api.registerTool({
1717
+ registerMcpTool({
1496
1718
  name: "orgx_create_entity",
1497
1719
  description: "Create an OrgX entity (initiative, workstream, task, decision, milestone, etc.).",
1498
1720
  parameters: {
@@ -1577,7 +1799,7 @@ export default function register(api) {
1577
1799
  },
1578
1800
  }, { optional: true });
1579
1801
  // --- orgx_update_entity ---
1580
- api.registerTool({
1802
+ registerMcpTool({
1581
1803
  name: "orgx_update_entity",
1582
1804
  description: "Update an existing OrgX entity by type and ID.",
1583
1805
  parameters: {
@@ -1618,7 +1840,7 @@ export default function register(api) {
1618
1840
  },
1619
1841
  }, { optional: true });
1620
1842
  // --- orgx_list_entities ---
1621
- api.registerTool({
1843
+ registerMcpTool({
1622
1844
  name: "orgx_list_entities",
1623
1845
  description: "List OrgX entities of a given type with optional status filter.",
1624
1846
  parameters: {
@@ -1760,7 +1982,7 @@ export default function register(api) {
1760
1982
  }
1761
1983
  }
1762
1984
  // --- orgx_emit_activity ---
1763
- api.registerTool({
1985
+ registerMcpTool({
1764
1986
  name: "orgx_emit_activity",
1765
1987
  description: "Emit append-only OrgX activity telemetry (launch reporting contract primary write tool).",
1766
1988
  parameters: {
@@ -1820,7 +2042,7 @@ export default function register(api) {
1820
2042
  },
1821
2043
  }, { optional: true });
1822
2044
  // --- orgx_apply_changeset ---
1823
- api.registerTool({
2045
+ registerMcpTool({
1824
2046
  name: "orgx_apply_changeset",
1825
2047
  description: "Apply an idempotent transactional OrgX changeset (launch reporting contract primary mutation tool).",
1826
2048
  parameters: {
@@ -1863,7 +2085,7 @@ export default function register(api) {
1863
2085
  },
1864
2086
  }, { optional: true });
1865
2087
  // --- orgx_report_progress (alias -> orgx_emit_activity) ---
1866
- api.registerTool({
2088
+ registerMcpTool({
1867
2089
  name: "orgx_report_progress",
1868
2090
  description: "Alias for orgx_emit_activity. Report progress at key milestones so the team can track your work.",
1869
2091
  parameters: {
@@ -1926,7 +2148,7 @@ export default function register(api) {
1926
2148
  },
1927
2149
  }, { optional: true });
1928
2150
  // --- orgx_request_decision (alias -> orgx_apply_changeset decision.create) ---
1929
- api.registerTool({
2151
+ registerMcpTool({
1930
2152
  name: "orgx_request_decision",
1931
2153
  description: "Alias for orgx_apply_changeset with decision.create. Request a human decision before proceeding.",
1932
2154
  parameters: {
@@ -2011,7 +2233,7 @@ export default function register(api) {
2011
2233
  },
2012
2234
  }, { optional: true });
2013
2235
  // --- orgx_register_artifact ---
2014
- api.registerTool({
2236
+ registerMcpTool({
2015
2237
  name: "orgx_register_artifact",
2016
2238
  description: "Register a work output (PR, document, config change, report, etc.) with OrgX. Makes it visible in the dashboard.",
2017
2239
  parameters: {
@@ -2184,7 +2406,18 @@ export default function register(api) {
2184
2406
  }, {
2185
2407
  getHealth: async (input = {}) => buildHealthReport({ probeRemote: input.probeRemote === true }),
2186
2408
  });
2187
- api.registerHttpHandler(httpHandler);
2409
+ const mcpHttpHandler = createMcpHttpHandler({
2410
+ tools: mcpToolRegistry,
2411
+ logger: api.log ?? {},
2412
+ serverName: "@useorgx/openclaw-plugin",
2413
+ serverVersion: config.pluginVersion,
2414
+ });
2415
+ const compositeHttpHandler = async (req, res) => {
2416
+ if (await mcpHttpHandler(req, res))
2417
+ return true;
2418
+ return await httpHandler(req, res);
2419
+ };
2420
+ api.registerHttpHandler(compositeHttpHandler);
2188
2421
  api.log?.info?.("[orgx] Plugin registered", {
2189
2422
  baseUrl: config.baseUrl,
2190
2423
  hasApiKey: !!config.apiKey,
@@ -0,0 +1,30 @@
1
+ import type { Logger } from "./mcp-http-handler.js";
2
+ export declare function patchClaudeMcpConfig(input: {
3
+ current: Record<string, unknown>;
4
+ localMcpUrl: string;
5
+ }): {
6
+ updated: boolean;
7
+ next: Record<string, unknown>;
8
+ };
9
+ export declare function patchCursorMcpConfig(input: {
10
+ current: Record<string, unknown>;
11
+ localMcpUrl: string;
12
+ }): {
13
+ updated: boolean;
14
+ next: Record<string, unknown>;
15
+ };
16
+ export declare function patchCodexConfigToml(input: {
17
+ current: string;
18
+ localMcpUrl: string;
19
+ }): {
20
+ updated: boolean;
21
+ next: string;
22
+ };
23
+ export declare function autoConfigureDetectedMcpClients(input: {
24
+ localMcpUrl: string;
25
+ logger?: Logger;
26
+ homeDir?: string;
27
+ }): Promise<{
28
+ updatedPaths: string[];
29
+ skippedPaths: string[];
30
+ }>;