@silicaclaw/cli 2026.3.19-11 → 2026.3.19-13

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/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## v1.0 beta - 2026-03-19
4
4
 
5
+ ### 2026.3.19-13
6
+
7
+ - release build:
8
+ - prepared another fresh date-based package build without publishing
9
+ - regenerated the npm tarball through the release packing workflow
10
+
11
+ ### 2026.3.19-12
12
+
13
+ - release build:
14
+ - prepared another fresh date-based package build without publishing
15
+ - regenerated the npm tarball through the release packing workflow
16
+
5
17
  ### 2026.3.19-11
6
18
 
7
19
  - release build:
package/VERSION CHANGED
@@ -1 +1 @@
1
- v2026.3.19-11
1
+ v2026.3.19-13
@@ -141,6 +141,7 @@ type OpenClawBridgeConfigView = {
141
141
  };
142
142
  export declare class LocalNodeService {
143
143
  private workspaceRoot;
144
+ private projectRoot;
144
145
  private storageRoot;
145
146
  private identityRepo;
146
147
  private profileRepo;
@@ -193,6 +194,7 @@ export declare class LocalNodeService {
193
194
  private appVersion;
194
195
  constructor(options?: {
195
196
  workspaceRoot?: string;
197
+ projectRoot?: string;
196
198
  storageRoot?: string;
197
199
  });
198
200
  start(): Promise<void>;
@@ -445,6 +447,7 @@ export declare class LocalNodeService {
445
447
  };
446
448
  getRuntimePaths(): {
447
449
  workspace_root: string;
450
+ project_root: string;
448
451
  storage_root: string;
449
452
  data_dir: string;
450
453
  social_runtime_path: string;
@@ -700,6 +703,7 @@ export declare class LocalNodeService {
700
703
  private persistSocialMessageObservations;
701
704
  private log;
702
705
  private getAdapterDiagnostics;
706
+ private getResolvedRealtimeNetworkSummary;
703
707
  private toPublicProfileSummary;
704
708
  private fingerprintPublicKey;
705
709
  private getOnboardingSummary;
@@ -89,13 +89,33 @@ function resolveWorkspaceRoot(cwd = process.cwd()) {
89
89
  }
90
90
  return cwd;
91
91
  }
92
+ function resolveProjectRoot(appRoot, cwd = process.cwd()) {
93
+ const envRoot = String(process.env.SILICACLAW_WORKSPACE_DIR || "").trim();
94
+ if (envRoot) {
95
+ return (0, path_1.resolve)(envRoot);
96
+ }
97
+ if (!(0, fs_1.existsSync)((0, path_1.resolve)(cwd, "apps", "local-console", "package.json"))) {
98
+ return (0, path_1.resolve)(cwd);
99
+ }
100
+ return appRoot;
101
+ }
92
102
  function resolveStorageRoot(workspaceRoot, cwd = process.cwd()) {
103
+ const home = process.env.HOME || (0, os_1.homedir)();
104
+ if (home) {
105
+ return (0, path_1.resolve)(home, ".silicaclaw", "local-console");
106
+ }
93
107
  const appRoot = (0, path_1.resolve)(workspaceRoot, "apps", "local-console");
94
108
  if ((0, fs_1.existsSync)((0, path_1.resolve)(appRoot, "package.json"))) {
95
109
  return appRoot;
96
110
  }
97
111
  return cwd;
98
112
  }
113
+ function defaultOpenClawSourceDir(rootDir) {
114
+ if ((0, fs_1.existsSync)((0, path_1.resolve)(rootDir, "openclaw.mjs")) || (0, fs_1.existsSync)((0, path_1.resolve)(rootDir, "package.json"))) {
115
+ return rootDir;
116
+ }
117
+ return (0, path_1.resolve)(rootDir, "..", "openclaw");
118
+ }
99
119
  function resolveExecutableInPath(binName) {
100
120
  const pathValue = String(process.env.PATH || "").trim();
101
121
  if (!pathValue)
@@ -206,7 +226,7 @@ function detectOpenClawInstallation(workspaceRoot) {
206
226
  }
207
227
  function readOpenClawConfiguredGateway(workspaceRoot) {
208
228
  const configuredSourceDir = String(process.env.OPENCLAW_SOURCE_DIR || "").trim();
209
- const defaultSourceDir = (0, path_1.resolve)(workspaceRoot, "..", "openclaw");
229
+ const defaultSourceDir = defaultOpenClawSourceDir(workspaceRoot);
210
230
  const sourceDir = configuredSourceDir || defaultSourceDir;
211
231
  const homeDir = (0, path_1.resolve)(process.env.HOME || "", ".openclaw");
212
232
  const explicitConfigPath = String(process.env.OPENCLAW_CONFIG_PATH || "").trim();
@@ -384,7 +404,7 @@ function detectOwnerDeliveryStatus(params) {
384
404
  const ownerAccount = String(process.env.OPENCLAW_OWNER_ACCOUNT || "").trim();
385
405
  const explicitOpenClawBin = String(process.env.OPENCLAW_BIN || "").trim();
386
406
  const configuredSourceDir = String(process.env.OPENCLAW_SOURCE_DIR || "").trim();
387
- const defaultSourceDir = (0, path_1.resolve)(params.workspaceRoot, "..", "openclaw");
407
+ const defaultSourceDir = defaultOpenClawSourceDir(params.workspaceRoot);
388
408
  const openclawSourceDir = configuredSourceDir || defaultSourceDir;
389
409
  const openclawSourceEntry = existingPathOrNull((0, path_1.resolve)(openclawSourceDir, "openclaw.mjs"));
390
410
  const openclawCommandResolvable = Boolean(explicitOpenClawBin || resolveExecutableInPath("openclaw") || openclawSourceEntry);
@@ -450,11 +470,15 @@ function hasMeaningfulJson(filePath) {
450
470
  return false;
451
471
  }
452
472
  }
453
- function migrateLegacyDataIfNeeded(workspaceRoot, storageRoot) {
454
- const legacyDataDir = (0, path_1.resolve)(workspaceRoot, "data");
473
+ function migrateLegacyDataIfNeeded(appRoot, projectRoot, storageRoot) {
455
474
  const targetDataDir = (0, path_1.resolve)(storageRoot, "data");
456
- if (legacyDataDir === targetDataDir)
457
- return;
475
+ const legacyDataDirs = [
476
+ (0, path_1.resolve)(appRoot, "data"),
477
+ (0, path_1.resolve)(appRoot, "apps", "local-console", "data"),
478
+ (0, path_1.resolve)(projectRoot, "data"),
479
+ (0, path_1.resolve)(projectRoot, "apps", "local-console", "data"),
480
+ (0, path_1.resolve)(process.cwd(), "data"),
481
+ ].filter((dir, index, list) => list.indexOf(dir) === index && dir !== targetDataDir);
458
482
  const files = [
459
483
  "identity.json",
460
484
  "profile.json",
@@ -464,16 +488,43 @@ function migrateLegacyDataIfNeeded(workspaceRoot, storageRoot) {
464
488
  "social-message-observations.json",
465
489
  ];
466
490
  for (const file of files) {
467
- const src = (0, path_1.resolve)(legacyDataDir, file);
468
491
  const dst = (0, path_1.resolve)(targetDataDir, file);
469
- if (!(0, fs_1.existsSync)(src))
470
- continue;
471
492
  if (hasMeaningfulJson(dst))
472
493
  continue;
473
- if (!hasMeaningfulJson(src))
494
+ for (const legacyDataDir of legacyDataDirs) {
495
+ const src = (0, path_1.resolve)(legacyDataDir, file);
496
+ if (!(0, fs_1.existsSync)(src))
497
+ continue;
498
+ if (!hasMeaningfulJson(src))
499
+ continue;
500
+ (0, fs_1.mkdirSync)(targetDataDir, { recursive: true });
501
+ (0, fs_1.copyFileSync)(src, dst);
502
+ break;
503
+ }
504
+ }
505
+ const targetDotDir = (0, path_1.resolve)(storageRoot, ".silicaclaw");
506
+ const legacyDotDirs = [
507
+ (0, path_1.resolve)(appRoot, ".silicaclaw"),
508
+ (0, path_1.resolve)(appRoot, "apps", "local-console", ".silicaclaw"),
509
+ (0, path_1.resolve)(projectRoot, ".silicaclaw"),
510
+ (0, path_1.resolve)(projectRoot, "apps", "local-console", ".silicaclaw"),
511
+ (0, path_1.resolve)(process.cwd(), ".silicaclaw"),
512
+ ].filter((dir, index, list) => list.indexOf(dir) === index && dir !== targetDotDir);
513
+ const dotFiles = ["social.runtime.json", "social.message-governance.json"];
514
+ for (const file of dotFiles) {
515
+ const dst = (0, path_1.resolve)(targetDotDir, file);
516
+ if (hasMeaningfulJson(dst))
474
517
  continue;
475
- (0, fs_1.mkdirSync)(targetDataDir, { recursive: true });
476
- (0, fs_1.copyFileSync)(src, dst);
518
+ for (const legacyDotDir of legacyDotDirs) {
519
+ const src = (0, path_1.resolve)(legacyDotDir, file);
520
+ if (!(0, fs_1.existsSync)(src))
521
+ continue;
522
+ if (!hasMeaningfulJson(src))
523
+ continue;
524
+ (0, fs_1.mkdirSync)(targetDotDir, { recursive: true });
525
+ (0, fs_1.copyFileSync)(src, dst);
526
+ break;
527
+ }
477
528
  }
478
529
  }
479
530
  function parseListEnv(raw) {
@@ -487,6 +538,7 @@ function dedupeStrings(values) {
487
538
  }
488
539
  class LocalNodeService {
489
540
  workspaceRoot;
541
+ projectRoot;
490
542
  storageRoot;
491
543
  identityRepo;
492
544
  profileRepo;
@@ -544,9 +596,10 @@ class LocalNodeService {
544
596
  appVersion = "unknown";
545
597
  constructor(options) {
546
598
  this.workspaceRoot = options?.workspaceRoot || resolveWorkspaceRoot();
599
+ this.projectRoot = options?.projectRoot || resolveProjectRoot(this.workspaceRoot);
547
600
  this.storageRoot = options?.storageRoot || resolveStorageRoot(this.workspaceRoot);
548
601
  this.appVersion = readWorkspaceVersion(this.workspaceRoot);
549
- migrateLegacyDataIfNeeded(this.workspaceRoot, this.storageRoot);
602
+ migrateLegacyDataIfNeeded(this.workspaceRoot, this.projectRoot, this.storageRoot);
550
603
  this.identityRepo = new storage_1.IdentityRepo(this.storageRoot);
551
604
  this.profileRepo = new storage_1.ProfileRepo(this.storageRoot);
552
605
  this.cacheRepo = new storage_1.CacheRepo(this.storageRoot);
@@ -556,16 +609,16 @@ class LocalNodeService {
556
609
  this.socialMessageObservationRepo = new storage_1.SocialMessageObservationRepo(this.storageRoot);
557
610
  this.socialRuntimeRepo = new storage_1.SocialRuntimeRepo(this.storageRoot);
558
611
  this.messageGovernance = this.defaultMessageGovernance();
559
- let loadedSocial = (0, core_1.loadSocialConfig)(this.workspaceRoot);
612
+ let loadedSocial = (0, core_1.loadSocialConfig)(this.projectRoot);
560
613
  if (!loadedSocial.meta.found) {
561
- (0, core_1.ensureDefaultSocialMd)(this.workspaceRoot, {
614
+ (0, core_1.ensureDefaultSocialMd)(this.projectRoot, {
562
615
  display_name: this.getDefaultDisplayName(),
563
616
  bio: "Local AI agent connected to SilicaClaw",
564
617
  tags: ["openclaw", "local-first"],
565
618
  mode: "global-preview",
566
619
  public_enabled: false,
567
620
  });
568
- loadedSocial = (0, core_1.loadSocialConfig)(this.workspaceRoot);
621
+ loadedSocial = (0, core_1.loadSocialConfig)(this.projectRoot);
569
622
  this.initState.social_auto_created = true;
570
623
  }
571
624
  this.socialConfig = loadedSocial.config;
@@ -650,7 +703,9 @@ class LocalNodeService {
650
703
  };
651
704
  }
652
705
  getNetworkSummary() {
653
- const diagnostics = this.getAdapterDiagnostics();
706
+ const network = this.getResolvedRealtimeNetworkSummary();
707
+ const diagnostics = network.diagnostics;
708
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
654
709
  const peerCount = diagnostics?.peers.total ?? 0;
655
710
  return {
656
711
  status: "running",
@@ -677,29 +732,31 @@ class LocalNodeService {
677
732
  real_preview_stats: diagnostics?.stats ?? null,
678
733
  real_preview_transport_stats: diagnostics?.transport_stats ?? null,
679
734
  real_preview_discovery_stats: diagnostics?.discovery_stats ?? null,
680
- webrtc_preview: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
735
+ webrtc_preview: relayCapable
681
736
  ? {
682
- signaling_url: diagnostics.signaling_url ?? null,
683
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
684
- room: diagnostics.room ?? null,
685
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
686
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
687
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
688
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
689
- active_webrtc_peers: diagnostics.active_webrtc_peers ?? 0,
690
- reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? 0,
691
- last_join_at: diagnostics.last_join_at ?? 0,
692
- last_poll_at: diagnostics.last_poll_at ?? 0,
693
- last_publish_at: diagnostics.last_publish_at ?? 0,
694
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
695
- last_error_at: diagnostics.last_error_at ?? 0,
696
- last_error: diagnostics.last_error ?? null,
737
+ signaling_url: network.signaling_url,
738
+ signaling_endpoints: network.signaling_endpoints,
739
+ room: network.room,
740
+ bootstrap_sources: network.bootstrap_sources,
741
+ seed_peers_count: network.seed_peers_count,
742
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
743
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
744
+ active_webrtc_peers: diagnostics?.active_webrtc_peers ?? 0,
745
+ reconnect_attempts_total: diagnostics?.reconnect_attempts_total ?? 0,
746
+ last_join_at: diagnostics?.last_join_at ?? 0,
747
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
748
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
749
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
750
+ last_error_at: diagnostics?.last_error_at ?? 0,
751
+ last_error: diagnostics?.last_error ?? null,
697
752
  }
698
753
  : null,
699
754
  };
700
755
  }
701
756
  getNetworkConfig() {
702
- const diagnostics = this.getAdapterDiagnostics();
757
+ const network = this.getResolvedRealtimeNetworkSummary();
758
+ const diagnostics = network.diagnostics;
759
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
703
760
  return {
704
761
  adapter: this.adapterMode,
705
762
  mode: this.networkMode,
@@ -713,23 +770,23 @@ class LocalNodeService {
713
770
  },
714
771
  limits: diagnostics?.limits ?? null,
715
772
  adapter_config: diagnostics?.config ?? null,
716
- adapter_extra: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
773
+ adapter_extra: relayCapable
717
774
  ? {
718
- signaling_url: diagnostics.signaling_url ?? null,
719
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
720
- room: diagnostics.room ?? null,
721
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
722
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
723
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
724
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
725
- connection_states_summary: diagnostics.connection_states_summary ?? null,
726
- datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
727
- last_join_at: diagnostics.last_join_at ?? 0,
728
- last_poll_at: diagnostics.last_poll_at ?? 0,
729
- last_publish_at: diagnostics.last_publish_at ?? 0,
730
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
731
- last_error_at: diagnostics.last_error_at ?? 0,
732
- last_error: diagnostics.last_error ?? null,
775
+ signaling_url: network.signaling_url,
776
+ signaling_endpoints: network.signaling_endpoints,
777
+ room: network.room,
778
+ bootstrap_sources: network.bootstrap_sources,
779
+ seed_peers_count: network.seed_peers_count,
780
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
781
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
782
+ connection_states_summary: diagnostics?.connection_states_summary ?? null,
783
+ datachannel_states_summary: diagnostics?.datachannel_states_summary ?? null,
784
+ last_join_at: diagnostics?.last_join_at ?? 0,
785
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
786
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
787
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
788
+ last_error_at: diagnostics?.last_error_at ?? 0,
789
+ last_error: diagnostics?.last_error ?? null,
733
790
  }
734
791
  : null,
735
792
  env: {
@@ -762,7 +819,9 @@ class LocalNodeService {
762
819
  };
763
820
  }
764
821
  getNetworkStats() {
765
- const diagnostics = this.getAdapterDiagnostics();
822
+ const network = this.getResolvedRealtimeNetworkSummary();
823
+ const diagnostics = network.diagnostics;
824
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
766
825
  const peers = diagnostics?.peers?.items ?? [];
767
826
  const online = peers.filter((peer) => peer.status === "online").length;
768
827
  return {
@@ -788,33 +847,34 @@ class LocalNodeService {
788
847
  adapter_stats: diagnostics?.stats ?? null,
789
848
  adapter_transport_stats: diagnostics?.transport_stats ?? null,
790
849
  adapter_discovery_stats: diagnostics?.discovery_stats ?? null,
791
- adapter_diagnostics_summary: diagnostics
850
+ adapter_diagnostics_summary: relayCapable || diagnostics
792
851
  ? {
793
- signaling_url: diagnostics.signaling_url ?? null,
794
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
795
- room: diagnostics.room ?? null,
796
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
797
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
798
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
799
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
800
- connection_states_summary: diagnostics.connection_states_summary ?? null,
801
- datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
802
- signaling_messages_sent_total: diagnostics.signaling_messages_sent_total ?? null,
803
- signaling_messages_received_total: diagnostics.signaling_messages_received_total ?? null,
804
- reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? null,
805
- active_webrtc_peers: diagnostics.active_webrtc_peers ?? null,
806
- last_join_at: diagnostics.last_join_at ?? 0,
807
- last_poll_at: diagnostics.last_poll_at ?? 0,
808
- last_publish_at: diagnostics.last_publish_at ?? 0,
809
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
810
- last_error_at: diagnostics.last_error_at ?? 0,
811
- last_error: diagnostics.last_error ?? null,
852
+ signaling_url: network.signaling_url,
853
+ signaling_endpoints: network.signaling_endpoints,
854
+ room: network.room,
855
+ bootstrap_sources: network.bootstrap_sources,
856
+ seed_peers_count: network.seed_peers_count,
857
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
858
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
859
+ connection_states_summary: diagnostics?.connection_states_summary ?? null,
860
+ datachannel_states_summary: diagnostics?.datachannel_states_summary ?? null,
861
+ signaling_messages_sent_total: diagnostics?.signaling_messages_sent_total ?? null,
862
+ signaling_messages_received_total: diagnostics?.signaling_messages_received_total ?? null,
863
+ reconnect_attempts_total: diagnostics?.reconnect_attempts_total ?? null,
864
+ active_webrtc_peers: diagnostics?.active_webrtc_peers ?? null,
865
+ last_join_at: diagnostics?.last_join_at ?? 0,
866
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
867
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
868
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
869
+ last_error_at: diagnostics?.last_error_at ?? 0,
870
+ last_error: diagnostics?.last_error ?? null,
812
871
  }
813
872
  : null,
814
873
  };
815
874
  }
816
875
  getPeersSummary() {
817
- const diagnostics = this.getAdapterDiagnostics();
876
+ const network = this.getResolvedRealtimeNetworkSummary();
877
+ const diagnostics = network.diagnostics;
818
878
  if (!diagnostics) {
819
879
  return {
820
880
  adapter: this.adapterMode,
@@ -837,11 +897,11 @@ class LocalNodeService {
837
897
  components: diagnostics.components,
838
898
  limits: diagnostics.limits,
839
899
  diagnostics_summary: {
840
- signaling_url: diagnostics.signaling_url ?? null,
841
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
842
- room: diagnostics.room ?? null,
843
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
844
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
900
+ signaling_url: network.signaling_url,
901
+ signaling_endpoints: network.signaling_endpoints,
902
+ room: network.room,
903
+ bootstrap_sources: network.bootstrap_sources,
904
+ seed_peers_count: network.seed_peers_count,
845
905
  discovery_events_total: diagnostics.discovery_events_total ?? 0,
846
906
  last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
847
907
  connection_states_summary: diagnostics.connection_states_summary ?? null,
@@ -885,11 +945,12 @@ class LocalNodeService {
885
945
  getRuntimePaths() {
886
946
  return {
887
947
  workspace_root: this.workspaceRoot,
948
+ project_root: this.projectRoot,
888
949
  storage_root: this.storageRoot,
889
950
  data_dir: (0, path_1.resolve)(this.storageRoot, "data"),
890
951
  social_runtime_path: (0, path_1.resolve)(this.storageRoot, ".silicaclaw", "social.runtime.json"),
891
952
  local_console_public_dir: (0, path_1.resolve)(this.workspaceRoot, "apps", "local-console", "public"),
892
- social_lookup_paths: (0, core_1.getSocialConfigSearchPaths)(this.workspaceRoot),
953
+ social_lookup_paths: (0, core_1.getSocialConfigSearchPaths)(this.projectRoot),
893
954
  social_source_path: this.socialSourcePath,
894
955
  };
895
956
  }
@@ -1035,7 +1096,7 @@ class LocalNodeService {
1035
1096
  namespace: this.networkNamespace,
1036
1097
  port: this.networkPort,
1037
1098
  };
1038
- const loaded = (0, core_1.loadSocialConfig)(this.workspaceRoot);
1099
+ const loaded = (0, core_1.loadSocialConfig)(this.projectRoot);
1039
1100
  this.socialConfig = loaded.config;
1040
1101
  this.socialSourcePath = loaded.meta.source_path;
1041
1102
  this.socialFound = loaded.meta.found;
@@ -1058,7 +1119,7 @@ class LocalNodeService {
1058
1119
  return this.getSocialConfigView();
1059
1120
  }
1060
1121
  async generateDefaultSocialMd() {
1061
- const result = (0, core_1.ensureDefaultSocialMd)(this.workspaceRoot, {
1122
+ const result = (0, core_1.ensureDefaultSocialMd)(this.projectRoot, {
1062
1123
  display_name: this.getDefaultDisplayName(),
1063
1124
  bio: "Local AI agent connected to SilicaClaw",
1064
1125
  tags: ["openclaw", "local-first"],
@@ -1147,11 +1208,11 @@ class LocalNodeService {
1147
1208
  }
1148
1209
  getOpenClawBridgeStatus() {
1149
1210
  const integration = this.getIntegrationStatus();
1150
- const openclawInstallation = detectOpenClawInstallation(this.workspaceRoot);
1151
- const openclawRuntime = detectOpenClawRuntime(this.workspaceRoot);
1211
+ const openclawInstallation = detectOpenClawInstallation(this.projectRoot);
1212
+ const openclawRuntime = detectOpenClawRuntime(this.projectRoot);
1152
1213
  const skillInstallation = detectOpenClawSkillInstallation();
1153
1214
  const ownerDelivery = detectOwnerDeliveryStatus({
1154
- workspaceRoot: this.workspaceRoot,
1215
+ workspaceRoot: this.projectRoot,
1155
1216
  connectedToSilicaclaw: integration.connected_to_silicaclaw,
1156
1217
  openclawRunning: openclawRuntime.running,
1157
1218
  skillInstalled: skillInstallation.installed,
@@ -1217,7 +1278,7 @@ class LocalNodeService {
1217
1278
  const scriptPath = (0, path_1.resolve)(this.workspaceRoot, "scripts", "install-openclaw-skill.mjs");
1218
1279
  const { stdout } = await execFileAsync(process.execPath, [scriptPath], {
1219
1280
  cwd: this.workspaceRoot,
1220
- env: process.env,
1281
+ env: { ...process.env, SILICACLAW_WORKSPACE_DIR: this.projectRoot },
1221
1282
  maxBuffer: 1024 * 1024,
1222
1283
  });
1223
1284
  const parsed = JSON.parse(String(stdout || "{}"));
@@ -1239,11 +1300,11 @@ class LocalNodeService {
1239
1300
  const homeDir = (0, path_1.resolve)(process.env.HOME || "", ".openclaw");
1240
1301
  const workspaceSkillDir = (0, path_1.resolve)(homeDir, "workspace", "skills");
1241
1302
  const legacySkillDir = (0, path_1.resolve)(homeDir, "skills");
1242
- const openclawSourceDir = (0, path_1.resolve)(this.workspaceRoot, "..", "openclaw");
1243
- const openclawRuntime = detectOpenClawRuntime(this.workspaceRoot);
1303
+ const openclawSourceDir = defaultOpenClawSourceDir(this.projectRoot);
1304
+ const openclawRuntime = detectOpenClawRuntime(this.projectRoot);
1244
1305
  return {
1245
1306
  bridge_api_base: "http://localhost:4310",
1246
- openclaw_detected: detectOpenClawInstallation(this.workspaceRoot).detected,
1307
+ openclaw_detected: detectOpenClawInstallation(this.projectRoot).detected,
1247
1308
  openclaw_running: openclawRuntime.running,
1248
1309
  openclaw_gateway_host: OPENCLAW_GATEWAY_HOST,
1249
1310
  openclaw_gateway_port: openclawRuntime.configured_gateway_port,
@@ -1613,7 +1674,7 @@ class LocalNodeService {
1613
1674
  socialConfig: this.socialConfig,
1614
1675
  existingIdentity,
1615
1676
  generatedIdentity: (0, core_1.createIdentity)(),
1616
- rootDir: this.workspaceRoot,
1677
+ rootDir: this.projectRoot,
1617
1678
  });
1618
1679
  this.identity = resolvedIdentity.identity;
1619
1680
  this.resolvedIdentitySource = resolvedIdentity.source;
@@ -1631,7 +1692,7 @@ class LocalNodeService {
1631
1692
  socialConfig: this.socialConfig,
1632
1693
  agentId: this.identity.agent_id,
1633
1694
  existingProfile: existingProfile && existingProfile.agent_id === this.identity.agent_id ? existingProfile : null,
1634
- rootDir: this.workspaceRoot,
1695
+ rootDir: this.projectRoot,
1635
1696
  });
1636
1697
  this.profile = (0, core_1.signProfile)(profileInput, this.identity);
1637
1698
  if (!existingProfile || existingProfile.agent_id !== this.identity.agent_id) {
@@ -1660,7 +1721,7 @@ class LocalNodeService {
1660
1721
  socialConfig: this.socialConfig,
1661
1722
  agentId: this.identity.agent_id,
1662
1723
  existingProfile: this.profile,
1663
- rootDir: this.workspaceRoot,
1724
+ rootDir: this.projectRoot,
1664
1725
  });
1665
1726
  const nextProfile = (0, core_1.signProfile)(nextProfileInput, this.identity);
1666
1727
  this.profile = nextProfile;
@@ -1961,6 +2022,18 @@ class LocalNodeService {
1961
2022
  }
1962
2023
  return this.network.getDiagnostics();
1963
2024
  }
2025
+ getResolvedRealtimeNetworkSummary() {
2026
+ const diagnostics = this.getAdapterDiagnostics();
2027
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
2028
+ return {
2029
+ diagnostics,
2030
+ signaling_url: diagnostics?.signaling_url ?? (relayCapable ? this.webrtcSignalingUrls[0] ?? null : null),
2031
+ signaling_endpoints: diagnostics?.signaling_endpoints ?? (relayCapable ? this.webrtcSignalingUrls : []),
2032
+ room: diagnostics?.room ?? (relayCapable ? this.webrtcRoom : null),
2033
+ bootstrap_sources: diagnostics?.bootstrap_sources ?? (relayCapable ? this.webrtcBootstrapSources : []),
2034
+ seed_peers_count: diagnostics?.seed_peers_count ?? this.webrtcSeedPeers.length,
2035
+ };
2036
+ }
1964
2037
  toPublicProfileSummary(profile, options) {
1965
2038
  const lastSeenAt = options?.last_seen_at ?? this.directory.presence[profile.agent_id] ?? 0;
1966
2039
  const online = (0, core_1.isAgentOnline)(lastSeenAt, Date.now(), PRESENCE_TTL_MS);
@@ -4,7 +4,7 @@ import { execFile, spawnSync } from "child_process";
4
4
  import { resolve } from "path";
5
5
  import { accessSync, constants, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from "fs";
6
6
  import { createHash } from "crypto";
7
- import { hostname } from "os";
7
+ import { homedir, hostname } from "os";
8
8
  import { promisify } from "util";
9
9
  import {
10
10
  AgentIdentity,
@@ -143,7 +143,22 @@ function resolveWorkspaceRoot(cwd = process.cwd()): string {
143
143
  return cwd;
144
144
  }
145
145
 
146
+ function resolveProjectRoot(appRoot: string, cwd = process.cwd()): string {
147
+ const envRoot = String(process.env.SILICACLAW_WORKSPACE_DIR || "").trim();
148
+ if (envRoot) {
149
+ return resolve(envRoot);
150
+ }
151
+ if (!existsSync(resolve(cwd, "apps", "local-console", "package.json"))) {
152
+ return resolve(cwd);
153
+ }
154
+ return appRoot;
155
+ }
156
+
146
157
  function resolveStorageRoot(workspaceRoot: string, cwd = process.cwd()): string {
158
+ const home = process.env.HOME || homedir();
159
+ if (home) {
160
+ return resolve(home, ".silicaclaw", "local-console");
161
+ }
147
162
  const appRoot = resolve(workspaceRoot, "apps", "local-console");
148
163
  if (existsSync(resolve(appRoot, "package.json"))) {
149
164
  return appRoot;
@@ -151,6 +166,13 @@ function resolveStorageRoot(workspaceRoot: string, cwd = process.cwd()): string
151
166
  return cwd;
152
167
  }
153
168
 
169
+ function defaultOpenClawSourceDir(rootDir: string): string {
170
+ if (existsSync(resolve(rootDir, "openclaw.mjs")) || existsSync(resolve(rootDir, "package.json"))) {
171
+ return rootDir;
172
+ }
173
+ return resolve(rootDir, "..", "openclaw");
174
+ }
175
+
154
176
  function resolveExecutableInPath(binName: string): string | null {
155
177
  const pathValue = String(process.env.PATH || "").trim();
156
178
  if (!pathValue) return null;
@@ -265,7 +287,7 @@ function detectOpenClawInstallation(workspaceRoot: string) {
265
287
 
266
288
  function readOpenClawConfiguredGateway(workspaceRoot: string) {
267
289
  const configuredSourceDir = String(process.env.OPENCLAW_SOURCE_DIR || "").trim();
268
- const defaultSourceDir = resolve(workspaceRoot, "..", "openclaw");
290
+ const defaultSourceDir = defaultOpenClawSourceDir(workspaceRoot);
269
291
  const sourceDir = configuredSourceDir || defaultSourceDir;
270
292
  const homeDir = resolve(process.env.HOME || "", ".openclaw");
271
293
  const explicitConfigPath = String(process.env.OPENCLAW_CONFIG_PATH || "").trim();
@@ -453,7 +475,7 @@ function detectOwnerDeliveryStatus(params: {
453
475
  const ownerAccount = String(process.env.OPENCLAW_OWNER_ACCOUNT || "").trim();
454
476
  const explicitOpenClawBin = String(process.env.OPENCLAW_BIN || "").trim();
455
477
  const configuredSourceDir = String(process.env.OPENCLAW_SOURCE_DIR || "").trim();
456
- const defaultSourceDir = resolve(params.workspaceRoot, "..", "openclaw");
478
+ const defaultSourceDir = defaultOpenClawSourceDir(params.workspaceRoot);
457
479
  const openclawSourceDir = configuredSourceDir || defaultSourceDir;
458
480
  const openclawSourceEntry = existingPathOrNull(resolve(openclawSourceDir, "openclaw.mjs"));
459
481
  const openclawCommandResolvable = Boolean(explicitOpenClawBin || resolveExecutableInPath("openclaw") || openclawSourceEntry);
@@ -512,10 +534,15 @@ function hasMeaningfulJson(filePath: string): boolean {
512
534
  }
513
535
  }
514
536
 
515
- function migrateLegacyDataIfNeeded(workspaceRoot: string, storageRoot: string): void {
516
- const legacyDataDir = resolve(workspaceRoot, "data");
537
+ function migrateLegacyDataIfNeeded(appRoot: string, projectRoot: string, storageRoot: string): void {
517
538
  const targetDataDir = resolve(storageRoot, "data");
518
- if (legacyDataDir === targetDataDir) return;
539
+ const legacyDataDirs = [
540
+ resolve(appRoot, "data"),
541
+ resolve(appRoot, "apps", "local-console", "data"),
542
+ resolve(projectRoot, "data"),
543
+ resolve(projectRoot, "apps", "local-console", "data"),
544
+ resolve(process.cwd(), "data"),
545
+ ].filter((dir, index, list) => list.indexOf(dir) === index && dir !== targetDataDir);
519
546
  const files = [
520
547
  "identity.json",
521
548
  "profile.json",
@@ -525,13 +552,38 @@ function migrateLegacyDataIfNeeded(workspaceRoot: string, storageRoot: string):
525
552
  "social-message-observations.json",
526
553
  ];
527
554
  for (const file of files) {
528
- const src = resolve(legacyDataDir, file);
529
555
  const dst = resolve(targetDataDir, file);
530
- if (!existsSync(src)) continue;
531
556
  if (hasMeaningfulJson(dst)) continue;
532
- if (!hasMeaningfulJson(src)) continue;
533
- mkdirSync(targetDataDir, { recursive: true });
534
- copyFileSync(src, dst);
557
+ for (const legacyDataDir of legacyDataDirs) {
558
+ const src = resolve(legacyDataDir, file);
559
+ if (!existsSync(src)) continue;
560
+ if (!hasMeaningfulJson(src)) continue;
561
+ mkdirSync(targetDataDir, { recursive: true });
562
+ copyFileSync(src, dst);
563
+ break;
564
+ }
565
+ }
566
+
567
+ const targetDotDir = resolve(storageRoot, ".silicaclaw");
568
+ const legacyDotDirs = [
569
+ resolve(appRoot, ".silicaclaw"),
570
+ resolve(appRoot, "apps", "local-console", ".silicaclaw"),
571
+ resolve(projectRoot, ".silicaclaw"),
572
+ resolve(projectRoot, "apps", "local-console", ".silicaclaw"),
573
+ resolve(process.cwd(), ".silicaclaw"),
574
+ ].filter((dir, index, list) => list.indexOf(dir) === index && dir !== targetDotDir);
575
+ const dotFiles = ["social.runtime.json", "social.message-governance.json"];
576
+ for (const file of dotFiles) {
577
+ const dst = resolve(targetDotDir, file);
578
+ if (hasMeaningfulJson(dst)) continue;
579
+ for (const legacyDotDir of legacyDotDirs) {
580
+ const src = resolve(legacyDotDir, file);
581
+ if (!existsSync(src)) continue;
582
+ if (!hasMeaningfulJson(src)) continue;
583
+ mkdirSync(targetDotDir, { recursive: true });
584
+ copyFileSync(src, dst);
585
+ break;
586
+ }
535
587
  }
536
588
  }
537
589
 
@@ -699,6 +751,7 @@ type OpenClawBridgeConfigView = {
699
751
 
700
752
  export class LocalNodeService {
701
753
  private workspaceRoot: string;
754
+ private projectRoot: string;
702
755
  private storageRoot: string;
703
756
  private identityRepo: IdentityRepo;
704
757
  private profileRepo: ProfileRepo;
@@ -761,11 +814,12 @@ export class LocalNodeService {
761
814
  private webrtcBootstrapSources: string[] = [];
762
815
  private appVersion = "unknown";
763
816
 
764
- constructor(options?: { workspaceRoot?: string; storageRoot?: string }) {
817
+ constructor(options?: { workspaceRoot?: string; projectRoot?: string; storageRoot?: string }) {
765
818
  this.workspaceRoot = options?.workspaceRoot || resolveWorkspaceRoot();
819
+ this.projectRoot = options?.projectRoot || resolveProjectRoot(this.workspaceRoot);
766
820
  this.storageRoot = options?.storageRoot || resolveStorageRoot(this.workspaceRoot);
767
821
  this.appVersion = readWorkspaceVersion(this.workspaceRoot);
768
- migrateLegacyDataIfNeeded(this.workspaceRoot, this.storageRoot);
822
+ migrateLegacyDataIfNeeded(this.workspaceRoot, this.projectRoot, this.storageRoot);
769
823
 
770
824
  this.identityRepo = new IdentityRepo(this.storageRoot);
771
825
  this.profileRepo = new ProfileRepo(this.storageRoot);
@@ -777,16 +831,16 @@ export class LocalNodeService {
777
831
  this.socialRuntimeRepo = new SocialRuntimeRepo(this.storageRoot);
778
832
  this.messageGovernance = this.defaultMessageGovernance();
779
833
 
780
- let loadedSocial = loadSocialConfig(this.workspaceRoot);
834
+ let loadedSocial = loadSocialConfig(this.projectRoot);
781
835
  if (!loadedSocial.meta.found) {
782
- ensureDefaultSocialMd(this.workspaceRoot, {
836
+ ensureDefaultSocialMd(this.projectRoot, {
783
837
  display_name: this.getDefaultDisplayName(),
784
838
  bio: "Local AI agent connected to SilicaClaw",
785
839
  tags: ["openclaw", "local-first"],
786
840
  mode: "global-preview",
787
841
  public_enabled: false,
788
842
  });
789
- loadedSocial = loadSocialConfig(this.workspaceRoot);
843
+ loadedSocial = loadSocialConfig(this.projectRoot);
790
844
  this.initState.social_auto_created = true;
791
845
  }
792
846
  this.socialConfig = loadedSocial.config;
@@ -888,7 +942,9 @@ export class LocalNodeService {
888
942
  }
889
943
 
890
944
  getNetworkSummary() {
891
- const diagnostics = this.getAdapterDiagnostics();
945
+ const network = this.getResolvedRealtimeNetworkSummary();
946
+ const diagnostics = network.diagnostics;
947
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
892
948
  const peerCount = diagnostics?.peers.total ?? 0;
893
949
 
894
950
  return {
@@ -916,30 +972,32 @@ export class LocalNodeService {
916
972
  real_preview_stats: diagnostics?.stats ?? null,
917
973
  real_preview_transport_stats: diagnostics?.transport_stats ?? null,
918
974
  real_preview_discovery_stats: diagnostics?.discovery_stats ?? null,
919
- webrtc_preview: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
975
+ webrtc_preview: relayCapable
920
976
  ? {
921
- signaling_url: diagnostics.signaling_url ?? null,
922
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
923
- room: diagnostics.room ?? null,
924
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
925
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
926
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
927
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
928
- active_webrtc_peers: diagnostics.active_webrtc_peers ?? 0,
929
- reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? 0,
930
- last_join_at: diagnostics.last_join_at ?? 0,
931
- last_poll_at: diagnostics.last_poll_at ?? 0,
932
- last_publish_at: diagnostics.last_publish_at ?? 0,
933
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
934
- last_error_at: diagnostics.last_error_at ?? 0,
935
- last_error: diagnostics.last_error ?? null,
977
+ signaling_url: network.signaling_url,
978
+ signaling_endpoints: network.signaling_endpoints,
979
+ room: network.room,
980
+ bootstrap_sources: network.bootstrap_sources,
981
+ seed_peers_count: network.seed_peers_count,
982
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
983
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
984
+ active_webrtc_peers: diagnostics?.active_webrtc_peers ?? 0,
985
+ reconnect_attempts_total: diagnostics?.reconnect_attempts_total ?? 0,
986
+ last_join_at: diagnostics?.last_join_at ?? 0,
987
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
988
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
989
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
990
+ last_error_at: diagnostics?.last_error_at ?? 0,
991
+ last_error: diagnostics?.last_error ?? null,
936
992
  }
937
993
  : null,
938
994
  };
939
995
  }
940
996
 
941
997
  getNetworkConfig() {
942
- const diagnostics = this.getAdapterDiagnostics();
998
+ const network = this.getResolvedRealtimeNetworkSummary();
999
+ const diagnostics = network.diagnostics;
1000
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
943
1001
  return {
944
1002
  adapter: this.adapterMode,
945
1003
  mode: this.networkMode,
@@ -953,23 +1011,23 @@ export class LocalNodeService {
953
1011
  },
954
1012
  limits: diagnostics?.limits ?? null,
955
1013
  adapter_config: diagnostics?.config ?? null,
956
- adapter_extra: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
1014
+ adapter_extra: relayCapable
957
1015
  ? {
958
- signaling_url: diagnostics.signaling_url ?? null,
959
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
960
- room: diagnostics.room ?? null,
961
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
962
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
963
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
964
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
965
- connection_states_summary: diagnostics.connection_states_summary ?? null,
966
- datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
967
- last_join_at: diagnostics.last_join_at ?? 0,
968
- last_poll_at: diagnostics.last_poll_at ?? 0,
969
- last_publish_at: diagnostics.last_publish_at ?? 0,
970
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
971
- last_error_at: diagnostics.last_error_at ?? 0,
972
- last_error: diagnostics.last_error ?? null,
1016
+ signaling_url: network.signaling_url,
1017
+ signaling_endpoints: network.signaling_endpoints,
1018
+ room: network.room,
1019
+ bootstrap_sources: network.bootstrap_sources,
1020
+ seed_peers_count: network.seed_peers_count,
1021
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
1022
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
1023
+ connection_states_summary: diagnostics?.connection_states_summary ?? null,
1024
+ datachannel_states_summary: diagnostics?.datachannel_states_summary ?? null,
1025
+ last_join_at: diagnostics?.last_join_at ?? 0,
1026
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
1027
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
1028
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
1029
+ last_error_at: diagnostics?.last_error_at ?? 0,
1030
+ last_error: diagnostics?.last_error ?? null,
973
1031
  }
974
1032
  : null,
975
1033
  env: {
@@ -1004,7 +1062,9 @@ export class LocalNodeService {
1004
1062
  }
1005
1063
 
1006
1064
  getNetworkStats() {
1007
- const diagnostics = this.getAdapterDiagnostics();
1065
+ const network = this.getResolvedRealtimeNetworkSummary();
1066
+ const diagnostics = network.diagnostics;
1067
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
1008
1068
  const peers: Array<{ status?: string }> = diagnostics?.peers?.items ?? [];
1009
1069
  const online = peers.filter((peer: { status?: string }) => peer.status === "online").length;
1010
1070
 
@@ -1031,34 +1091,35 @@ export class LocalNodeService {
1031
1091
  adapter_stats: diagnostics?.stats ?? null,
1032
1092
  adapter_transport_stats: diagnostics?.transport_stats ?? null,
1033
1093
  adapter_discovery_stats: diagnostics?.discovery_stats ?? null,
1034
- adapter_diagnostics_summary: diagnostics
1094
+ adapter_diagnostics_summary: relayCapable || diagnostics
1035
1095
  ? {
1036
- signaling_url: diagnostics.signaling_url ?? null,
1037
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
1038
- room: diagnostics.room ?? null,
1039
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
1040
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
1041
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
1042
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
1043
- connection_states_summary: diagnostics.connection_states_summary ?? null,
1044
- datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
1045
- signaling_messages_sent_total: diagnostics.signaling_messages_sent_total ?? null,
1046
- signaling_messages_received_total: diagnostics.signaling_messages_received_total ?? null,
1047
- reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? null,
1048
- active_webrtc_peers: diagnostics.active_webrtc_peers ?? null,
1049
- last_join_at: diagnostics.last_join_at ?? 0,
1050
- last_poll_at: diagnostics.last_poll_at ?? 0,
1051
- last_publish_at: diagnostics.last_publish_at ?? 0,
1052
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
1053
- last_error_at: diagnostics.last_error_at ?? 0,
1054
- last_error: diagnostics.last_error ?? null,
1096
+ signaling_url: network.signaling_url,
1097
+ signaling_endpoints: network.signaling_endpoints,
1098
+ room: network.room,
1099
+ bootstrap_sources: network.bootstrap_sources,
1100
+ seed_peers_count: network.seed_peers_count,
1101
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
1102
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
1103
+ connection_states_summary: diagnostics?.connection_states_summary ?? null,
1104
+ datachannel_states_summary: diagnostics?.datachannel_states_summary ?? null,
1105
+ signaling_messages_sent_total: diagnostics?.signaling_messages_sent_total ?? null,
1106
+ signaling_messages_received_total: diagnostics?.signaling_messages_received_total ?? null,
1107
+ reconnect_attempts_total: diagnostics?.reconnect_attempts_total ?? null,
1108
+ active_webrtc_peers: diagnostics?.active_webrtc_peers ?? null,
1109
+ last_join_at: diagnostics?.last_join_at ?? 0,
1110
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
1111
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
1112
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
1113
+ last_error_at: diagnostics?.last_error_at ?? 0,
1114
+ last_error: diagnostics?.last_error ?? null,
1055
1115
  }
1056
1116
  : null,
1057
1117
  };
1058
1118
  }
1059
1119
 
1060
1120
  getPeersSummary() {
1061
- const diagnostics = this.getAdapterDiagnostics();
1121
+ const network = this.getResolvedRealtimeNetworkSummary();
1122
+ const diagnostics = network.diagnostics;
1062
1123
  if (!diagnostics) {
1063
1124
  return {
1064
1125
  adapter: this.adapterMode,
@@ -1081,11 +1142,11 @@ export class LocalNodeService {
1081
1142
  components: diagnostics.components,
1082
1143
  limits: diagnostics.limits,
1083
1144
  diagnostics_summary: {
1084
- signaling_url: diagnostics.signaling_url ?? null,
1085
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
1086
- room: diagnostics.room ?? null,
1087
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
1088
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
1145
+ signaling_url: network.signaling_url,
1146
+ signaling_endpoints: network.signaling_endpoints,
1147
+ room: network.room,
1148
+ bootstrap_sources: network.bootstrap_sources,
1149
+ seed_peers_count: network.seed_peers_count,
1089
1150
  discovery_events_total: diagnostics.discovery_events_total ?? 0,
1090
1151
  last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
1091
1152
  connection_states_summary: diagnostics.connection_states_summary ?? null,
@@ -1132,11 +1193,12 @@ export class LocalNodeService {
1132
1193
  getRuntimePaths() {
1133
1194
  return {
1134
1195
  workspace_root: this.workspaceRoot,
1196
+ project_root: this.projectRoot,
1135
1197
  storage_root: this.storageRoot,
1136
1198
  data_dir: resolve(this.storageRoot, "data"),
1137
1199
  social_runtime_path: resolve(this.storageRoot, ".silicaclaw", "social.runtime.json"),
1138
1200
  local_console_public_dir: resolve(this.workspaceRoot, "apps", "local-console", "public"),
1139
- social_lookup_paths: getSocialConfigSearchPaths(this.workspaceRoot),
1201
+ social_lookup_paths: getSocialConfigSearchPaths(this.projectRoot),
1140
1202
  social_source_path: this.socialSourcePath,
1141
1203
  };
1142
1204
  }
@@ -1297,7 +1359,7 @@ export class LocalNodeService {
1297
1359
  port: this.networkPort,
1298
1360
  };
1299
1361
 
1300
- const loaded = loadSocialConfig(this.workspaceRoot);
1362
+ const loaded = loadSocialConfig(this.projectRoot);
1301
1363
  this.socialConfig = loaded.config;
1302
1364
  this.socialSourcePath = loaded.meta.source_path;
1303
1365
  this.socialFound = loaded.meta.found;
@@ -1325,7 +1387,7 @@ export class LocalNodeService {
1325
1387
  }
1326
1388
 
1327
1389
  async generateDefaultSocialMd() {
1328
- const result = ensureDefaultSocialMd(this.workspaceRoot, {
1390
+ const result = ensureDefaultSocialMd(this.projectRoot, {
1329
1391
  display_name: this.getDefaultDisplayName(),
1330
1392
  bio: "Local AI agent connected to SilicaClaw",
1331
1393
  tags: ["openclaw", "local-first"],
@@ -1433,11 +1495,11 @@ export class LocalNodeService {
1433
1495
 
1434
1496
  getOpenClawBridgeStatus(): OpenClawBridgeStatus {
1435
1497
  const integration = this.getIntegrationStatus();
1436
- const openclawInstallation = detectOpenClawInstallation(this.workspaceRoot);
1437
- const openclawRuntime = detectOpenClawRuntime(this.workspaceRoot);
1498
+ const openclawInstallation = detectOpenClawInstallation(this.projectRoot);
1499
+ const openclawRuntime = detectOpenClawRuntime(this.projectRoot);
1438
1500
  const skillInstallation = detectOpenClawSkillInstallation();
1439
1501
  const ownerDelivery = detectOwnerDeliveryStatus({
1440
- workspaceRoot: this.workspaceRoot,
1502
+ workspaceRoot: this.projectRoot,
1441
1503
  connectedToSilicaclaw: integration.connected_to_silicaclaw,
1442
1504
  openclawRunning: openclawRuntime.running,
1443
1505
  skillInstalled: skillInstallation.installed,
@@ -1504,7 +1566,7 @@ export class LocalNodeService {
1504
1566
  const scriptPath = resolve(this.workspaceRoot, "scripts", "install-openclaw-skill.mjs");
1505
1567
  const { stdout } = await execFileAsync(process.execPath, [scriptPath], {
1506
1568
  cwd: this.workspaceRoot,
1507
- env: process.env,
1569
+ env: { ...process.env, SILICACLAW_WORKSPACE_DIR: this.projectRoot },
1508
1570
  maxBuffer: 1024 * 1024,
1509
1571
  });
1510
1572
  const parsed = JSON.parse(String(stdout || "{}"));
@@ -1528,12 +1590,12 @@ export class LocalNodeService {
1528
1590
  const homeDir = resolve(process.env.HOME || "", ".openclaw");
1529
1591
  const workspaceSkillDir = resolve(homeDir, "workspace", "skills");
1530
1592
  const legacySkillDir = resolve(homeDir, "skills");
1531
- const openclawSourceDir = resolve(this.workspaceRoot, "..", "openclaw");
1532
- const openclawRuntime = detectOpenClawRuntime(this.workspaceRoot);
1593
+ const openclawSourceDir = defaultOpenClawSourceDir(this.projectRoot);
1594
+ const openclawRuntime = detectOpenClawRuntime(this.projectRoot);
1533
1595
 
1534
1596
  return {
1535
1597
  bridge_api_base: "http://localhost:4310",
1536
- openclaw_detected: detectOpenClawInstallation(this.workspaceRoot).detected,
1598
+ openclaw_detected: detectOpenClawInstallation(this.projectRoot).detected,
1537
1599
  openclaw_running: openclawRuntime.running,
1538
1600
  openclaw_gateway_host: OPENCLAW_GATEWAY_HOST,
1539
1601
  openclaw_gateway_port: openclawRuntime.configured_gateway_port,
@@ -1939,7 +2001,7 @@ export class LocalNodeService {
1939
2001
  socialConfig: this.socialConfig,
1940
2002
  existingIdentity,
1941
2003
  generatedIdentity: createIdentity(),
1942
- rootDir: this.workspaceRoot,
2004
+ rootDir: this.projectRoot,
1943
2005
  });
1944
2006
  this.identity = resolvedIdentity.identity;
1945
2007
  this.resolvedIdentitySource = resolvedIdentity.source;
@@ -1958,7 +2020,7 @@ export class LocalNodeService {
1958
2020
  socialConfig: this.socialConfig,
1959
2021
  agentId: this.identity.agent_id,
1960
2022
  existingProfile: existingProfile && existingProfile.agent_id === this.identity.agent_id ? existingProfile : null,
1961
- rootDir: this.workspaceRoot,
2023
+ rootDir: this.projectRoot,
1962
2024
  });
1963
2025
  this.profile = signProfile(profileInput, this.identity);
1964
2026
  if (!existingProfile || existingProfile.agent_id !== this.identity.agent_id) {
@@ -1990,7 +2052,7 @@ export class LocalNodeService {
1990
2052
  socialConfig: this.socialConfig,
1991
2053
  agentId: this.identity.agent_id,
1992
2054
  existingProfile: this.profile,
1993
- rootDir: this.workspaceRoot,
2055
+ rootDir: this.projectRoot,
1994
2056
  });
1995
2057
  const nextProfile = signProfile(nextProfileInput, this.identity);
1996
2058
  this.profile = nextProfile;
@@ -2330,6 +2392,19 @@ export class LocalNodeService {
2330
2392
  return (this.network as any).getDiagnostics();
2331
2393
  }
2332
2394
 
2395
+ private getResolvedRealtimeNetworkSummary() {
2396
+ const diagnostics = this.getAdapterDiagnostics();
2397
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
2398
+ return {
2399
+ diagnostics,
2400
+ signaling_url: diagnostics?.signaling_url ?? (relayCapable ? this.webrtcSignalingUrls[0] ?? null : null),
2401
+ signaling_endpoints: diagnostics?.signaling_endpoints ?? (relayCapable ? this.webrtcSignalingUrls : []),
2402
+ room: diagnostics?.room ?? (relayCapable ? this.webrtcRoom : null),
2403
+ bootstrap_sources: diagnostics?.bootstrap_sources ?? (relayCapable ? this.webrtcBootstrapSources : []),
2404
+ seed_peers_count: diagnostics?.seed_peers_count ?? this.webrtcSeedPeers.length,
2405
+ };
2406
+ }
2407
+
2333
2408
  private toPublicProfileSummary(
2334
2409
  profile: PublicProfile,
2335
2410
  options?: { last_seen_at?: number }
@@ -1 +1 @@
1
- 2026.3.19-11
1
+ 2026.3.19-13
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "silicaclaw-broadcast",
3
- "version": "2026.3.19-11",
3
+ "version": "2026.3.19-13",
4
4
  "display_name": "SilicaClaw Broadcast",
5
5
  "description": "OpenClaw skill for reading SilicaClaw public broadcasts, publishing public broadcasts, and forwarding relevant updates to the owner through OpenClaw's native social channel.",
6
6
  "entrypoints": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silicaclaw/cli",
3
- "version": "2026.3.19-11",
3
+ "version": "2026.3.19-13",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -9,6 +9,7 @@ import { fileURLToPath } from "node:url";
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = dirname(__filename);
11
11
  const ROOT_DIR = resolve(__dirname, "..");
12
+ const INVOCATION_CWD = process.cwd();
12
13
 
13
14
  const COLOR = {
14
15
  reset: "\x1b[0m",
@@ -50,7 +51,10 @@ function run(cmd, args, extra = {}) {
50
51
  const result = spawnSync(cmd, args, {
51
52
  cwd: ROOT_DIR,
52
53
  stdio: "inherit",
53
- env: process.env,
54
+ env: {
55
+ ...process.env,
56
+ SILICACLAW_WORKSPACE_DIR: process.env.SILICACLAW_WORKSPACE_DIR || INVOCATION_CWD,
57
+ },
54
58
  ...extra,
55
59
  });
56
60
  if (result.error) {
@@ -68,7 +72,10 @@ function runCapture(cmd, args, extra = {}) {
68
72
  cwd: ROOT_DIR,
69
73
  stdio: ["ignore", "pipe", "pipe"],
70
74
  encoding: "utf8",
71
- env: process.env,
75
+ env: {
76
+ ...process.env,
77
+ SILICACLAW_WORKSPACE_DIR: process.env.SILICACLAW_WORKSPACE_DIR || INVOCATION_CWD,
78
+ },
72
79
  ...extra,
73
80
  });
74
81
  if (result.error) {
@@ -81,7 +88,10 @@ function runInherit(cmd, args, extra = {}) {
81
88
  const result = spawnSync(cmd, args, {
82
89
  cwd: ROOT_DIR,
83
90
  stdio: "inherit",
84
- env: process.env,
91
+ env: {
92
+ ...process.env,
93
+ SILICACLAW_WORKSPACE_DIR: process.env.SILICACLAW_WORKSPACE_DIR || INVOCATION_CWD,
94
+ },
85
95
  ...extra,
86
96
  });
87
97
  if (result.error) {
@@ -114,9 +114,16 @@ function detectAppDir() {
114
114
  return ROOT_DIR;
115
115
  }
116
116
 
117
+ function detectWorkspaceDir() {
118
+ const envDir = process.env.SILICACLAW_WORKSPACE_DIR;
119
+ if (envDir) return resolve(envDir);
120
+ return resolve(process.cwd());
121
+ }
122
+
117
123
  const APP_DIR = detectAppDir();
124
+ const WORKSPACE_DIR = detectWorkspaceDir();
118
125
  const LOCAL_CONSOLE_DIR = join(APP_DIR, "apps", "local-console");
119
- const STATE_DIR = join(APP_DIR, ".silicaclaw", "gateway");
126
+ const STATE_DIR = join(homedir(), ".silicaclaw", "gateway");
120
127
  const CONSOLE_PID_FILE = join(STATE_DIR, "local-console.pid");
121
128
  const CONSOLE_LOG_FILE = join(STATE_DIR, "local-console.log");
122
129
  const SIGNALING_PID_FILE = join(STATE_DIR, "signaling.pid");
@@ -361,6 +368,7 @@ function launchdStatusPayload() {
361
368
  const signalingListener = listeningProcessOnPort(4510);
362
369
  return {
363
370
  app_dir: APP_DIR,
371
+ workspace_dir: WORKSPACE_DIR,
364
372
  mode: state?.mode || "unknown",
365
373
  adapter: state?.adapter || "unknown",
366
374
  service_manager: "launchd",
@@ -395,6 +403,7 @@ function buildStatusPayload() {
395
403
  const signalingListener = listeningProcessOnPort(4510);
396
404
  return {
397
405
  app_dir: APP_DIR,
406
+ workspace_dir: state?.workspace_dir || WORKSPACE_DIR,
398
407
  mode: state?.mode || "unknown",
399
408
  adapter: state?.adapter || "unknown",
400
409
  local_console: {
@@ -685,6 +694,7 @@ async function startAll() {
685
694
  NETWORK_MODE: mode,
686
695
  WEBRTC_SIGNALING_URL: signalingUrl,
687
696
  WEBRTC_ROOM: room,
697
+ SILICACLAW_WORKSPACE_DIR: WORKSPACE_DIR,
688
698
  PATH: process.env.PATH || "/usr/bin:/bin:/usr/sbin:/sbin",
689
699
  HOME: process.env.HOME || homedir(),
690
700
  };
@@ -715,6 +725,7 @@ async function startAll() {
715
725
 
716
726
  writeState({
717
727
  app_dir: APP_DIR,
728
+ workspace_dir: WORKSPACE_DIR,
718
729
  mode,
719
730
  adapter,
720
731
  signaling_url: signalingUrl,
@@ -744,6 +755,7 @@ async function startAll() {
744
755
  NETWORK_MODE: mode,
745
756
  WEBRTC_SIGNALING_URL: signalingUrl,
746
757
  WEBRTC_ROOM: room,
758
+ SILICACLAW_WORKSPACE_DIR: WORKSPACE_DIR,
747
759
  };
748
760
  localPid = spawnBackground(
749
761
  process.execPath,
@@ -771,6 +783,7 @@ async function startAll() {
771
783
 
772
784
  writeState({
773
785
  app_dir: APP_DIR,
786
+ workspace_dir: WORKSPACE_DIR,
774
787
  mode,
775
788
  adapter,
776
789
  signaling_url: signalingUrl,