@openclawbrain/cli 0.4.30 → 0.4.32

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/src/cli.js CHANGED
@@ -1738,6 +1738,19 @@ function readInstallRuntimeFingerprint(openclawHome) {
1738
1738
  function runOpenClawBrainConvergePluginStep(openclawHome) {
1739
1739
  const before = readInstallRuntimeFingerprint(openclawHome);
1740
1740
  const plan = planOpenClawBrainConvergePluginAction(before);
1741
+ if (plan.action === "noop") {
1742
+ return {
1743
+ plan,
1744
+ command: null,
1745
+ changed: false,
1746
+ changeReasons: [],
1747
+ detail: "Skipped the OpenClaw plugin manager because the authoritative split-package plugin is already present and a no-op refresh would only churn volatile install metadata.",
1748
+ warning: null,
1749
+ capture: null,
1750
+ before,
1751
+ after: before
1752
+ };
1753
+ }
1741
1754
  let uninstallCapture = null;
1742
1755
  if (plan.action === "install" && shouldReplaceOpenClawBrainInstallBeforeConverge(before)) {
1743
1756
  uninstallCapture = runCapturedExternalCommand("openclaw", ["plugins", "uninstall", plan.pluginId]);
@@ -1820,6 +1820,7 @@ interface OperatorHookSummary {
1820
1820
  manifestId: string | null;
1821
1821
  installId: string | null;
1822
1822
  packageName: string | null;
1823
+ packageVersion: string | null;
1823
1824
  installLayout: import("./openclaw-plugin-install.js").OpenClawBrainInstallLayout | null;
1824
1825
  additionalInstallCount: number;
1825
1826
  installState: CurrentProfileHookInstallStateV1;
package/dist/src/index.js CHANGED
@@ -7832,6 +7832,7 @@ function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId)
7832
7832
  manifestId: report.hook.manifestId,
7833
7833
  installId: report.hook.installId,
7834
7834
  packageName: report.hook.packageName,
7835
+ packageVersion: report.hook.packageVersion,
7835
7836
  installLayout: report.hook.installLayout,
7836
7837
  additionalInstallCount: report.hook.additionalInstallCount,
7837
7838
  installState: report.hook.installState,
@@ -103,10 +103,10 @@ export function planOpenClawBrainConvergePluginAction(fingerprint) {
103
103
  };
104
104
  }
105
105
  return {
106
- action: "update",
106
+ action: "noop",
107
107
  packageSpec: "@openclawbrain/openclaw",
108
108
  pluginId: "openclawbrain",
109
- reason: "refresh the existing split-package plugin install so install/upgrade/repair stays on one converge path",
109
+ reason: "the authoritative split-package plugin is already installed, so converge should preserve the current plugin-manager record instead of rewriting volatile install metadata",
110
110
  };
111
111
  }
112
112
 
@@ -257,7 +257,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
257
257
  manifestId: incompleteInstall?.manifestId ?? null,
258
258
  installId: incompleteInstall?.installId ?? null,
259
259
  packageName: incompleteInstall?.packageName ?? null,
260
- packageVersion: readInstalledHookPackageVersion(incompleteInstall?.packageJsonPath ?? null),
260
+ packageVersion: incompleteInstall?.packageVersion ?? readInstalledHookPackageVersion(incompleteInstall?.packageJsonPath ?? null) ?? incompleteInstall?.manifestVersion ?? null,
261
261
  installLayout: incompleteInstall?.installLayout ?? null,
262
262
  additionalInstallCount: installedPlugin.additionalInstalls.length,
263
263
  installState: "not_installed",
@@ -274,7 +274,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
274
274
  const allowlist = inspectOpenClawBrainPluginAllowlist(resolvedHome);
275
275
  const layoutLabel = describeOpenClawBrainInstallLayout(selectedInstall.installLayout);
276
276
  const identityDetail = describeOpenClawBrainInstallIdentity(selectedInstall);
277
- const packageVersion = readInstalledHookPackageVersion(selectedInstall.packageJsonPath);
277
+ const packageVersion = selectedInstall.packageVersion ?? readInstalledHookPackageVersion(selectedInstall.packageJsonPath) ?? selectedInstall.manifestVersion ?? null;
278
278
  const activationRootState = inspectInstalledHookActivationRoot(selectedInstall.loaderEntryPath);
279
279
  if (allowlist.state === "blocked") {
280
280
  return {
@@ -164,6 +164,10 @@ function inspectOpenClawBrainPluginInstall(extensionDir, pluginId) {
164
164
  const packageName = typeof packageJson.name === "string" && packageJson.name.trim().length > 0
165
165
  ? packageJson.name.trim()
166
166
  : null;
167
+ const packageVersion = typeof packageJson.version === "string" && packageJson.version.trim().length > 0
168
+ ? packageJson.version.trim()
169
+ : null;
170
+ const manifestVersion = normalizeOptionalString(manifest?.version);
167
171
  const installId = normalizeInstallId(packageName) ?? normalizeInstallId(path.basename(extensionDir));
168
172
  const installLayout = inferInstallLayout({
169
173
  extensionDir,
@@ -182,8 +186,10 @@ function inspectOpenClawBrainPluginInstall(extensionDir, pluginId) {
182
186
  runtimeGuardPath: loaderEntryPath === null ? null : resolveRuntimeGuardPath(loaderEntryPath),
183
187
  configuredEntries,
184
188
  manifestId,
189
+ manifestVersion,
185
190
  installId,
186
191
  packageName,
192
+ packageVersion,
187
193
  installLayout
188
194
  };
189
195
  }
@@ -272,13 +272,15 @@ function loadJsonFile(pathname) {
272
272
  function resolveActivePackPaths(activationRoot) {
273
273
  const pointers = toRecord(loadJsonFile(path.join(path.resolve(activationRoot), "activation-pointers.json")));
274
274
  const active = toRecord(pointers?.active);
275
+ const packId = normalizeOptionalString(active?.packId);
275
276
  const packRootDir = normalizeOptionalString(active?.packRootDir)
276
- ?? (normalizeOptionalString(active?.packId) === null
277
+ ?? (packId === null
277
278
  ? null
278
- : path.join(path.resolve(activationRoot), "packs", String(active.packId)));
279
+ : path.join(path.resolve(activationRoot), "packs", String(packId)));
279
280
  const manifestPath = normalizeOptionalString(active?.manifestPath)
280
281
  ?? (packRootDir === null ? null : path.join(packRootDir, "manifest.json"));
281
282
  return {
283
+ packId,
282
284
  packRootDir,
283
285
  manifestPath
284
286
  };
@@ -376,6 +378,38 @@ function buildWatchSnapshotAttributionCoverage(activationRoot) {
376
378
  detail: `watch sparse-feedback queue: completed_without_evaluation=0, ready=${normalizeCount(readyCount)}, delayed=${normalizeCount(delayedCount)}, budget_deferred=${normalizeCount(budgetDeferredCount)}`
377
379
  };
378
380
  }
381
+ function readWatchTeacherSnapshotPackTruth(activationRoot) {
382
+ const snapshot = toRecord(loadJsonFile(path.join(path.resolve(activationRoot), "watch", "teacher-snapshot.json")));
383
+ const learning = toRecord(snapshot?.learning);
384
+ const nestedSnapshot = toRecord(snapshot?.snapshot);
385
+ const nestedLearning = toRecord(nestedSnapshot?.learning);
386
+ return {
387
+ lastHandledMaterializationPackId: normalizeOptionalString(snapshot?.lastHandledMaterializationPackId)
388
+ ?? normalizeOptionalString(learning?.lastHandledMaterializationPackId)
389
+ ?? normalizeOptionalString(nestedLearning?.lastHandledMaterializationPackId),
390
+ lastMaterializationPackId: normalizeOptionalString(snapshot?.lastMaterializationPackId)
391
+ ?? normalizeOptionalString(learning?.lastMaterializationPackId)
392
+ ?? normalizeOptionalString(nestedLearning?.lastMaterializationPackId)
393
+ };
394
+ }
395
+ function buildActivationPackTruth(activationRoot) {
396
+ const active = resolveActivePackPaths(activationRoot);
397
+ const activePackId = active.packId;
398
+ if (activePackId === null) {
399
+ return null;
400
+ }
401
+ const watchTruth = readWatchTeacherSnapshotPackTruth(activationRoot);
402
+ const handledPackId = watchTruth.lastHandledMaterializationPackId ?? watchTruth.lastMaterializationPackId;
403
+ if (handledPackId === null) {
404
+ return null;
405
+ }
406
+ return {
407
+ activePackId,
408
+ handledPackId,
409
+ materializedPackId: handledPackId,
410
+ promoted: handledPackId === activePackId
411
+ };
412
+ }
379
413
  function shouldPreferActivationFeedbackSummary(current, fallback) {
380
414
  if (fallback === null) {
381
415
  return false;
@@ -407,18 +441,35 @@ function shouldPreferWatchAttributionCoverage(current, fallback) {
407
441
  function enrichBridgeWithActivationTruth(activationRoot, bridge) {
408
442
  const feedbackSummary = buildActivePackFeedbackSummary(activationRoot);
409
443
  const attributionCoverage = buildWatchSnapshotAttributionCoverage(activationRoot);
410
- if (!shouldPreferActivationFeedbackSummary(bridge.feedbackSummary, feedbackSummary)
411
- && !shouldPreferWatchAttributionCoverage(bridge.attributionCoverage, attributionCoverage)) {
444
+ const packTruth = buildActivationPackTruth(activationRoot);
445
+ const preferFeedbackSummary = shouldPreferActivationFeedbackSummary(bridge.feedbackSummary, feedbackSummary);
446
+ const preferAttributionCoverage = shouldPreferWatchAttributionCoverage(bridge.attributionCoverage, attributionCoverage);
447
+ const preferPackTruth = packTruth !== null
448
+ && (bridge.materializedPackId === null || (bridge.promoted !== true && packTruth.promoted === true))
449
+ && (packTruth.promoted === true || bridge.materializedPackId === null);
450
+ if (!preferFeedbackSummary && !preferAttributionCoverage && !preferPackTruth) {
412
451
  return bridge;
413
452
  }
414
453
  return normalizeBridgePayload({
415
454
  ...bridge,
416
- feedbackSummary: shouldPreferActivationFeedbackSummary(bridge.feedbackSummary, feedbackSummary)
455
+ materializedPackId: preferPackTruth ? packTruth.materializedPackId : bridge.materializedPackId,
456
+ promoted: preferPackTruth ? packTruth.promoted : bridge.promoted,
457
+ feedbackSummary: preferFeedbackSummary
417
458
  ? feedbackSummary
418
459
  : bridge.feedbackSummary,
419
- attributionCoverage: shouldPreferWatchAttributionCoverage(bridge.attributionCoverage, attributionCoverage)
460
+ attributionCoverage: preferAttributionCoverage
420
461
  ? attributionCoverage
421
- : bridge.attributionCoverage
462
+ : bridge.attributionCoverage,
463
+ source: preferPackTruth
464
+ ? {
465
+ ...(bridge.source ?? {}),
466
+ activationPackTruth: {
467
+ activePackId: packTruth.activePackId,
468
+ handledPackId: packTruth.handledPackId,
469
+ source: "active_pack_plus_watch_snapshot"
470
+ }
471
+ }
472
+ : bridge.source
422
473
  });
423
474
  }
424
475
  function normalizeLastInterruptionSummary(value) {
@@ -865,6 +916,21 @@ export function persistBrainStoreTracedLearningBridge(payload, options = {}) {
865
916
  try {
866
917
  db = new sqlite.DatabaseSync(dbPath);
867
918
  const summary = normalizePersistedStatusSurface(payload);
919
+ const existingSummaryLoaded = loadTrainingStateJson(db, TRACED_LEARNING_STATUS_SURFACE_STATE_KEY);
920
+ if (existingSummaryLoaded.value !== null) {
921
+ const existingSummary = normalizePersistedStatusSurface(existingSummaryLoaded.value);
922
+ if (JSON.stringify(existingSummary) === JSON.stringify(summary)) {
923
+ return {
924
+ path: dbPath,
925
+ bridge: buildPersistedStatusSurfaceBridge(existingSummary, {
926
+ brainRoot,
927
+ dbPath
928
+ }),
929
+ persisted: false,
930
+ error: null
931
+ };
932
+ }
933
+ }
868
934
  writeTrainingStateJson(db, TRACED_LEARNING_STATUS_SURFACE_STATE_KEY, summary);
869
935
  return {
870
936
  path: dbPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclawbrain/cli",
3
- "version": "0.4.30",
3
+ "version": "0.4.32",
4
4
  "description": "OpenClawBrain operator CLI package with install/status helpers, daemon controls, and import/export tooling.",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",