oomi-ai 0.2.45 → 0.2.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/oomi-ai.js CHANGED
@@ -924,8 +924,98 @@ function collectManagedPersonaRefreshTargets({
924
924
 
925
925
  return targets.sort((a, b) => a.slug.localeCompare(b.slug));
926
926
  }
927
-
928
- async function findExistingManagedPersona(client, slug) {
927
+
928
+ function normalizeBackendPersonaRefreshRecord(rawPersona) {
929
+ if (!rawPersona || typeof rawPersona !== 'object') {
930
+ return null;
931
+ }
932
+
933
+ const slug = String(
934
+ rawPersona.slug ||
935
+ rawPersona.id ||
936
+ rawPersona.personaId ||
937
+ ''
938
+ ).trim();
939
+ if (!slug) {
940
+ return null;
941
+ }
942
+
943
+ return {
944
+ slug,
945
+ name: String(rawPersona.name || slug).trim() || slug,
946
+ description: String(rawPersona.description || rawPersona.summary || rawPersona.name || slug).trim() || slug,
947
+ templateVersion: String(rawPersona.promptTemplateVersion || 'v1').trim() || 'v1',
948
+ templateType: String(rawPersona.templateType || '').trim(),
949
+ };
950
+ }
951
+
952
+ function resolveExistingWorkspacePathForSlug(slug, workspaceRoot = defaultPersonaWorkspaceRoot()) {
953
+ for (const root of listPersonaWorkspaceRoots(workspaceRoot)) {
954
+ const workspacePath = resolvePersonaWorkspacePath({
955
+ workspaceRoot: root,
956
+ slug,
957
+ });
958
+ if (fs.existsSync(workspacePath)) {
959
+ return workspacePath;
960
+ }
961
+ }
962
+ return '';
963
+ }
964
+
965
+ async function discoverBackendLinkedPersonaRefreshTargets({
966
+ client,
967
+ workspaceRoot = defaultPersonaWorkspaceRoot(),
968
+ existingTargets = [],
969
+ logger = null,
970
+ } = {}) {
971
+ if (!client || typeof client.listPersonas !== 'function') {
972
+ return [];
973
+ }
974
+
975
+ const targetsBySlug = new Map(
976
+ Array.isArray(existingTargets)
977
+ ? existingTargets.map((target) => [String(target?.slug || '').trim(), target]).filter(([slug]) => slug)
978
+ : [],
979
+ );
980
+
981
+ const payload = await client.listPersonas();
982
+ const backendPersonas = Array.isArray(payload?.personas) ? payload.personas : [];
983
+ const discoveredTargets = [];
984
+
985
+ for (const rawPersona of backendPersonas) {
986
+ const backendPersona = normalizeBackendPersonaRefreshRecord(rawPersona);
987
+ if (!backendPersona || targetsBySlug.has(backendPersona.slug)) {
988
+ continue;
989
+ }
990
+ const workspacePath = resolveExistingWorkspacePathForSlug(backendPersona.slug, workspaceRoot);
991
+ if (!workspacePath) {
992
+ continue;
993
+ }
994
+ const state = readPersonaRuntimeState(workspacePath);
995
+ const target = {
996
+ slug: backendPersona.slug,
997
+ workspacePath,
998
+ state: {
999
+ ...state,
1000
+ slug: backendPersona.slug,
1001
+ name: backendPersona.name,
1002
+ description: backendPersona.description,
1003
+ templateVersion: backendPersona.templateVersion,
1004
+ },
1005
+ processRunning: false,
1006
+ };
1007
+ discoveredTargets.push(target);
1008
+ targetsBySlug.set(backendPersona.slug, target);
1009
+ }
1010
+
1011
+ if (discoveredTargets.length > 0) {
1012
+ logger?.(`Added ${discoveredTargets.length} backend-linked persona runtime target${discoveredTargets.length === 1 ? '' : 's'} from workspace discovery.`);
1013
+ }
1014
+
1015
+ return discoveredTargets;
1016
+ }
1017
+
1018
+ async function findExistingManagedPersona(client, slug) {
929
1019
  try {
930
1020
  return await client.getPersona({ slug });
931
1021
  } catch (error) {
@@ -1566,13 +1656,16 @@ async function handlePersonaDeleteCommand(slug, flags = {}) {
1566
1656
  printStructuredResult(result, isTruthyFlag(flags.json));
1567
1657
  }
1568
1658
 
1569
- async function restartManagedPersonaRefreshTargets(flags = {}) {
1659
+ async function restartManagedPersonaRefreshTargets(flags = {}, options = {}) {
1570
1660
  const workspaceRoot = resolvePersonaWorkspaceRoot(flags);
1571
- const targets = collectManagedPersonaRefreshTargets({
1661
+ const localTargets = collectManagedPersonaRefreshTargets({
1572
1662
  workspaceRoot,
1573
1663
  includeStopped: isTruthyFlag(flags['include-stopped']),
1574
1664
  });
1665
+ const targetsBySlug = new Map(localTargets.map((target) => [target.slug, target]));
1666
+ const targets = [...localTargets];
1575
1667
  const results = [];
1668
+ const logger = options.logger || null;
1576
1669
 
1577
1670
  let client = null;
1578
1671
  let registrationError = '';
@@ -1580,10 +1673,35 @@ async function restartManagedPersonaRefreshTargets(flags = {}) {
1580
1673
  client = createCliPersonaApiClient(flags);
1581
1674
  } catch (error) {
1582
1675
  registrationError = error instanceof Error ? error.message : String(error);
1676
+ logger?.(`Persona backend registration unavailable: ${registrationError}`);
1583
1677
  }
1584
1678
 
1679
+ if (client) {
1680
+ try {
1681
+ const backendTargets = await discoverBackendLinkedPersonaRefreshTargets({
1682
+ client,
1683
+ workspaceRoot,
1684
+ existingTargets: targets,
1685
+ logger,
1686
+ });
1687
+ for (const target of backendTargets) {
1688
+ targetsBySlug.set(target.slug, target);
1689
+ targets.push(target);
1690
+ }
1691
+ } catch (error) {
1692
+ logger?.(`Backend persona discovery failed: ${error instanceof Error ? error.message : String(error)}`);
1693
+ }
1694
+ }
1695
+
1696
+ logger?.(
1697
+ `Discovered ${targets.length} managed persona runtime${targets.length == 1 ? '' : 's'} to refresh.`,
1698
+ );
1699
+
1585
1700
  for (const target of targets) {
1586
1701
  const state = target.state && typeof target.state === 'object' ? target.state : {};
1702
+ logger?.(
1703
+ `Refreshing persona ${target.slug} (previous port: ${String(state.localPort || 'unknown')}).`,
1704
+ );
1587
1705
  const launchResult = await launchManagedPersonaRuntime({
1588
1706
  slug: target.slug,
1589
1707
  name: String(state.name || target.slug).trim() || target.slug,
@@ -1600,6 +1718,7 @@ async function restartManagedPersonaRefreshTargets(flags = {}) {
1600
1718
  let registration = null;
1601
1719
  if (client) {
1602
1720
  try {
1721
+ logger?.(`Re-registering runtime for ${launchResult.slug} at ${launchResult.runtime.endpoint}.`);
1603
1722
  registration = await client.registerRuntime({
1604
1723
  slug: launchResult.slug,
1605
1724
  endpoint: launchResult.runtime.endpoint,
@@ -1613,9 +1732,14 @@ async function restartManagedPersonaRefreshTargets(flags = {}) {
1613
1732
  ok: false,
1614
1733
  error: error instanceof Error ? error.message : String(error),
1615
1734
  };
1735
+ logger?.(`Runtime registration failed for ${launchResult.slug}: ${registration.error}`);
1616
1736
  }
1617
1737
  }
1618
1738
 
1739
+ logger?.(
1740
+ `Persona ${launchResult.slug} refreshed on port ${launchResult.runtime.localPort} (${launchResult.runtime.endpoint}).`,
1741
+ );
1742
+
1619
1743
  results.push({
1620
1744
  slug: launchResult.slug,
1621
1745
  workspacePath: launchResult.workspacePath,
@@ -1634,10 +1758,12 @@ async function restartManagedPersonaRefreshTargets(flags = {}) {
1634
1758
  };
1635
1759
  }
1636
1760
 
1637
- async function refreshBridgeForUpdate(flags = {}) {
1761
+ async function refreshBridgeForUpdate(flags = {}, options = {}) {
1762
+ const logger = options.logger || null;
1638
1763
  if (process.platform === 'darwin') {
1639
1764
  const launchdStatus = readBridgeLaunchdStatus();
1640
1765
  if (launchdStatus.installed) {
1766
+ logger?.(`Restarting launchd-managed bridge ${launchdStatus.target}.`);
1641
1767
  await stopBridgeLaunchdService();
1642
1768
  startBridgeLaunchdService();
1643
1769
  incrementBridgeMetric('bridge_restart_count');
@@ -1651,12 +1777,14 @@ async function refreshBridgeForUpdate(flags = {}) {
1651
1777
 
1652
1778
  const running = findRunningBridgeProcess();
1653
1779
  if (!running) {
1780
+ logger?.('No bridge process is currently running; skipping bridge restart.');
1654
1781
  return {
1655
1782
  restarted: false,
1656
1783
  mode: 'process',
1657
1784
  };
1658
1785
  }
1659
1786
 
1787
+ logger?.(`Restarting bridge process ${running.pid}.`);
1660
1788
  const stopResult = await stopBridgeProcesses();
1661
1789
  if (Array.isArray(stopResult.stillAlive) && stopResult.stillAlive.length > 0) {
1662
1790
  throw new Error(`Failed to stop bridge processes: ${stopResult.stillAlive.join(', ')}`);
@@ -1673,19 +1801,31 @@ async function refreshBridgeForUpdate(flags = {}) {
1673
1801
  }
1674
1802
 
1675
1803
  async function handleOpenclawRefreshCommand(flags = {}) {
1804
+ const jsonOutput = isTruthyFlag(flags.json);
1805
+ const logProgress = jsonOutput ? null : (message) => console.log(`[refresh] ${message}`);
1676
1806
  const currentVersion = currentPackageVersion();
1677
1807
  let latestVersion = '';
1678
1808
  if (!isTruthyFlag(flags['skip-version-check'])) {
1809
+ logProgress?.(`Checking npm for the latest oomi-ai version (installed: ${currentVersion || 'unknown'}).`);
1679
1810
  latestVersion = await fetchLatestPublishedVersion('oomi-ai');
1680
1811
  if (latestVersion && compareVersions(currentVersion, latestVersion) < 0) {
1681
1812
  throw new Error(
1682
1813
  `Installed oomi-ai ${currentVersion} is behind npm ${latestVersion}. Update first, then rerun: oomi openclaw refresh`
1683
1814
  );
1684
1815
  }
1816
+ if (latestVersion) {
1817
+ logProgress?.(`Latest published version is ${latestVersion}.`);
1818
+ }
1685
1819
  }
1686
1820
 
1687
- const personaRefresh = await restartManagedPersonaRefreshTargets(flags);
1688
- const bridgeRefresh = await refreshBridgeForUpdate(flags);
1821
+ logProgress?.('Refreshing managed persona runtimes.');
1822
+ const personaRefresh = await restartManagedPersonaRefreshTargets(flags, {
1823
+ logger: logProgress,
1824
+ });
1825
+ logProgress?.('Refreshing bridge process.');
1826
+ const bridgeRefresh = await refreshBridgeForUpdate(flags, {
1827
+ logger: logProgress,
1828
+ });
1689
1829
  const payload = {
1690
1830
  ok: true,
1691
1831
  currentVersion,
@@ -1699,7 +1839,7 @@ async function handleOpenclawRefreshCommand(flags = {}) {
1699
1839
  bridge: bridgeRefresh,
1700
1840
  };
1701
1841
 
1702
- if (isTruthyFlag(flags.json)) {
1842
+ if (jsonOutput) {
1703
1843
  console.log(JSON.stringify(payload, null, 2));
1704
1844
  return;
1705
1845
  }
@@ -5827,5 +5967,8 @@ export {
5827
5967
  isBridgeWorkerCommand,
5828
5968
  parsePositiveInteger,
5829
5969
  collectManagedPersonaRefreshTargets,
5970
+ discoverBackendLinkedPersonaRefreshTargets,
5971
+ normalizeBackendPersonaRefreshRecord,
5830
5972
  resolvePersonaRuntimeInput,
5973
+ resolveExistingWorkspacePathForSlug,
5831
5974
  };
@@ -100,10 +100,19 @@ export function createPersonaApiClient({
100
100
  };
101
101
  }
102
102
 
103
- return {
104
- getPersona({
105
- slug,
106
- }) {
103
+ return {
104
+ listPersonas() {
105
+ return getJson({
106
+ fetchImpl,
107
+ backendUrl: resolvedBackendUrl,
108
+ deviceToken: resolvedDeviceToken,
109
+ path: '/v1/personas',
110
+ });
111
+ },
112
+
113
+ getPersona({
114
+ slug,
115
+ }) {
107
116
  const safeSlug = trimString(slug);
108
117
  if (!safeSlug) {
109
118
  throw new Error('Persona slug is required.');
@@ -2,7 +2,7 @@
2
2
  "id": "oomi-ai",
3
3
  "name": "Oomi Channel Plugin",
4
4
  "description": "Managed Oomi channel integration for OpenClaw.",
5
- "version": "0.2.45",
5
+ "version": "0.2.47",
6
6
  "author": "Oomi",
7
7
  "license": "MIT",
8
8
  "openclawVersion": ">=0.5.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oomi-ai",
3
- "version": "0.2.45",
3
+ "version": "0.2.47",
4
4
  "description": "Oomi OpenClaw channel plugin and bridge tooling",
5
5
  "bin": {
6
6
  "oomi": "bin/oomi-ai.js"