clawdentity 0.0.13 → 0.0.15

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/dist/bin.js CHANGED
@@ -15643,6 +15643,7 @@ var runtimeEnvironmentValues = [
15643
15643
  // ../../packages/sdk/src/config.ts
15644
15644
  var environmentSchema = external_exports.enum(runtimeEnvironmentValues);
15645
15645
  var registrySigningKeyStatusSchema = external_exports.enum(["active", "revoked"]);
15646
+ var registryEventBusBackendSchema = external_exports.enum(["memory", "queue"]);
15646
15647
  var ED25519_PUBLIC_KEY_LENGTH2 = 32;
15647
15648
  var registrySigningPublicKeySchema = external_exports.object({
15648
15649
  kid: external_exports.string().min(1),
@@ -15712,6 +15713,7 @@ var registryConfigSchema = external_exports.object({
15712
15713
  ENVIRONMENT: environmentSchema,
15713
15714
  APP_VERSION: external_exports.string().min(1).optional(),
15714
15715
  PROXY_URL: external_exports.string().url().optional(),
15716
+ EVENT_BUS_BACKEND: registryEventBusBackendSchema.optional(),
15715
15717
  BOOTSTRAP_SECRET: external_exports.string().min(1).optional(),
15716
15718
  REGISTRY_SIGNING_KEY: external_exports.string().min(1).optional(),
15717
15719
  REGISTRY_SIGNING_KEYS: registrySigningKeysEnvSchema.optional()
@@ -18671,6 +18673,7 @@ var DEFAULT_RECONNECT_BACKOFF_FACTOR = 2;
18671
18673
  var DEFAULT_RECONNECT_JITTER_RATIO = 0.2;
18672
18674
  var DEFAULT_CONNECTOR_BASE_URL = "http://127.0.0.1:19400";
18673
18675
  var DEFAULT_CONNECTOR_OUTBOUND_PATH = "/v1/outbound";
18676
+ var DEFAULT_CONNECTOR_STATUS_PATH = "/v1/status";
18674
18677
  var DEFAULT_RELAY_DELIVER_TIMEOUT_MS = 15e3;
18675
18678
  var DEFAULT_OPENCLAW_DELIVER_RETRY_BUDGET_MS = DEFAULT_RELAY_DELIVER_TIMEOUT_MS - 1e3;
18676
18679
  var AGENT_ACCESS_HEADER = "x-claw-agent-access";
@@ -19598,6 +19601,7 @@ async function startConnectorRuntime(input) {
19598
19601
  });
19599
19602
  const outboundBaseUrl = normalizeOutboundBaseUrl(input.outboundBaseUrl);
19600
19603
  const outboundPath = normalizeOutboundPath(input.outboundPath);
19604
+ const statusPath = DEFAULT_CONNECTOR_STATUS_PATH;
19601
19605
  const outboundUrl = new URL(outboundPath, outboundBaseUrl).toString();
19602
19606
  const relayToPeer = async (request) => {
19603
19607
  const peerUrl = new URL(request.peerProxyUrl);
@@ -19665,6 +19669,21 @@ async function startConnectorRuntime(input) {
19665
19669
  };
19666
19670
  const server = createServer(async (req, res) => {
19667
19671
  const requestPath = req.url ? new URL(req.url, outboundBaseUrl).pathname : "/";
19672
+ if (requestPath === statusPath) {
19673
+ if (req.method !== "GET") {
19674
+ res.statusCode = 405;
19675
+ res.setHeader("allow", "GET");
19676
+ writeJson(res, 405, { error: "Method Not Allowed" });
19677
+ return;
19678
+ }
19679
+ writeJson(res, 200, {
19680
+ status: "ok",
19681
+ outboundUrl,
19682
+ websocketUrl: wsUrl,
19683
+ websocketConnected: connectorClient.isConnected()
19684
+ });
19685
+ return;
19686
+ }
19668
19687
  if (requestPath !== outboundPath) {
19669
19688
  writeJson(res, 404, { error: "Not Found" });
19670
19689
  return;
@@ -20921,11 +20940,13 @@ var createInviteCommand = (dependencies = {}) => {
20921
20940
  };
20922
20941
 
20923
20942
  // src/commands/openclaw.ts
20943
+ import { spawn } from "child_process";
20924
20944
  import { randomBytes as randomBytes3 } from "crypto";
20925
20945
  import { existsSync } from "fs";
20926
20946
  import { chmod as chmod3, copyFile, mkdir as mkdir5, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
20927
20947
  import { homedir as homedir3 } from "os";
20928
20948
  import { dirname as dirname4, join as join6, resolve as resolvePath } from "path";
20949
+ import { fileURLToPath as fileURLToPath2 } from "url";
20929
20950
  import { Command as Command7 } from "commander";
20930
20951
  var logger8 = createLogger({ service: "cli", module: "openclaw" });
20931
20952
  var CLAWDENTITY_DIR_NAME = ".clawdentity";
@@ -20960,10 +20981,13 @@ var DEFAULT_OPENCLAW_MAIN_SESSION_KEY = "main";
20960
20981
  var DEFAULT_OPENCLAW_AGENT_ID = "main";
20961
20982
  var DEFAULT_CONNECTOR_PORT = 19400;
20962
20983
  var DEFAULT_CONNECTOR_OUTBOUND_PATH3 = "/v1/outbound";
20984
+ var DEFAULT_CONNECTOR_STATUS_PATH2 = "/v1/status";
20985
+ var DEFAULT_SETUP_WAIT_TIMEOUT_SECONDS = 30;
20963
20986
  var CONNECTOR_HOST_LOOPBACK = "127.0.0.1";
20964
20987
  var CONNECTOR_HOST_DOCKER = "host.docker.internal";
20965
20988
  var CONNECTOR_HOST_DOCKER_GATEWAY = "gateway.docker.internal";
20966
20989
  var CONNECTOR_HOST_LINUX_BRIDGE = "172.17.0.1";
20990
+ var CONNECTOR_RUN_DIR_NAME = "run";
20967
20991
  var PEER_ALIAS_PATTERN = /^[a-zA-Z0-9._-]+$/;
20968
20992
  var FILE_MODE3 = 384;
20969
20993
  var OPENCLAW_HOOK_TOKEN_BYTES = 32;
@@ -21376,6 +21400,256 @@ function buildRelayConnectorBaseUrls(port) {
21376
21400
  buildConnectorBaseUrl(CONNECTOR_HOST_LOOPBACK, port)
21377
21401
  ];
21378
21402
  }
21403
+ function parseOpenclawRuntimeMode(value) {
21404
+ if (typeof value !== "string" || value.trim().length === 0) {
21405
+ return "auto";
21406
+ }
21407
+ const normalized = value.trim().toLowerCase();
21408
+ if (normalized === "auto" || normalized === "service" || normalized === "detached") {
21409
+ return normalized;
21410
+ }
21411
+ throw createCliError6(
21412
+ "CLI_OPENCLAW_SETUP_RUNTIME_MODE_INVALID",
21413
+ "runtimeMode must be one of: auto, service, detached"
21414
+ );
21415
+ }
21416
+ function parseWaitTimeoutSeconds(value) {
21417
+ if (typeof value !== "string" || value.trim().length === 0) {
21418
+ return DEFAULT_SETUP_WAIT_TIMEOUT_SECONDS;
21419
+ }
21420
+ const parsed = Number.parseInt(value, 10);
21421
+ if (!Number.isInteger(parsed) || parsed < 1) {
21422
+ throw createCliError6(
21423
+ "CLI_OPENCLAW_SETUP_TIMEOUT_INVALID",
21424
+ "waitTimeoutSeconds must be a positive integer"
21425
+ );
21426
+ }
21427
+ return parsed;
21428
+ }
21429
+ function resolveConnectorStatusUrl(connectorBaseUrl) {
21430
+ const normalizedBase = connectorBaseUrl.endsWith("/") ? connectorBaseUrl : `${connectorBaseUrl}/`;
21431
+ return new URL(
21432
+ DEFAULT_CONNECTOR_STATUS_PATH2.slice(1),
21433
+ normalizedBase
21434
+ ).toString();
21435
+ }
21436
+ function parseConnectorStatusPayload(payload) {
21437
+ if (!isRecord8(payload) || typeof payload.websocketConnected !== "boolean") {
21438
+ throw createCliError6(
21439
+ "CLI_OPENCLAW_SETUP_CONNECTOR_STATUS_INVALID",
21440
+ "Connector status response is invalid"
21441
+ );
21442
+ }
21443
+ return {
21444
+ websocketConnected: payload.websocketConnected
21445
+ };
21446
+ }
21447
+ async function fetchConnectorHealthStatus(input) {
21448
+ const statusUrl = resolveConnectorStatusUrl(input.connectorBaseUrl);
21449
+ try {
21450
+ const response = await input.fetchImpl(statusUrl, {
21451
+ method: "GET",
21452
+ headers: {
21453
+ accept: "application/json"
21454
+ }
21455
+ });
21456
+ if (!response.ok) {
21457
+ return {
21458
+ connected: false,
21459
+ reachable: false,
21460
+ statusUrl,
21461
+ reason: `HTTP ${response.status}`
21462
+ };
21463
+ }
21464
+ let payload;
21465
+ try {
21466
+ payload = await response.json();
21467
+ } catch {
21468
+ return {
21469
+ connected: false,
21470
+ reachable: false,
21471
+ statusUrl,
21472
+ reason: "invalid JSON payload"
21473
+ };
21474
+ }
21475
+ const parsed = parseConnectorStatusPayload(payload);
21476
+ return {
21477
+ connected: parsed.websocketConnected,
21478
+ reachable: true,
21479
+ statusUrl,
21480
+ reason: parsed.websocketConnected ? void 0 : "connector websocket is disconnected"
21481
+ };
21482
+ } catch {
21483
+ return {
21484
+ connected: false,
21485
+ reachable: false,
21486
+ statusUrl,
21487
+ reason: "connector status endpoint is unreachable"
21488
+ };
21489
+ }
21490
+ }
21491
+ async function waitForConnectorConnected(input) {
21492
+ const deadline = Date.now() + input.waitTimeoutSeconds * 1e3;
21493
+ let latest = await fetchConnectorHealthStatus({
21494
+ connectorBaseUrl: input.connectorBaseUrl,
21495
+ fetchImpl: input.fetchImpl
21496
+ });
21497
+ while (!latest.connected && Date.now() < deadline) {
21498
+ await new Promise((resolve2) => {
21499
+ setTimeout(resolve2, 1e3);
21500
+ });
21501
+ latest = await fetchConnectorHealthStatus({
21502
+ connectorBaseUrl: input.connectorBaseUrl,
21503
+ fetchImpl: input.fetchImpl
21504
+ });
21505
+ }
21506
+ if (!latest.connected) {
21507
+ throw createCliError6(
21508
+ "CLI_OPENCLAW_SETUP_CONNECTOR_NOT_READY",
21509
+ `Connector runtime is not websocket-connected after ${input.waitTimeoutSeconds} seconds`,
21510
+ {
21511
+ connectorBaseUrl: input.connectorBaseUrl,
21512
+ connectorStatusUrl: latest.statusUrl,
21513
+ reason: latest.reason
21514
+ }
21515
+ );
21516
+ }
21517
+ return latest;
21518
+ }
21519
+ function resolveConnectorRunDir(homeDir) {
21520
+ return join6(homeDir, CLAWDENTITY_DIR_NAME, CONNECTOR_RUN_DIR_NAME);
21521
+ }
21522
+ function resolveConnectorPidPath(homeDir, agentName) {
21523
+ return join6(resolveConnectorRunDir(homeDir), `connector-${agentName}.pid`);
21524
+ }
21525
+ async function readConnectorPidFile(pidPath) {
21526
+ try {
21527
+ const raw = (await readFile4(pidPath, "utf8")).trim();
21528
+ if (raw.length === 0) {
21529
+ return void 0;
21530
+ }
21531
+ const parsed = Number.parseInt(raw, 10);
21532
+ if (!Number.isInteger(parsed) || parsed <= 0) {
21533
+ return void 0;
21534
+ }
21535
+ return parsed;
21536
+ } catch (error48) {
21537
+ if (getErrorCode2(error48) === "ENOENT") {
21538
+ return void 0;
21539
+ }
21540
+ throw error48;
21541
+ }
21542
+ }
21543
+ function isPidRunning(pid) {
21544
+ try {
21545
+ process.kill(pid, 0);
21546
+ return true;
21547
+ } catch {
21548
+ return false;
21549
+ }
21550
+ }
21551
+ async function stopDetachedConnectorIfRunning(input) {
21552
+ const pidPath = resolveConnectorPidPath(input.homeDir, input.agentName);
21553
+ const pid = await readConnectorPidFile(pidPath);
21554
+ if (pid === void 0 || !isPidRunning(pid)) {
21555
+ return;
21556
+ }
21557
+ try {
21558
+ process.kill(pid, "SIGTERM");
21559
+ } catch {
21560
+ }
21561
+ }
21562
+ function resolveCliEntryPathForDetachedStart() {
21563
+ const argvEntry = typeof process.argv[1] === "string" ? process.argv[1] : "";
21564
+ if (argvEntry.length > 0 && existsSync(argvEntry)) {
21565
+ return argvEntry;
21566
+ }
21567
+ const modulePath = fileURLToPath2(import.meta.url);
21568
+ return join6(dirname4(modulePath), "..", "bin.js");
21569
+ }
21570
+ async function startDetachedConnectorRuntime(input) {
21571
+ await stopDetachedConnectorIfRunning({
21572
+ homeDir: input.homeDir,
21573
+ agentName: input.agentName
21574
+ });
21575
+ const runDir = resolveConnectorRunDir(input.homeDir);
21576
+ await mkdir5(runDir, { recursive: true });
21577
+ const cliEntryPath = resolveCliEntryPathForDetachedStart();
21578
+ const args = [
21579
+ cliEntryPath,
21580
+ "connector",
21581
+ "start",
21582
+ input.agentName,
21583
+ "--openclaw-base-url",
21584
+ input.openclawBaseUrl
21585
+ ];
21586
+ const child = spawn(process.execPath, args, {
21587
+ detached: true,
21588
+ stdio: "ignore",
21589
+ env: process.env
21590
+ });
21591
+ child.unref();
21592
+ await writeSecureFile3(
21593
+ resolveConnectorPidPath(input.homeDir, input.agentName),
21594
+ `${child.pid}
21595
+ `
21596
+ );
21597
+ }
21598
+ async function startSetupConnectorRuntime(input) {
21599
+ if (input.mode !== "service") {
21600
+ const existingStatus = await fetchConnectorHealthStatus({
21601
+ connectorBaseUrl: input.connectorBaseUrl,
21602
+ fetchImpl: input.fetchImpl
21603
+ });
21604
+ if (existingStatus.connected) {
21605
+ return {
21606
+ runtimeMode: "existing",
21607
+ runtimeStatus: "running",
21608
+ websocketStatus: "connected",
21609
+ connectorStatusUrl: existingStatus.statusUrl
21610
+ };
21611
+ }
21612
+ }
21613
+ let runtimeMode = "service";
21614
+ if (input.mode === "detached") {
21615
+ runtimeMode = "detached";
21616
+ } else {
21617
+ try {
21618
+ await installConnectorServiceForAgent(input.agentName, {
21619
+ platform: "auto",
21620
+ openclawBaseUrl: input.openclawBaseUrl
21621
+ });
21622
+ runtimeMode = "service";
21623
+ } catch (error48) {
21624
+ if (input.mode === "service") {
21625
+ throw error48;
21626
+ }
21627
+ runtimeMode = "detached";
21628
+ logger8.warn("cli.openclaw.setup.service_fallback_detached", {
21629
+ agentName: input.agentName,
21630
+ reason: error48 instanceof Error ? error48.message : "unknown"
21631
+ });
21632
+ }
21633
+ }
21634
+ if (runtimeMode === "detached") {
21635
+ await startDetachedConnectorRuntime({
21636
+ agentName: input.agentName,
21637
+ homeDir: input.homeDir,
21638
+ openclawBaseUrl: input.openclawBaseUrl
21639
+ });
21640
+ }
21641
+ const connectedStatus = await waitForConnectorConnected({
21642
+ connectorBaseUrl: input.connectorBaseUrl,
21643
+ fetchImpl: input.fetchImpl,
21644
+ waitTimeoutSeconds: input.waitTimeoutSeconds
21645
+ });
21646
+ return {
21647
+ runtimeMode,
21648
+ runtimeStatus: "running",
21649
+ websocketStatus: "connected",
21650
+ connectorStatusUrl: connectedStatus.statusUrl
21651
+ };
21652
+ }
21379
21653
  function parseRelayRuntimeConfig(value, relayRuntimeConfigPath) {
21380
21654
  if (!isRecord8(value)) {
21381
21655
  throw createCliError6(
@@ -22054,6 +22328,97 @@ async function runOpenclawDoctor(options = {}) {
22054
22328
  })
22055
22329
  );
22056
22330
  }
22331
+ if (options.includeConnectorRuntimeCheck !== false) {
22332
+ if (selectedAgentName === void 0) {
22333
+ checks.push(
22334
+ toDoctorCheck({
22335
+ id: "state.connectorRuntime",
22336
+ label: "Connector runtime",
22337
+ status: "fail",
22338
+ message: "cannot validate connector runtime without selected agent marker",
22339
+ remediationHint: OPENCLAW_SETUP_COMMAND_HINT
22340
+ })
22341
+ );
22342
+ } else {
22343
+ const connectorAssignmentsPath = resolveConnectorAssignmentsPath(homeDir);
22344
+ try {
22345
+ const connectorAssignments = await loadConnectorAssignments(
22346
+ connectorAssignmentsPath
22347
+ );
22348
+ const assignment = connectorAssignments.agents[selectedAgentName];
22349
+ if (assignment === void 0) {
22350
+ checks.push(
22351
+ toDoctorCheck({
22352
+ id: "state.connectorRuntime",
22353
+ label: "Connector runtime",
22354
+ status: "fail",
22355
+ message: `no connector assignment found for ${selectedAgentName}`,
22356
+ remediationHint: OPENCLAW_SETUP_COMMAND_HINT,
22357
+ details: { connectorAssignmentsPath, selectedAgentName }
22358
+ })
22359
+ );
22360
+ } else {
22361
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
22362
+ if (typeof fetchImpl !== "function") {
22363
+ checks.push(
22364
+ toDoctorCheck({
22365
+ id: "state.connectorRuntime",
22366
+ label: "Connector runtime",
22367
+ status: "fail",
22368
+ message: "fetch implementation is unavailable for connector checks",
22369
+ remediationHint: "Run doctor in a Node runtime with fetch support, or rerun openclaw setup"
22370
+ })
22371
+ );
22372
+ } else {
22373
+ const connectorStatus = await fetchConnectorHealthStatus({
22374
+ connectorBaseUrl: assignment.connectorBaseUrl,
22375
+ fetchImpl
22376
+ });
22377
+ if (connectorStatus.connected) {
22378
+ checks.push(
22379
+ toDoctorCheck({
22380
+ id: "state.connectorRuntime",
22381
+ label: "Connector runtime",
22382
+ status: "pass",
22383
+ message: `connector websocket is connected (${assignment.connectorBaseUrl})`,
22384
+ details: {
22385
+ connectorStatusUrl: connectorStatus.statusUrl,
22386
+ connectorBaseUrl: assignment.connectorBaseUrl
22387
+ }
22388
+ })
22389
+ );
22390
+ } else {
22391
+ const reason = connectorStatus.reason ?? "connector runtime is unavailable";
22392
+ checks.push(
22393
+ toDoctorCheck({
22394
+ id: "state.connectorRuntime",
22395
+ label: "Connector runtime",
22396
+ status: "fail",
22397
+ message: `connector runtime is not ready: ${reason}`,
22398
+ remediationHint: OPENCLAW_SETUP_COMMAND_HINT,
22399
+ details: {
22400
+ connectorStatusUrl: connectorStatus.statusUrl,
22401
+ connectorBaseUrl: assignment.connectorBaseUrl
22402
+ }
22403
+ })
22404
+ );
22405
+ }
22406
+ }
22407
+ }
22408
+ } catch {
22409
+ checks.push(
22410
+ toDoctorCheck({
22411
+ id: "state.connectorRuntime",
22412
+ label: "Connector runtime",
22413
+ status: "fail",
22414
+ message: `unable to read connector assignments at ${connectorAssignmentsPath}`,
22415
+ remediationHint: OPENCLAW_SETUP_COMMAND_HINT,
22416
+ details: { connectorAssignmentsPath }
22417
+ })
22418
+ );
22419
+ }
22420
+ }
22421
+ }
22057
22422
  return toDoctorResult(checks);
22058
22423
  }
22059
22424
  function parseRelayProbeFailure(input) {
@@ -22135,7 +22500,8 @@ async function runOpenclawRelayTest(options) {
22135
22500
  homeDir,
22136
22501
  openclawDir,
22137
22502
  peerAlias,
22138
- resolveConfigImpl: options.resolveConfigImpl
22503
+ resolveConfigImpl: options.resolveConfigImpl,
22504
+ includeConnectorRuntimeCheck: false
22139
22505
  });
22140
22506
  const relayRuntimeConfigPath = resolveRelayRuntimeConfigPath(homeDir);
22141
22507
  let openclawBaseUrl = DEFAULT_OPENCLAW_BASE_URL2;
@@ -22346,6 +22712,42 @@ async function setupOpenclawRelay(agentName, options) {
22346
22712
  relayRuntimeConfigPath
22347
22713
  };
22348
22714
  }
22715
+ async function setupOpenclawSelfReady(agentName, options) {
22716
+ const setup = await setupOpenclawRelay(agentName, options);
22717
+ if (options.noRuntimeStart === true) {
22718
+ return {
22719
+ ...setup,
22720
+ runtimeMode: "none",
22721
+ runtimeStatus: "skipped",
22722
+ websocketStatus: "skipped"
22723
+ };
22724
+ }
22725
+ const fetchImpl = globalThis.fetch;
22726
+ if (typeof fetchImpl !== "function") {
22727
+ throw createCliError6(
22728
+ "CLI_OPENCLAW_SETUP_FETCH_UNAVAILABLE",
22729
+ "Runtime fetch is unavailable for connector readiness checks"
22730
+ );
22731
+ }
22732
+ const resolvedMode = parseOpenclawRuntimeMode(options.runtimeMode);
22733
+ const waitTimeoutSeconds = parseWaitTimeoutSeconds(
22734
+ options.waitTimeoutSeconds
22735
+ );
22736
+ const resolvedHomeDir = resolveHomeDir(options.homeDir);
22737
+ const runtime = await startSetupConnectorRuntime({
22738
+ agentName: assertValidAgentName(agentName),
22739
+ homeDir: resolvedHomeDir,
22740
+ openclawBaseUrl: setup.openclawBaseUrl,
22741
+ connectorBaseUrl: setup.connectorBaseUrl,
22742
+ mode: resolvedMode,
22743
+ waitTimeoutSeconds,
22744
+ fetchImpl
22745
+ });
22746
+ return {
22747
+ ...setup,
22748
+ ...runtime
22749
+ };
22750
+ }
22349
22751
  var createOpenclawCommand = () => {
22350
22752
  const openclawCommand = new Command7("openclaw").description(
22351
22753
  "Manage OpenClaw relay setup"
@@ -22359,11 +22761,20 @@ var createOpenclawCommand = () => {
22359
22761
  ).option(
22360
22762
  "--openclaw-base-url <url>",
22361
22763
  "Base URL for local OpenClaw hook API (default http://127.0.0.1:18789)"
22764
+ ).option(
22765
+ "--runtime-mode <mode>",
22766
+ "Connector runtime mode: auto | service | detached (default auto)"
22767
+ ).option(
22768
+ "--wait-timeout-seconds <seconds>",
22769
+ "Seconds to wait for connector websocket readiness (default 30)"
22770
+ ).option(
22771
+ "--no-runtime-start",
22772
+ "Skip connector runtime startup (advanced/manual mode)"
22362
22773
  ).action(
22363
22774
  withErrorHandling(
22364
22775
  "openclaw setup",
22365
22776
  async (agentName, options) => {
22366
- const result = await setupOpenclawRelay(agentName, options);
22777
+ const result = await setupOpenclawSelfReady(agentName, options);
22367
22778
  writeStdoutLine("Self setup complete");
22368
22779
  writeStdoutLine(
22369
22780
  `Updated OpenClaw config: ${result.openclawConfigPath}`
@@ -22380,6 +22791,14 @@ var createOpenclawCommand = () => {
22380
22791
  writeStdoutLine(
22381
22792
  `Relay runtime config: ${result.relayRuntimeConfigPath}`
22382
22793
  );
22794
+ writeStdoutLine(`Runtime mode: ${result.runtimeMode}`);
22795
+ writeStdoutLine(`Runtime status: ${result.runtimeStatus}`);
22796
+ writeStdoutLine(`WebSocket status: ${result.websocketStatus}`);
22797
+ if (result.connectorStatusUrl) {
22798
+ writeStdoutLine(
22799
+ `Connector status URL: ${result.connectorStatusUrl}`
22800
+ );
22801
+ }
22383
22802
  }
22384
22803
  )
22385
22804
  );
@@ -22471,13 +22890,15 @@ var PAIRING_QR_DIR_NAME = "pairing";
22471
22890
  var PEERS_FILE_NAME2 = "peers.json";
22472
22891
  var PAIR_START_PATH = "/pair/start";
22473
22892
  var PAIR_CONFIRM_PATH = "/pair/confirm";
22474
- var OWNER_PAT_HEADER = "x-claw-owner-pat";
22893
+ var PAIR_STATUS_PATH = "/pair/status";
22475
22894
  var NONCE_SIZE2 = 24;
22476
22895
  var PAIRING_TICKET_PREFIX = "clwpair1_";
22477
22896
  var PAIRING_QR_MAX_AGE_SECONDS = 900;
22478
22897
  var PAIRING_QR_FILENAME_PATTERN = /-pair-(\d+)\.png$/;
22479
22898
  var FILE_MODE4 = 384;
22480
22899
  var PEER_ALIAS_PATTERN2 = /^[a-zA-Z0-9._-]+$/;
22900
+ var DEFAULT_STATUS_WAIT_SECONDS = 300;
22901
+ var DEFAULT_STATUS_POLL_INTERVAL_SECONDS = 3;
22481
22902
  var isRecord9 = (value) => {
22482
22903
  return typeof value === "object" && value !== null;
22483
22904
  };
@@ -22553,6 +22974,52 @@ function parsePairingTicketIssuerOrigin(ticket) {
22553
22974
  }
22554
22975
  return issuerUrl.origin;
22555
22976
  }
22977
+ function parseAitAgentDid(ait) {
22978
+ const parts = ait.split(".");
22979
+ if (parts.length < 2) {
22980
+ throw createCliError7(
22981
+ "CLI_PAIR_AGENT_NOT_FOUND",
22982
+ "Agent AIT is invalid. Recreate the agent before pairing."
22983
+ );
22984
+ }
22985
+ let payloadRaw;
22986
+ try {
22987
+ payloadRaw = new TextDecoder().decode(decodeBase64url(parts[1] ?? ""));
22988
+ } catch {
22989
+ throw createCliError7(
22990
+ "CLI_PAIR_AGENT_NOT_FOUND",
22991
+ "Agent AIT is invalid. Recreate the agent before pairing."
22992
+ );
22993
+ }
22994
+ let payload;
22995
+ try {
22996
+ payload = JSON.parse(payloadRaw);
22997
+ } catch {
22998
+ throw createCliError7(
22999
+ "CLI_PAIR_AGENT_NOT_FOUND",
23000
+ "Agent AIT is invalid. Recreate the agent before pairing."
23001
+ );
23002
+ }
23003
+ if (!isRecord9(payload) || typeof payload.sub !== "string") {
23004
+ throw createCliError7(
23005
+ "CLI_PAIR_AGENT_NOT_FOUND",
23006
+ "Agent AIT is invalid. Recreate the agent before pairing."
23007
+ );
23008
+ }
23009
+ const candidate = payload.sub.trim();
23010
+ try {
23011
+ const parsed = parseDid(candidate);
23012
+ if (parsed.kind !== "agent") {
23013
+ throw new Error("invalid kind");
23014
+ }
23015
+ } catch {
23016
+ throw createCliError7(
23017
+ "CLI_PAIR_AGENT_NOT_FOUND",
23018
+ "Agent AIT is invalid. Recreate the agent before pairing."
23019
+ );
23020
+ }
23021
+ return candidate;
23022
+ }
22556
23023
  function parsePeerAlias2(value) {
22557
23024
  if (value.length === 0 || value.length > 128) {
22558
23025
  throw createCliError7(
@@ -22684,6 +23151,20 @@ function parseTtlSeconds(value) {
22684
23151
  }
22685
23152
  return parsed;
22686
23153
  }
23154
+ function parsePositiveIntegerOption(input) {
23155
+ const raw = parseNonEmptyString9(input.value);
23156
+ if (raw.length === 0) {
23157
+ return input.defaultValue;
23158
+ }
23159
+ const parsed = Number.parseInt(raw, 10);
23160
+ if (!Number.isInteger(parsed) || parsed < 1) {
23161
+ throw createCliError7(
23162
+ "CLI_PAIR_STATUS_WAIT_INVALID",
23163
+ `${input.optionName} must be a positive integer`
23164
+ );
23165
+ }
23166
+ return parsed;
23167
+ }
22687
23168
  function parseProxyUrl2(candidate) {
22688
23169
  try {
22689
23170
  const parsed = new URL(candidate);
@@ -22767,11 +23248,8 @@ async function executePairRequest(input) {
22767
23248
  function mapStartPairError(status, payload) {
22768
23249
  const code = extractErrorCode(payload);
22769
23250
  const message2 = extractErrorMessage(payload);
22770
- if (code === "PROXY_PAIR_OWNER_PAT_INVALID" || status === 401) {
22771
- return message2 ? `Owner PAT is invalid (401): ${message2}` : "Owner PAT is invalid or expired (401).";
22772
- }
22773
- if (code === "PROXY_PAIR_OWNER_PAT_FORBIDDEN" || status === 403) {
22774
- return message2 ? `Owner PAT does not control initiator agent DID (403): ${message2}` : "Owner PAT does not control initiator agent DID (403).";
23251
+ if (code === "PROXY_PAIR_OWNERSHIP_FORBIDDEN" || status === 403) {
23252
+ return message2 ? `Initiator agent ownership check failed (403): ${message2}` : "Initiator agent ownership check failed (403).";
22775
23253
  }
22776
23254
  if (status === 400) {
22777
23255
  return message2 ? `Pair start request is invalid (400): ${message2}` : "Pair start request is invalid (400).";
@@ -22804,6 +23282,29 @@ function mapConfirmPairError(status, payload) {
22804
23282
  }
22805
23283
  return `Pair confirm failed (${status})`;
22806
23284
  }
23285
+ function mapStatusPairError(status, payload) {
23286
+ const code = extractErrorCode(payload);
23287
+ const message2 = extractErrorMessage(payload);
23288
+ if (code === "PROXY_PAIR_TICKET_NOT_FOUND" || status === 404) {
23289
+ return "Pairing ticket not found";
23290
+ }
23291
+ if (code === "PROXY_PAIR_TICKET_EXPIRED" || status === 410) {
23292
+ return "Pairing ticket has expired";
23293
+ }
23294
+ if (code === "PROXY_PAIR_STATUS_FORBIDDEN" || status === 403) {
23295
+ return message2 ? `Pair status request is forbidden (403): ${message2}` : "Pair status request is forbidden (403).";
23296
+ }
23297
+ if (status === 400) {
23298
+ return message2 ? `Pair status request is invalid (400): ${message2}` : "Pair status request is invalid (400).";
23299
+ }
23300
+ if (status >= 500) {
23301
+ return `Proxy pairing service is unavailable (${status}).`;
23302
+ }
23303
+ if (message2) {
23304
+ return `Pair status failed (${status}): ${message2}`;
23305
+ }
23306
+ return `Pair status failed (${status})`;
23307
+ }
22807
23308
  function parsePairStartResponse(payload) {
22808
23309
  if (!isRecord9(payload)) {
22809
23310
  throw createCliError7(
@@ -22848,6 +23349,44 @@ function parsePairConfirmResponse(payload) {
22848
23349
  responderAgentDid
22849
23350
  };
22850
23351
  }
23352
+ function parsePairStatusResponse(payload) {
23353
+ if (!isRecord9(payload)) {
23354
+ throw createCliError7(
23355
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23356
+ "Pair status response is invalid"
23357
+ );
23358
+ }
23359
+ const statusRaw = parseNonEmptyString9(payload.status);
23360
+ if (statusRaw !== "pending" && statusRaw !== "confirmed") {
23361
+ throw createCliError7(
23362
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23363
+ "Pair status response is invalid"
23364
+ );
23365
+ }
23366
+ const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
23367
+ const responderAgentDid = parseNonEmptyString9(payload.responderAgentDid);
23368
+ const expiresAt = parseNonEmptyString9(payload.expiresAt);
23369
+ const confirmedAt = parseNonEmptyString9(payload.confirmedAt);
23370
+ if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
23371
+ throw createCliError7(
23372
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23373
+ "Pair status response is invalid"
23374
+ );
23375
+ }
23376
+ if (statusRaw === "confirmed" && responderAgentDid.length === 0) {
23377
+ throw createCliError7(
23378
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23379
+ "Pair status response is invalid"
23380
+ );
23381
+ }
23382
+ return {
23383
+ status: statusRaw,
23384
+ initiatorAgentDid,
23385
+ responderAgentDid: responderAgentDid.length > 0 ? responderAgentDid : void 0,
23386
+ expiresAt,
23387
+ confirmedAt: confirmedAt.length > 0 ? confirmedAt : void 0
23388
+ };
23389
+ }
22851
23390
  async function readAgentProofMaterial(agentName, dependencies) {
22852
23391
  const readFileImpl = dependencies.readFileImpl ?? readFile5;
22853
23392
  const getConfigDirImpl = dependencies.getConfigDirImpl ?? getConfigDir;
@@ -22911,16 +23450,6 @@ async function readAgentProofMaterial(agentName, dependencies) {
22911
23450
  secretKey
22912
23451
  };
22913
23452
  }
22914
- function resolveOwnerPat(options) {
22915
- const ownerPat = parseNonEmptyString9(options.explicitOwnerPat) || parseNonEmptyString9(options.config.apiKey);
22916
- if (ownerPat.length > 0) {
22917
- return ownerPat;
22918
- }
22919
- throw createCliError7(
22920
- "CLI_PAIR_START_OWNER_PAT_REQUIRED",
22921
- "Owner PAT is required. Pass --owner-pat <token> or configure API key with `clawdentity invite redeem` / `clawdentity config set apiKey <token>`."
22922
- );
22923
- }
22924
23453
  async function buildSignedHeaders(input) {
22925
23454
  const signed = await signHttpRequest({
22926
23455
  method: input.method,
@@ -23076,10 +23605,6 @@ async function startPairing(agentName, options, dependencies = {}) {
23076
23605
  const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
23077
23606
  const ttlSeconds = parseTtlSeconds(options.ttlSeconds);
23078
23607
  const config2 = await resolveConfigImpl();
23079
- const ownerPat = resolveOwnerPat({
23080
- explicitOwnerPat: options.ownerPat,
23081
- config: config2
23082
- });
23083
23608
  const proxyUrl = await resolveProxyUrl({
23084
23609
  config: config2,
23085
23610
  fetchImpl
@@ -23111,7 +23636,6 @@ async function startPairing(agentName, options, dependencies = {}) {
23111
23636
  headers: {
23112
23637
  authorization: `Claw ${ait}`,
23113
23638
  "content-type": "application/json",
23114
- [OWNER_PAT_HEADER]: ownerPat,
23115
23639
  ...signedHeaders
23116
23640
  },
23117
23641
  body: requestBody
@@ -23238,14 +23762,157 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23238
23762
  peerAlias
23239
23763
  };
23240
23764
  }
23765
+ async function getPairingStatusOnce(agentName, options, dependencies = {}) {
23766
+ const fetchImpl = dependencies.fetchImpl ?? fetch;
23767
+ const resolveConfigImpl = dependencies.resolveConfigImpl ?? resolveConfig;
23768
+ const nowSecondsImpl = dependencies.nowSecondsImpl ?? (() => Math.floor(Date.now() / 1e3));
23769
+ const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
23770
+ const config2 = await resolveConfigImpl();
23771
+ const proxyUrl = await resolveProxyUrl({
23772
+ config: config2,
23773
+ fetchImpl
23774
+ });
23775
+ const ticket = parsePairingTicket(options.ticket);
23776
+ const { ait, secretKey } = await readAgentProofMaterial(
23777
+ agentName,
23778
+ dependencies
23779
+ );
23780
+ const callerAgentDid = parseAitAgentDid(ait);
23781
+ const requestUrl = toProxyRequestUrl(proxyUrl, PAIR_STATUS_PATH);
23782
+ const requestBody = JSON.stringify({ ticket });
23783
+ const bodyBytes = new TextEncoder().encode(requestBody);
23784
+ const timestampSeconds = nowSecondsImpl();
23785
+ const nonce = nonceFactoryImpl();
23786
+ const signedHeaders = await buildSignedHeaders({
23787
+ method: "POST",
23788
+ requestUrl,
23789
+ bodyBytes,
23790
+ secretKey,
23791
+ timestampSeconds,
23792
+ nonce
23793
+ });
23794
+ const response = await executePairRequest({
23795
+ fetchImpl,
23796
+ url: requestUrl,
23797
+ init: {
23798
+ method: "POST",
23799
+ headers: {
23800
+ authorization: `Claw ${ait}`,
23801
+ "content-type": "application/json",
23802
+ ...signedHeaders
23803
+ },
23804
+ body: requestBody
23805
+ }
23806
+ });
23807
+ const responseBody = await parseJsonResponse6(response);
23808
+ if (!response.ok) {
23809
+ throw createCliError7(
23810
+ "CLI_PAIR_STATUS_FAILED",
23811
+ mapStatusPairError(response.status, responseBody)
23812
+ );
23813
+ }
23814
+ const parsed = parsePairStatusResponse(responseBody);
23815
+ let peerAlias;
23816
+ if (parsed.status === "confirmed") {
23817
+ const responderAgentDid = parsed.responderAgentDid;
23818
+ if (!responderAgentDid) {
23819
+ throw createCliError7(
23820
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23821
+ "Pair status response is invalid"
23822
+ );
23823
+ }
23824
+ const peerDid = callerAgentDid === parsed.initiatorAgentDid ? responderAgentDid : callerAgentDid === responderAgentDid ? parsed.initiatorAgentDid : void 0;
23825
+ if (!peerDid) {
23826
+ throw createCliError7(
23827
+ "CLI_PAIR_STATUS_FORBIDDEN",
23828
+ "Local agent is not a participant in the pairing ticket"
23829
+ );
23830
+ }
23831
+ peerAlias = await persistPairedPeer({
23832
+ ticket,
23833
+ peerDid,
23834
+ dependencies
23835
+ });
23836
+ }
23837
+ return {
23838
+ ...parsed,
23839
+ proxyUrl,
23840
+ peerAlias
23841
+ };
23842
+ }
23843
+ async function waitForPairingStatus(input) {
23844
+ const nowSecondsImpl = input.dependencies.nowSecondsImpl ?? (() => Math.floor(Date.now() / 1e3));
23845
+ const sleepImpl = input.dependencies.sleepImpl ?? (async (ms) => {
23846
+ await new Promise((resolve2) => {
23847
+ setTimeout(resolve2, ms);
23848
+ });
23849
+ });
23850
+ const deadlineSeconds = nowSecondsImpl() + input.waitSeconds;
23851
+ while (true) {
23852
+ const status = await getPairingStatusOnce(
23853
+ input.agentName,
23854
+ { ticket: input.ticket },
23855
+ input.dependencies
23856
+ );
23857
+ if (status.status === "confirmed") {
23858
+ return status;
23859
+ }
23860
+ const nowSeconds = nowSecondsImpl();
23861
+ if (nowSeconds >= deadlineSeconds) {
23862
+ throw createCliError7(
23863
+ "CLI_PAIR_STATUS_WAIT_TIMEOUT",
23864
+ `Pairing is still pending after ${input.waitSeconds} seconds`
23865
+ );
23866
+ }
23867
+ const remainingSeconds = Math.max(0, deadlineSeconds - nowSeconds);
23868
+ const sleepSeconds = Math.min(input.pollIntervalSeconds, remainingSeconds);
23869
+ await sleepImpl(sleepSeconds * 1e3);
23870
+ }
23871
+ }
23872
+ async function getPairingStatus(agentName, options, dependencies = {}) {
23873
+ const ticketRaw = parseNonEmptyString9(options.ticket);
23874
+ if (ticketRaw.length === 0) {
23875
+ throw createCliError7(
23876
+ "CLI_PAIR_STATUS_TICKET_REQUIRED",
23877
+ "Pair status requires --ticket <clwpair1_...>"
23878
+ );
23879
+ }
23880
+ const ticket = parsePairingTicket(ticketRaw);
23881
+ if (options.wait !== true) {
23882
+ return getPairingStatusOnce(agentName, { ticket }, dependencies);
23883
+ }
23884
+ const waitSeconds = parsePositiveIntegerOption({
23885
+ value: options.waitSeconds,
23886
+ optionName: "waitSeconds",
23887
+ defaultValue: DEFAULT_STATUS_WAIT_SECONDS
23888
+ });
23889
+ const pollIntervalSeconds = parsePositiveIntegerOption({
23890
+ value: options.pollIntervalSeconds,
23891
+ optionName: "pollIntervalSeconds",
23892
+ defaultValue: DEFAULT_STATUS_POLL_INTERVAL_SECONDS
23893
+ });
23894
+ return waitForPairingStatus({
23895
+ agentName,
23896
+ ticket,
23897
+ waitSeconds,
23898
+ pollIntervalSeconds,
23899
+ dependencies
23900
+ });
23901
+ }
23241
23902
  var createPairCommand = (dependencies = {}) => {
23242
23903
  const pairCommand = new Command8("pair").description(
23243
23904
  "Manage proxy trust pairing between agents"
23244
23905
  );
23245
- pairCommand.command("start <agentName>").description("Start pairing and issue one-time pairing ticket").option(
23246
- "--owner-pat <token>",
23247
- "Owner PAT override (defaults to configured API key)"
23248
- ).option("--ttl-seconds <seconds>", "Pairing ticket expiry in seconds").option("--qr", "Generate a local QR file for sharing").option("--qr-output <path>", "Write QR PNG to a specific file path").action(
23906
+ pairCommand.command("start <agentName>").description("Start pairing and issue one-time pairing ticket").option("--ttl-seconds <seconds>", "Pairing ticket expiry in seconds").option("--qr", "Generate a local QR file for sharing").option("--qr-output <path>", "Write QR PNG to a specific file path").option(
23907
+ "--wait",
23908
+ "Wait for responder confirmation and auto-save peer on initiator"
23909
+ ).option(
23910
+ "--wait-seconds <seconds>",
23911
+ "Max seconds to poll for confirmation (default: 300)"
23912
+ ).option(
23913
+ "--poll-interval-seconds <seconds>",
23914
+ "Polling interval in seconds while waiting (default: 3)"
23915
+ ).action(
23249
23916
  withErrorHandling(
23250
23917
  "pair start",
23251
23918
  async (agentName, options) => {
@@ -23263,6 +23930,48 @@ var createPairCommand = (dependencies = {}) => {
23263
23930
  if (result.qrPath) {
23264
23931
  writeStdoutLine(`QR File: ${result.qrPath}`);
23265
23932
  }
23933
+ if (options.wait === true) {
23934
+ const waitSeconds = parsePositiveIntegerOption({
23935
+ value: options.waitSeconds,
23936
+ optionName: "waitSeconds",
23937
+ defaultValue: DEFAULT_STATUS_WAIT_SECONDS
23938
+ });
23939
+ const pollIntervalSeconds = parsePositiveIntegerOption({
23940
+ value: options.pollIntervalSeconds,
23941
+ optionName: "pollIntervalSeconds",
23942
+ defaultValue: DEFAULT_STATUS_POLL_INTERVAL_SECONDS
23943
+ });
23944
+ writeStdoutLine(
23945
+ `Waiting for confirmation (timeout=${waitSeconds}s, interval=${pollIntervalSeconds}s) ...`
23946
+ );
23947
+ const status = await waitForPairingStatus({
23948
+ agentName,
23949
+ ticket: result.ticket,
23950
+ waitSeconds,
23951
+ pollIntervalSeconds,
23952
+ dependencies
23953
+ });
23954
+ logger9.info("cli.pair_status_confirmed_after_start", {
23955
+ initiatorAgentDid: status.initiatorAgentDid,
23956
+ responderAgentDid: status.responderAgentDid,
23957
+ peerAlias: status.peerAlias
23958
+ });
23959
+ writeStdoutLine("Pairing confirmed");
23960
+ writeStdoutLine(`Status: ${status.status}`);
23961
+ if (status.initiatorAgentDid) {
23962
+ writeStdoutLine(
23963
+ `Initiator Agent DID: ${status.initiatorAgentDid}`
23964
+ );
23965
+ }
23966
+ if (status.responderAgentDid) {
23967
+ writeStdoutLine(
23968
+ `Responder Agent DID: ${status.responderAgentDid}`
23969
+ );
23970
+ }
23971
+ if (status.peerAlias) {
23972
+ writeStdoutLine(`Peer alias saved: ${status.peerAlias}`);
23973
+ }
23974
+ }
23266
23975
  }
23267
23976
  )
23268
23977
  );
@@ -23287,6 +23996,43 @@ var createPairCommand = (dependencies = {}) => {
23287
23996
  }
23288
23997
  )
23289
23998
  );
23999
+ pairCommand.command("status <agentName>").description("Check pairing ticket status and sync local peer on confirm").option("--ticket <ticket>", "One-time pairing ticket (clwpair1_...)").option("--wait", "Poll until ticket is confirmed or timeout is reached").option(
24000
+ "--wait-seconds <seconds>",
24001
+ "Max seconds to poll for confirmation (default: 300)"
24002
+ ).option(
24003
+ "--poll-interval-seconds <seconds>",
24004
+ "Polling interval in seconds while waiting (default: 3)"
24005
+ ).action(
24006
+ withErrorHandling(
24007
+ "pair status",
24008
+ async (agentName, options) => {
24009
+ const result = await getPairingStatus(
24010
+ agentName,
24011
+ options,
24012
+ dependencies
24013
+ );
24014
+ logger9.info("cli.pair_status", {
24015
+ initiatorAgentDid: result.initiatorAgentDid,
24016
+ responderAgentDid: result.responderAgentDid,
24017
+ status: result.status,
24018
+ proxyUrl: result.proxyUrl,
24019
+ peerAlias: result.peerAlias
24020
+ });
24021
+ writeStdoutLine(`Status: ${result.status}`);
24022
+ writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24023
+ if (result.responderAgentDid) {
24024
+ writeStdoutLine(`Responder Agent DID: ${result.responderAgentDid}`);
24025
+ }
24026
+ writeStdoutLine(`Expires At: ${result.expiresAt}`);
24027
+ if (result.confirmedAt) {
24028
+ writeStdoutLine(`Confirmed At: ${result.confirmedAt}`);
24029
+ }
24030
+ if (result.peerAlias) {
24031
+ writeStdoutLine(`Peer alias saved: ${result.peerAlias}`);
24032
+ }
24033
+ }
24034
+ )
24035
+ );
23290
24036
  return pairCommand;
23291
24037
  };
23292
24038
 
@@ -23299,7 +24045,7 @@ import { access as access3, copyFile as copyFile2, mkdir as mkdir7, readdir as r
23299
24045
  import { createRequire } from "module";
23300
24046
  import { homedir as homedir4 } from "os";
23301
24047
  import { dirname as dirname6, join as join8, relative } from "path";
23302
- import { fileURLToPath as fileURLToPath2 } from "url";
24048
+ import { fileURLToPath as fileURLToPath3 } from "url";
23303
24049
  var OPENCLAW_DIR_NAME2 = ".openclaw";
23304
24050
  var SKILL_PACKAGE_NAME = "@clawdentity/openclaw-skill";
23305
24051
  var SKILL_DIR_NAME2 = "clawdentity-openclaw-relay";
@@ -23344,7 +24090,7 @@ function resolveSkillPackageRoot(input) {
23344
24090
  return overriddenRoot.trim();
23345
24091
  }
23346
24092
  const bundledSkillRoot = join8(
23347
- dirname6(fileURLToPath2(import.meta.url)),
24093
+ dirname6(fileURLToPath3(import.meta.url)),
23348
24094
  "..",
23349
24095
  "skill-bundle",
23350
24096
  "openclaw-skill"
@@ -23359,7 +24105,7 @@ function resolveSkillPackageRoot(input) {
23359
24105
  return dirname6(packageJsonPath);
23360
24106
  } catch {
23361
24107
  const workspaceFallbackRoot = join8(
23362
- dirname6(fileURLToPath2(import.meta.url)),
24108
+ dirname6(fileURLToPath3(import.meta.url)),
23363
24109
  "..",
23364
24110
  "..",
23365
24111
  "openclaw-skill"
@@ -23452,11 +24198,7 @@ async function resolveArtifacts(input) {
23452
24198
  }
23453
24199
  });
23454
24200
  }
23455
- const targetSkillRoot = join8(
23456
- input.openclawDir,
23457
- "skills",
23458
- SKILL_DIR_NAME2
23459
- );
24201
+ const targetSkillRoot = join8(input.openclawDir, "skills", SKILL_DIR_NAME2);
23460
24202
  const artifacts = [
23461
24203
  {
23462
24204
  sourcePath: skillDocSource,