@openclawbrain/cli 0.4.29 → 0.4.30
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 +132 -12
- package/dist/src/install-converge.js +74 -3
- package/dist/src/openclaw-hook-truth.js +138 -62
- package/dist/src/proof-command.js +52 -3
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -562,7 +562,7 @@ function operatorCliHelp() {
|
|
|
562
562
|
" openclawbrain-ops scan --session <trace.json> --root <path> [options] # compatibility alias",
|
|
563
563
|
"",
|
|
564
564
|
"Options:",
|
|
565
|
-
" --openclaw-home <path> OpenClaw home dir for install/attach/detach/uninstall (e.g. ~/.openclaw-Tern or ~/.openclaw). Also pins status/rollback/context/history/learn to that installed target when applicable.",
|
|
565
|
+
" --openclaw-home <path> OpenClaw home dir for install/attach/detach/uninstall (e.g. ./openclaw-cormorantai, ~/.openclaw-Tern, or ~/.openclaw). Also pins status/rollback/context/history/learn to that installed target when applicable.",
|
|
566
566
|
" --shared Set brain-attachment-policy to shared instead of dedicated (install/attach only).",
|
|
567
567
|
` --skip-embedder-provision Skip the default Ollama ${DEFAULT_OLLAMA_EMBEDDING_MODEL} pull before install/attach bootstrap. Use only when intentionally deferring embedder setup. Also supports ${OPENCLAWBRAIN_INSTALL_SKIP_EMBEDDER_PROVISION_ENV}=1.`,
|
|
568
568
|
" --activation-root <path> Explicit activation root for attach/watch/daemon and other stateful commands; install/attach default to sibling .openclawbrain/activation next to the selected OpenClaw home.",
|
|
@@ -602,6 +602,11 @@ function operatorCliHelp() {
|
|
|
602
602
|
" 9. detach openclawbrain detach --openclaw-home <path> — remove the profile hookup only and keep brain data",
|
|
603
603
|
" 10. uninstall openclawbrain uninstall --openclaw-home <path> --keep-data|--purge-data — remove the hookup and choose the data outcome explicitly",
|
|
604
604
|
"",
|
|
605
|
+
"Examples:",
|
|
606
|
+
" openclawbrain install --openclaw-home ./openclaw-cormorantai",
|
|
607
|
+
" openclawbrain status --openclaw-home ./openclaw-cormorantai --detailed",
|
|
608
|
+
" openclawbrain proof --openclaw-home ./openclaw-cormorantai",
|
|
609
|
+
"",
|
|
605
610
|
"Advanced/operator surfaces:",
|
|
606
611
|
" context preview the brain context that would be injected for a message",
|
|
607
612
|
" rollback preview or apply active <- previous, active -> candidate pointer movement",
|
|
@@ -955,16 +960,69 @@ function summarizeStatusAttachmentTruth(input) {
|
|
|
955
960
|
})
|
|
956
961
|
};
|
|
957
962
|
}
|
|
963
|
+
let cachedCliPackageMetadata = null;
|
|
964
|
+
function resolveCliPackageManifestPath() {
|
|
965
|
+
const candidates = [
|
|
966
|
+
path.resolve(__dirname, "..", "..", "package.json"),
|
|
967
|
+
path.resolve(__dirname, "..", "package.json"),
|
|
968
|
+
];
|
|
969
|
+
for (const candidate of candidates) {
|
|
970
|
+
if (existsSync(candidate)) {
|
|
971
|
+
return candidate;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
throw new Error("OpenClawBrain CLI package manifest not found. Searched:\n" +
|
|
975
|
+
candidates.map((candidate) => ` - ${candidate}`).join("\n"));
|
|
976
|
+
}
|
|
977
|
+
function readCliPackageMetadata() {
|
|
978
|
+
if (cachedCliPackageMetadata !== null) {
|
|
979
|
+
return cachedCliPackageMetadata;
|
|
980
|
+
}
|
|
981
|
+
const manifest = JSON.parse(readFileSync(resolveCliPackageManifestPath(), "utf8"));
|
|
982
|
+
const name = typeof manifest.name === "string" && manifest.name.trim().length > 0
|
|
983
|
+
? manifest.name.trim()
|
|
984
|
+
: "@openclawbrain/cli";
|
|
985
|
+
const version = typeof manifest.version === "string" && manifest.version.trim().length > 0
|
|
986
|
+
? manifest.version.trim()
|
|
987
|
+
: "0.0.0";
|
|
988
|
+
cachedCliPackageMetadata = { name, version };
|
|
989
|
+
return cachedCliPackageMetadata;
|
|
990
|
+
}
|
|
991
|
+
function inspectDaemonRuntimeSurface(activationRoot) {
|
|
992
|
+
const managedInspection = inspectManagedLearnerService(activationRoot);
|
|
993
|
+
if (managedInspection.installed === true ||
|
|
994
|
+
managedInspection.configuredRuntimePath !== null ||
|
|
995
|
+
managedInspection.configuredRuntimePackageSpec !== null ||
|
|
996
|
+
managedInspection.configuredRuntimePackageName !== null ||
|
|
997
|
+
managedInspection.configuredRuntimePackageVersion !== null) {
|
|
998
|
+
return {
|
|
999
|
+
...managedInspection,
|
|
1000
|
+
surfaceIdentitySource: "managed_service"
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
const cliPackageMetadata = readCliPackageMetadata();
|
|
1004
|
+
return {
|
|
1005
|
+
...managedInspection,
|
|
1006
|
+
configuredRuntimePath: canonicalizeExistingCliPath(__filename),
|
|
1007
|
+
configuredRuntimePackageName: cliPackageMetadata.name,
|
|
1008
|
+
configuredRuntimePackageVersion: cliPackageMetadata.version,
|
|
1009
|
+
configuredRuntimePackageSpec: null,
|
|
1010
|
+
surfaceIdentitySource: "current_cli"
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
958
1013
|
function summarizeStatusHotfixBoundary(status) {
|
|
959
1014
|
return describeOpenClawBrainHotfixBoundary({
|
|
960
1015
|
hookInspection: status.hook,
|
|
961
|
-
daemonInspection:
|
|
1016
|
+
daemonInspection: inspectDaemonRuntimeSurface(status.host.activationRoot)
|
|
962
1017
|
});
|
|
963
1018
|
}
|
|
964
1019
|
function formatStatusHotfixBoundarySummary(boundary) {
|
|
965
1020
|
return [
|
|
966
1021
|
`boundary=${boundary.boundary}`,
|
|
967
1022
|
`skew=${boundary.skew}`,
|
|
1023
|
+
`converge=${boundary.convergeState ?? "unverified"}`,
|
|
1024
|
+
`daemonSource=${boundary.daemonSource ?? "unverified"}`,
|
|
1025
|
+
`selectedHome=${boundary.selectedOpenClawHome === null ? "unverified" : shortenPath(boundary.selectedOpenClawHome)}`,
|
|
968
1026
|
`daemon=${boundary.daemonPackage ?? "unverified"}`,
|
|
969
1027
|
`hook=${boundary.hookPackage ?? "unverified"}`
|
|
970
1028
|
].join(" ");
|
|
@@ -1649,6 +1707,8 @@ function readInstallRuntimeFingerprint(openclawHome) {
|
|
|
1649
1707
|
openclawHome,
|
|
1650
1708
|
quiet: true
|
|
1651
1709
|
});
|
|
1710
|
+
const activationRoot = resolvedActivationRoot.trim().length === 0 ? null : path.resolve(resolvedActivationRoot);
|
|
1711
|
+
const daemonSurface = activationRoot === null ? null : inspectDaemonRuntimeSurface(activationRoot);
|
|
1652
1712
|
const { config } = readOpenClawJsonConfig(openclawHome);
|
|
1653
1713
|
return {
|
|
1654
1714
|
selectedInstall: selectedInstall === null
|
|
@@ -1664,10 +1724,15 @@ function readInstallRuntimeFingerprint(openclawHome) {
|
|
|
1664
1724
|
hookPath: hook.hookPath,
|
|
1665
1725
|
hookState: hook.installState,
|
|
1666
1726
|
loadability: hook.loadability,
|
|
1667
|
-
activationRoot
|
|
1727
|
+
activationRoot,
|
|
1668
1728
|
loaderSource: readTextFileIfExists(selectedInstall?.loaderEntryPath ?? null),
|
|
1669
1729
|
runtimeGuardSource: readTextFileIfExists(selectedInstall?.runtimeGuardPath ?? null),
|
|
1670
|
-
pluginsConfig: JSON.stringify(config.plugins ?? null)
|
|
1730
|
+
pluginsConfig: JSON.stringify(config.plugins ?? null),
|
|
1731
|
+
daemonRuntimePath: daemonSurface?.configuredRuntimePath ?? null,
|
|
1732
|
+
daemonRuntimePackageName: daemonSurface?.configuredRuntimePackageName ?? null,
|
|
1733
|
+
daemonRuntimePackageVersion: daemonSurface?.configuredRuntimePackageVersion ?? null,
|
|
1734
|
+
daemonRuntimePackageSpec: daemonSurface?.configuredRuntimePackageSpec ?? null,
|
|
1735
|
+
daemonRuntimeSource: daemonSurface?.surfaceIdentitySource ?? null
|
|
1671
1736
|
};
|
|
1672
1737
|
}
|
|
1673
1738
|
function runOpenClawBrainConvergePluginStep(openclawHome) {
|
|
@@ -1738,7 +1803,22 @@ function inspectInstallConvergeVerification(parsed) {
|
|
|
1738
1803
|
status: normalizedStatusAndReport.status
|
|
1739
1804
|
});
|
|
1740
1805
|
const displayedStatus = summarizeDisplayedStatus(normalizedStatusAndReport.status, installHook);
|
|
1806
|
+
const hotfixBoundary = summarizeStatusHotfixBoundary(normalizedStatusAndReport.status);
|
|
1807
|
+
const surfaceSummary = hotfixBoundary.convergeState === "half_converged"
|
|
1808
|
+
? `daemon runtime and installed hook/runtime-guard are half-converged: ${hotfixBoundary.detail}`
|
|
1809
|
+
: hotfixBoundary.convergeState === "warning"
|
|
1810
|
+
? `daemon runtime and installed hook/runtime-guard identity is not fully proven: ${hotfixBoundary.detail}`
|
|
1811
|
+
: hotfixBoundary.convergeState === "unverified"
|
|
1812
|
+
? `daemon runtime and installed hook/runtime-guard convergence is unverified: ${hotfixBoundary.detail}`
|
|
1813
|
+
: hotfixBoundary.detail;
|
|
1741
1814
|
const routeFn = summarizeStatusRouteFn(normalizedStatusAndReport.status, normalizedStatusAndReport.report);
|
|
1815
|
+
const defaultNextStep = buildStatusNextStep(normalizedStatusAndReport.status, normalizedStatusAndReport.report, {
|
|
1816
|
+
openclawHome: parsed.openclawHome,
|
|
1817
|
+
installHook
|
|
1818
|
+
});
|
|
1819
|
+
const nextStep = hotfixBoundary.convergeState === "half_converged"
|
|
1820
|
+
? `Daemon runtime and installed hook/runtime-guard are half-converged for ${shortenPath(parsed.openclawHome)} (${hotfixBoundary.skew}); refresh the daemon-side CLI/runtime surface, then rerun ${buildInstallCommand(parsed.openclawHome)}.`
|
|
1821
|
+
: defaultNextStep;
|
|
1742
1822
|
return {
|
|
1743
1823
|
targetInspection,
|
|
1744
1824
|
status: normalizedStatusAndReport.status,
|
|
@@ -1747,11 +1827,9 @@ function inspectInstallConvergeVerification(parsed) {
|
|
|
1747
1827
|
attachmentTruth,
|
|
1748
1828
|
displayedStatus,
|
|
1749
1829
|
routeFn,
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
}),
|
|
1754
|
-
summaryLine: `STATUS ${displayedStatus}; hook=${installHook.state}/${installHook.loadability}; guard=${normalizedStatusAndReport.status.hook.guardSeverity}/${normalizedStatusAndReport.status.hook.guardActionability}; runtime=${attachmentTruth.runtimeLoad}; loadProof=${normalizedStatusAndReport.status.hook.loadProof}; serve=${normalizedStatusAndReport.status.brainStatus.serveState}`,
|
|
1830
|
+
hotfixBoundary,
|
|
1831
|
+
nextStep,
|
|
1832
|
+
summaryLine: `STATUS ${displayedStatus}; hook=${installHook.state}/${installHook.loadability}; surface=${hotfixBoundary.convergeState}/${hotfixBoundary.skew}; guard=${normalizedStatusAndReport.status.hook.guardSeverity}/${normalizedStatusAndReport.status.hook.guardActionability}; runtime=${attachmentTruth.runtimeLoad}; loadProof=${normalizedStatusAndReport.status.hook.loadProof}; serve=${normalizedStatusAndReport.status.brainStatus.serveState}`,
|
|
1755
1833
|
facts: {
|
|
1756
1834
|
installLayout: normalizedStatusAndReport.status.hook.installLayout ?? installHook.installLayout ?? null,
|
|
1757
1835
|
installState: installHook.state,
|
|
@@ -1763,7 +1841,17 @@ function inspectInstallConvergeVerification(parsed) {
|
|
|
1763
1841
|
loadProof: normalizedStatusAndReport.status.hook.loadProof,
|
|
1764
1842
|
serveState: normalizedStatusAndReport.status.brainStatus.serveState,
|
|
1765
1843
|
routeFnAvailable: routeFn.available,
|
|
1766
|
-
awaitingFirstExport: normalizedStatusAndReport.status.brainStatus.awaitingFirstExport
|
|
1844
|
+
awaitingFirstExport: normalizedStatusAndReport.status.brainStatus.awaitingFirstExport,
|
|
1845
|
+
surfaceBoundary: hotfixBoundary.boundary,
|
|
1846
|
+
surfaceSkew: hotfixBoundary.skew,
|
|
1847
|
+
surfaceConvergeState: hotfixBoundary.convergeState,
|
|
1848
|
+
surfaceSummary,
|
|
1849
|
+
daemonPackage: hotfixBoundary.daemonPackage,
|
|
1850
|
+
hookPackage: hotfixBoundary.hookPackage,
|
|
1851
|
+
daemonPath: hotfixBoundary.daemonPath,
|
|
1852
|
+
hookPath: hotfixBoundary.hookPath,
|
|
1853
|
+
runtimeGuardPath: hotfixBoundary.runtimeGuardPath,
|
|
1854
|
+
selectedOpenClawHome: hotfixBoundary.selectedOpenClawHome
|
|
1767
1855
|
}
|
|
1768
1856
|
};
|
|
1769
1857
|
}
|
|
@@ -4065,6 +4153,8 @@ function emitInstallConvergeResult(result, parsed) {
|
|
|
4065
4153
|
console.log(`Attach: ${result.attach.detail}`);
|
|
4066
4154
|
console.log(`Restart: ${result.restart.detail}`);
|
|
4067
4155
|
console.log(`Verify: ${result.verification.summaryLine}`);
|
|
4156
|
+
console.log(`Surface: ${result.verification.surface.summaryLine}`);
|
|
4157
|
+
console.log(`Paths: ${result.verification.surface.pathsLine}`);
|
|
4068
4158
|
console.log(`Verdict: ${result.verdict.verdict}`);
|
|
4069
4159
|
console.log(`Why: ${result.verdict.why}`);
|
|
4070
4160
|
if (result.verdict.warnings.length > 0) {
|
|
@@ -4126,7 +4216,22 @@ function runInstallCommand(parsed) {
|
|
|
4126
4216
|
loadProof: "unknown",
|
|
4127
4217
|
serveState: "unknown",
|
|
4128
4218
|
routeFnAvailable: false,
|
|
4129
|
-
awaitingFirstExport: false
|
|
4219
|
+
awaitingFirstExport: false,
|
|
4220
|
+
surface: {
|
|
4221
|
+
summaryLine: "daemon/runtime hook surface identity was not verified because install failed earlier",
|
|
4222
|
+
pathsLine: "daemonPath=none hookPath=unverified runtimeGuard=unverified",
|
|
4223
|
+
boundary: "unknown",
|
|
4224
|
+
skew: "unknown",
|
|
4225
|
+
convergeState: "unknown",
|
|
4226
|
+
daemonSource: "unknown",
|
|
4227
|
+
daemonPackage: null,
|
|
4228
|
+
hookPackage: null,
|
|
4229
|
+
detail: "install failed before daemon/runtime hook surface identity could be verified",
|
|
4230
|
+
daemonPath: null,
|
|
4231
|
+
hookPath: null,
|
|
4232
|
+
runtimeGuardPath: null,
|
|
4233
|
+
selectedOpenClawHome: parsed.openclawHome
|
|
4234
|
+
}
|
|
4130
4235
|
},
|
|
4131
4236
|
verdict
|
|
4132
4237
|
};
|
|
@@ -4211,7 +4316,22 @@ function runInstallCommand(parsed) {
|
|
|
4211
4316
|
loadProof: verificationSnapshot.facts.loadProof,
|
|
4212
4317
|
serveState: verificationSnapshot.facts.serveState,
|
|
4213
4318
|
routeFnAvailable: verificationSnapshot.facts.routeFnAvailable,
|
|
4214
|
-
awaitingFirstExport: verificationSnapshot.facts.awaitingFirstExport
|
|
4319
|
+
awaitingFirstExport: verificationSnapshot.facts.awaitingFirstExport,
|
|
4320
|
+
surface: {
|
|
4321
|
+
summaryLine: `boundary=${verificationSnapshot.hotfixBoundary.boundary}; skew=${verificationSnapshot.hotfixBoundary.skew}; converge=${verificationSnapshot.hotfixBoundary.convergeState}; daemonSource=${verificationSnapshot.hotfixBoundary.daemonSource}; selectedHome=${verificationSnapshot.hotfixBoundary.selectedOpenClawHome === null ? "unverified" : shortenPath(verificationSnapshot.hotfixBoundary.selectedOpenClawHome)}; daemon=${verificationSnapshot.hotfixBoundary.daemonPackage ?? "unverified"}; hook=${verificationSnapshot.hotfixBoundary.hookPackage ?? "unverified"}; detail=${verificationSnapshot.hotfixBoundary.detail}`,
|
|
4322
|
+
pathsLine: `daemonPath=${verificationSnapshot.hotfixBoundary.daemonPath === null ? "none" : shortenPath(verificationSnapshot.hotfixBoundary.daemonPath)} hookPath=${verificationSnapshot.hotfixBoundary.hookPath === null ? "unverified" : shortenPath(verificationSnapshot.hotfixBoundary.hookPath)} runtimeGuard=${verificationSnapshot.hotfixBoundary.runtimeGuardPath === null ? "unverified" : shortenPath(verificationSnapshot.hotfixBoundary.runtimeGuardPath)}`,
|
|
4323
|
+
boundary: verificationSnapshot.hotfixBoundary.boundary,
|
|
4324
|
+
skew: verificationSnapshot.hotfixBoundary.skew,
|
|
4325
|
+
convergeState: verificationSnapshot.hotfixBoundary.convergeState,
|
|
4326
|
+
daemonSource: verificationSnapshot.hotfixBoundary.daemonSource,
|
|
4327
|
+
daemonPackage: verificationSnapshot.hotfixBoundary.daemonPackage,
|
|
4328
|
+
hookPackage: verificationSnapshot.hotfixBoundary.hookPackage,
|
|
4329
|
+
detail: verificationSnapshot.hotfixBoundary.detail,
|
|
4330
|
+
daemonPath: verificationSnapshot.hotfixBoundary.daemonPath,
|
|
4331
|
+
hookPath: verificationSnapshot.hotfixBoundary.hookPath,
|
|
4332
|
+
runtimeGuardPath: verificationSnapshot.hotfixBoundary.runtimeGuardPath,
|
|
4333
|
+
selectedOpenClawHome: verificationSnapshot.hotfixBoundary.selectedOpenClawHome
|
|
4334
|
+
}
|
|
4215
4335
|
},
|
|
4216
4336
|
verdict,
|
|
4217
4337
|
underlyingInstall: attachResult
|
|
@@ -10,8 +10,22 @@ const CHANGE_REASON_LABELS = {
|
|
|
10
10
|
loader_source: "loader source changed",
|
|
11
11
|
runtime_guard_source: "runtime-guard source changed",
|
|
12
12
|
plugins_config: "OpenClaw plugins config changed",
|
|
13
|
+
daemon_runtime_path: "daemon runtime path changed",
|
|
14
|
+
daemon_runtime_identity: "daemon runtime identity changed",
|
|
13
15
|
};
|
|
14
16
|
|
|
17
|
+
const GATEWAY_RESTART_CHANGE_REASONS = new Set([
|
|
18
|
+
"install_identity",
|
|
19
|
+
"install_layout",
|
|
20
|
+
"hook_path",
|
|
21
|
+
"hook_state",
|
|
22
|
+
"loadability",
|
|
23
|
+
"activation_root",
|
|
24
|
+
"loader_source",
|
|
25
|
+
"runtime_guard_source",
|
|
26
|
+
"plugins_config",
|
|
27
|
+
]);
|
|
28
|
+
|
|
15
29
|
function sameValue(left, right) {
|
|
16
30
|
return left === right;
|
|
17
31
|
}
|
|
@@ -28,6 +42,32 @@ function installIdentityOf(fingerprint) {
|
|
|
28
42
|
});
|
|
29
43
|
}
|
|
30
44
|
|
|
45
|
+
function daemonRuntimeIdentityOf(fingerprint) {
|
|
46
|
+
return JSON.stringify({
|
|
47
|
+
runtimePackageName: fingerprint?.daemonRuntimePackageName ?? null,
|
|
48
|
+
runtimePackageVersion: fingerprint?.daemonRuntimePackageVersion ?? null,
|
|
49
|
+
runtimePackageSpec: fingerprint?.daemonRuntimePackageSpec ?? null,
|
|
50
|
+
runtimeSource: fingerprint?.daemonRuntimeSource ?? null,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function describeSurfaceHalfConvergedReason(input) {
|
|
55
|
+
const boundary = input.surfaceBoundary ?? null;
|
|
56
|
+
const skew = input.surfaceSkew ?? null;
|
|
57
|
+
const selectedOpenClawHome = input.selectedOpenClawHome ?? null;
|
|
58
|
+
const daemonPackage = input.daemonPackage ?? null;
|
|
59
|
+
const hookPackage = input.hookPackage ?? null;
|
|
60
|
+
const boundarySuffix = boundary === null
|
|
61
|
+
? ""
|
|
62
|
+
: skew === null || skew === "unverified"
|
|
63
|
+
? ` (${boundary})`
|
|
64
|
+
: ` (${boundary}/${skew})`;
|
|
65
|
+
const packageSuffix = daemonPackage === null && hookPackage === null
|
|
66
|
+
? ""
|
|
67
|
+
: `; daemon=${daemonPackage ?? "unverified"} hook=${hookPackage ?? "unverified"}`;
|
|
68
|
+
return `daemon runtime and installed hook/runtime-guard are half-converged${selectedOpenClawHome === null ? "" : ` for ${selectedOpenClawHome}`}${boundarySuffix}${packageSuffix}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
31
71
|
export function shouldReplaceOpenClawBrainInstallBeforeConverge(fingerprint) {
|
|
32
72
|
const selectedInstall = fingerprint?.selectedInstall ?? null;
|
|
33
73
|
if (selectedInstall === null) {
|
|
@@ -99,6 +139,12 @@ export function diffOpenClawBrainConvergeRuntimeFingerprint(before, after) {
|
|
|
99
139
|
if (!sameValue(before?.pluginsConfig ?? null, after?.pluginsConfig ?? null)) {
|
|
100
140
|
reasons.push("plugins_config");
|
|
101
141
|
}
|
|
142
|
+
if (!sameValue(before?.daemonRuntimePath ?? null, after?.daemonRuntimePath ?? null)) {
|
|
143
|
+
reasons.push("daemon_runtime_path");
|
|
144
|
+
}
|
|
145
|
+
if (!sameValue(daemonRuntimeIdentityOf(before), daemonRuntimeIdentityOf(after))) {
|
|
146
|
+
reasons.push("daemon_runtime_identity");
|
|
147
|
+
}
|
|
102
148
|
return {
|
|
103
149
|
changed: reasons.length > 0,
|
|
104
150
|
reasons,
|
|
@@ -114,12 +160,15 @@ export function describeOpenClawBrainConvergeChangeReasons(reasons) {
|
|
|
114
160
|
|
|
115
161
|
export function buildOpenClawBrainConvergeRestartPlan(input) {
|
|
116
162
|
const changeReasons = input.changeReasons ?? [];
|
|
117
|
-
|
|
163
|
+
const gatewayRestartReasons = changeReasons.filter((reason) => GATEWAY_RESTART_CHANGE_REASONS.has(reason));
|
|
164
|
+
if (gatewayRestartReasons.length === 0) {
|
|
118
165
|
return {
|
|
119
166
|
required: false,
|
|
120
167
|
automatic: false,
|
|
121
|
-
reason: "no_runtime_affecting_changes",
|
|
122
|
-
detail:
|
|
168
|
+
reason: changeReasons.length === 0 ? "no_runtime_affecting_changes" : "daemon_only_runtime_changes",
|
|
169
|
+
detail: changeReasons.length === 0
|
|
170
|
+
? "Skipped gateway restart because converge did not change plugin files, hook wiring, or the pinned activation root."
|
|
171
|
+
: "Skipped gateway restart because converge only changed the daemon runtime surface; the selected OpenClaw hook/runtime-guard wiring did not change.",
|
|
123
172
|
};
|
|
124
173
|
}
|
|
125
174
|
if (input.profileName === null) {
|
|
@@ -149,6 +198,13 @@ export function classifyOpenClawBrainConvergeVerification(input) {
|
|
|
149
198
|
const loadProof = input.loadProof ?? "unverified";
|
|
150
199
|
const serveState = input.serveState ?? "unknown";
|
|
151
200
|
const installedPackageName = input.installedPackageName ?? null;
|
|
201
|
+
const surfaceConvergeState = input.surfaceConvergeState ?? null;
|
|
202
|
+
const surfaceBoundary = input.surfaceBoundary ?? null;
|
|
203
|
+
const surfaceSkew = input.surfaceSkew ?? null;
|
|
204
|
+
const selectedOpenClawHome = input.selectedOpenClawHome ?? null;
|
|
205
|
+
const daemonPackage = input.daemonPackage ?? null;
|
|
206
|
+
const hookPackage = input.hookPackage ?? null;
|
|
207
|
+
const surfaceSummary = input.surfaceSummary ?? null;
|
|
152
208
|
if (installedPackageName === LEGACY_COMPAT_PACKAGE_NAME) {
|
|
153
209
|
blockingReasons.push(`installed plugin still references the retired compatibility package ${LEGACY_COMPAT_PACKAGE_NAME}; converge must replace it with @openclawbrain/openclaw`);
|
|
154
210
|
}
|
|
@@ -164,6 +220,15 @@ export function classifyOpenClawBrainConvergeVerification(input) {
|
|
|
164
220
|
if (displayedStatus === "fail") {
|
|
165
221
|
blockingReasons.push("status still reports fail");
|
|
166
222
|
}
|
|
223
|
+
if (surfaceConvergeState === "half_converged") {
|
|
224
|
+
blockingReasons.push(surfaceSummary ?? describeSurfaceHalfConvergedReason({
|
|
225
|
+
surfaceBoundary,
|
|
226
|
+
surfaceSkew,
|
|
227
|
+
selectedOpenClawHome,
|
|
228
|
+
daemonPackage,
|
|
229
|
+
hookPackage,
|
|
230
|
+
}));
|
|
231
|
+
}
|
|
167
232
|
const runtimeTruthAlreadyProven = runtimeLoad === "proven"
|
|
168
233
|
&& loadProof === "status_probe_ready"
|
|
169
234
|
&& installState === "installed"
|
|
@@ -182,6 +247,12 @@ export function classifyOpenClawBrainConvergeVerification(input) {
|
|
|
182
247
|
if (input.restartRequired === true && input.restartPerformed !== true && runtimeTruthAlreadyProven) {
|
|
183
248
|
warnings.push("automatic restart was not performed because install could not infer an exact OpenClaw profile token, but current status already proves runtime load");
|
|
184
249
|
}
|
|
250
|
+
if (surfaceConvergeState === "warning") {
|
|
251
|
+
warnings.push(surfaceSummary ?? "daemon runtime vs installed hook/runtime-guard identity is not fully proven from this verification snapshot");
|
|
252
|
+
}
|
|
253
|
+
if (surfaceConvergeState === "unverified") {
|
|
254
|
+
warnings.push(surfaceSummary ?? "daemon runtime vs installed hook/runtime-guard convergence is not fully proven from this verification snapshot");
|
|
255
|
+
}
|
|
185
256
|
// When runtime proof is green for the repaired profile, promote the proof
|
|
186
257
|
// surface to healthy rather than leaving stale degraded warnings that
|
|
187
258
|
// contradict the proven truth.
|
|
@@ -66,6 +66,58 @@ function normalizeSurfacePath(filePath) {
|
|
|
66
66
|
? path.resolve(filePath)
|
|
67
67
|
: null;
|
|
68
68
|
}
|
|
69
|
+
function classifyRuntimeSurfaceConvergeState(input) {
|
|
70
|
+
const reasons = [];
|
|
71
|
+
if (input.scope === "activation_root_only") {
|
|
72
|
+
reasons.push("selected_openclaw_home_unverified");
|
|
73
|
+
return {
|
|
74
|
+
state: "unverified",
|
|
75
|
+
reasons
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (input.daemonPath === null) {
|
|
79
|
+
reasons.push("daemon_surface_unverified");
|
|
80
|
+
}
|
|
81
|
+
if (input.hookPath === null && input.runtimeGuardPath === null) {
|
|
82
|
+
reasons.push("installed_surface_unverified");
|
|
83
|
+
return {
|
|
84
|
+
state: input.daemonPath === null ? "unverified" : "half_converged",
|
|
85
|
+
reasons
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (input.hookLoadability !== "loadable") {
|
|
89
|
+
reasons.push("installed_surface_not_loadable");
|
|
90
|
+
return {
|
|
91
|
+
state: input.daemonPath === null ? "unverified" : "half_converged",
|
|
92
|
+
reasons
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (input.daemonPath === null) {
|
|
96
|
+
return {
|
|
97
|
+
state: "unverified",
|
|
98
|
+
reasons
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (input.samePath) {
|
|
102
|
+
reasons.push("same_path");
|
|
103
|
+
return {
|
|
104
|
+
state: "converged",
|
|
105
|
+
reasons
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (input.daemonVersion !== null && input.hookVersion !== null) {
|
|
109
|
+
reasons.push(input.daemonVersion === input.hookVersion ? "split_path_same_version" : "version_skew");
|
|
110
|
+
return {
|
|
111
|
+
state: input.daemonVersion === input.hookVersion ? "converged" : "half_converged",
|
|
112
|
+
reasons
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
reasons.push("version_unverified");
|
|
116
|
+
return {
|
|
117
|
+
state: "unverified",
|
|
118
|
+
reasons
|
|
119
|
+
};
|
|
120
|
+
}
|
|
69
121
|
function inspectInstalledHookActivationRoot(loaderEntryPath) {
|
|
70
122
|
let content;
|
|
71
123
|
try {
|
|
@@ -328,77 +380,101 @@ export function describeOpenClawBrainHotfixBoundary(input) {
|
|
|
328
380
|
const daemonPath = normalizeSurfacePath(daemonInspection?.configuredRuntimePath ?? null);
|
|
329
381
|
const hookPath = normalizeSurfacePath(hookInspection.hookPath);
|
|
330
382
|
const runtimeGuardPath = normalizeSurfacePath(hookInspection.runtimeGuardPath);
|
|
383
|
+
const selectedOpenClawHome = typeof hookInspection.openclawHome === "string" && hookInspection.openclawHome.trim().length > 0
|
|
384
|
+
? path.resolve(hookInspection.openclawHome)
|
|
385
|
+
: null;
|
|
386
|
+
const daemonSource = daemonInspection?.surfaceIdentitySource ?? (daemonPath === null ? "unverified" : "managed_service");
|
|
387
|
+
const daemonPackageName = daemonInspection?.configuredRuntimePackageName ?? null;
|
|
388
|
+
const daemonPackageVersion = daemonInspection?.configuredRuntimePackageVersion ?? null;
|
|
389
|
+
const hookPackageName = hookInspection.packageName ?? null;
|
|
390
|
+
const hookPackageVersion = hookInspection.packageVersion ?? null;
|
|
331
391
|
const daemonPackage = formatPackageIdentity(daemonInspection?.configuredRuntimePackageName ?? null, daemonInspection?.configuredRuntimePackageVersion ?? null, daemonInspection?.configuredRuntimePackageSpec ?? null);
|
|
332
392
|
const hookPackage = formatPackageIdentity(hookInspection.packageName, hookInspection.packageVersion);
|
|
393
|
+
const samePath = daemonPath === hookPath || daemonPath === runtimeGuardPath;
|
|
394
|
+
const daemonVersion = daemonPackageVersion;
|
|
395
|
+
const hookVersion = hookPackageVersion;
|
|
396
|
+
let boundary;
|
|
397
|
+
let skew;
|
|
398
|
+
let displayedHookPath = hookPath;
|
|
399
|
+
let displayedRuntimeGuardPath = runtimeGuardPath;
|
|
400
|
+
let displayedDaemonPackage = daemonPackage;
|
|
401
|
+
let displayedHookPackage = hookPackage;
|
|
402
|
+
let guidance;
|
|
403
|
+
let detail;
|
|
333
404
|
if (hookInspection.scope === "activation_root_only") {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
detail: daemonPath === null
|
|
344
|
-
? "activation-root-only status does not expose the installed hook/runtime-guard surface."
|
|
345
|
-
: `daemon runtime path ${shortenPath(daemonPath)} is visible, but activation-root-only status still does not expose the installed hook/runtime-guard surface.`
|
|
346
|
-
};
|
|
405
|
+
boundary = "hook_surface_unverified";
|
|
406
|
+
skew = "unverified";
|
|
407
|
+
displayedHookPath = null;
|
|
408
|
+
displayedRuntimeGuardPath = null;
|
|
409
|
+
displayedHookPackage = null;
|
|
410
|
+
guidance = "Pin --openclaw-home before patching the installed hook/runtime-guard surface; activation-root-only status does not prove which OpenClaw install you would be changing.";
|
|
411
|
+
detail = daemonPath === null
|
|
412
|
+
? "activation-root-only status does not expose the installed hook/runtime-guard surface."
|
|
413
|
+
: `daemon runtime path ${shortenPath(daemonPath)} is visible, but activation-root-only status still does not expose the installed hook/runtime-guard surface.`;
|
|
347
414
|
}
|
|
348
|
-
if (hookPath === null && runtimeGuardPath === null) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
: "Patch the daemon runtime path for background watch fixes, but repair or reinstall the installed hook/runtime-guard surface before patching OpenClaw load behavior.",
|
|
360
|
-
detail: daemonPath === null
|
|
361
|
-
? "no verified daemon runtime path or installed hook/runtime-guard path is visible from this status snapshot."
|
|
362
|
-
: `daemon runtime path ${shortenPath(daemonPath)} is visible, but the installed hook/runtime-guard surface is not yet loadable.`
|
|
363
|
-
};
|
|
415
|
+
else if (hookPath === null && runtimeGuardPath === null) {
|
|
416
|
+
boundary = "hook_surface_unverified";
|
|
417
|
+
skew = "unverified";
|
|
418
|
+
displayedHookPath = null;
|
|
419
|
+
displayedRuntimeGuardPath = null;
|
|
420
|
+
guidance = daemonPath === null
|
|
421
|
+
? "Repair or reinstall the installed hook surface before patching OpenClaw load behavior."
|
|
422
|
+
: "Patch the daemon runtime path for background watch fixes, but repair or reinstall the installed hook/runtime-guard surface before patching OpenClaw load behavior.";
|
|
423
|
+
detail = daemonPath === null
|
|
424
|
+
? "no verified daemon runtime path or installed hook/runtime-guard path is visible from this status snapshot."
|
|
425
|
+
: `daemon runtime path ${shortenPath(daemonPath)} is visible, but the installed hook/runtime-guard surface is not yet loadable.`;
|
|
364
426
|
}
|
|
365
|
-
if (daemonPath === null) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
runtimeGuardPath,
|
|
372
|
-
daemonPackage: null,
|
|
373
|
-
hookPackage,
|
|
374
|
-
guidance: "Patch the installed hook/runtime-guard surface for OpenClaw load fixes. No configured daemon runtime path is visible from status.",
|
|
375
|
-
detail: `installed hook loads from ${hookPath === null ? "unverified" : shortenPath(hookPath)}${runtimeGuardPath === null ? "" : ` with runtime-guard ${shortenPath(runtimeGuardPath)}`}, but no configured daemon runtime path is visible.`
|
|
376
|
-
};
|
|
427
|
+
else if (daemonPath === null) {
|
|
428
|
+
boundary = "daemon_surface_only";
|
|
429
|
+
skew = "unverified";
|
|
430
|
+
displayedDaemonPackage = null;
|
|
431
|
+
guidance = "Patch the installed hook/runtime-guard surface for OpenClaw load fixes. No configured daemon runtime path is visible from status.";
|
|
432
|
+
detail = `installed hook loads from ${hookPath === null ? "unverified" : shortenPath(hookPath)}${runtimeGuardPath === null ? "" : ` with runtime-guard ${shortenPath(runtimeGuardPath)}`}, but no configured daemon runtime path is visible.`;
|
|
377
433
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
434
|
+
else {
|
|
435
|
+
skew = samePath
|
|
436
|
+
? "same_path"
|
|
437
|
+
: daemonVersion !== null && hookVersion !== null
|
|
438
|
+
? daemonVersion === hookVersion
|
|
439
|
+
? "split_path_same_version"
|
|
440
|
+
: "split_path_version_skew"
|
|
441
|
+
: "split_path_version_unverified";
|
|
442
|
+
boundary = samePath ? "same_surface" : "split_surfaces";
|
|
443
|
+
guidance = samePath
|
|
444
|
+
? "Daemon and installed hook paths currently collapse to the same file; verify both surfaces before patching anyway."
|
|
445
|
+
: "Patch the daemon runtime path for background watch/learner fixes. Patch the installed hook/runtime-guard paths for OpenClaw load fixes.";
|
|
446
|
+
detail = samePath
|
|
447
|
+
? `daemon runtime path ${shortenPath(daemonPath)} currently resolves to the same file as the installed OpenClaw hook surface.`
|
|
448
|
+
: `daemon background watch runs from ${shortenPath(daemonPath)}${daemonPackage === null ? "" : ` (${daemonPackage})`}; OpenClaw loads the installed hook from ${hookPath === null ? "unverified" : shortenPath(hookPath)}${hookPackage === null ? "" : ` (${hookPackage})`}${runtimeGuardPath === null ? "" : ` and runtime-guard ${shortenPath(runtimeGuardPath)}`}.`;
|
|
449
|
+
}
|
|
450
|
+
const converge = classifyRuntimeSurfaceConvergeState({
|
|
451
|
+
scope: hookInspection.scope,
|
|
452
|
+
daemonPath,
|
|
453
|
+
hookPath: displayedHookPath,
|
|
454
|
+
runtimeGuardPath: displayedRuntimeGuardPath,
|
|
455
|
+
hookLoadability: hookInspection.loadability,
|
|
456
|
+
daemonVersion,
|
|
457
|
+
hookVersion,
|
|
458
|
+
samePath
|
|
459
|
+
});
|
|
388
460
|
return {
|
|
389
|
-
boundary
|
|
461
|
+
boundary,
|
|
390
462
|
skew,
|
|
391
463
|
daemonPath,
|
|
392
|
-
hookPath,
|
|
393
|
-
runtimeGuardPath,
|
|
394
|
-
daemonPackage,
|
|
395
|
-
hookPackage,
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
464
|
+
hookPath: displayedHookPath,
|
|
465
|
+
runtimeGuardPath: displayedRuntimeGuardPath,
|
|
466
|
+
daemonPackage: displayedDaemonPackage,
|
|
467
|
+
hookPackage: displayedHookPackage,
|
|
468
|
+
daemonPackageName,
|
|
469
|
+
daemonPackageVersion,
|
|
470
|
+
hookPackageName,
|
|
471
|
+
hookPackageVersion,
|
|
472
|
+
daemonSource,
|
|
473
|
+
selectedOpenClawHome,
|
|
474
|
+
convergeState: converge.state,
|
|
475
|
+
convergeReasons: converge.reasons,
|
|
476
|
+
guidance,
|
|
477
|
+
detail
|
|
402
478
|
};
|
|
403
479
|
}
|
|
404
480
|
//# sourceMappingURL=openclaw-hook-truth.js.map
|
|
@@ -279,6 +279,7 @@ function extractStartupBreadcrumbs(logText, bundleStartedAtIso) {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
function extractStatusSignals(statusText) {
|
|
282
|
+
const surface = extractKeyValuePairs(extractDetailedStatusLine(statusText, "surface"));
|
|
282
283
|
return {
|
|
283
284
|
statusOk: /^STATUS ok$/m.test(statusText),
|
|
284
285
|
loadProofReady: /loadProof=status_probe_ready/.test(statusText),
|
|
@@ -288,6 +289,11 @@ function extractStatusSignals(statusText) {
|
|
|
288
289
|
routeFnAvailable: /routeFn\s+available=yes/.test(statusText),
|
|
289
290
|
proofPath: statusText.match(/proofPath=([^\s]+)/)?.[1] ?? null,
|
|
290
291
|
proofError: statusText.match(/proofError=([^\s]+)/)?.[1] ?? null,
|
|
292
|
+
surfaceBoundary: surface.boundary ?? null,
|
|
293
|
+
surfaceSkew: surface.skew ?? null,
|
|
294
|
+
surfaceConvergeState: surface.converge ?? null,
|
|
295
|
+
surfaceDaemonSource: surface.daemonSource ?? null,
|
|
296
|
+
surfaceSelectedHome: surface.selectedHome ?? null,
|
|
291
297
|
};
|
|
292
298
|
}
|
|
293
299
|
function extractDetailedStatusLine(statusText, prefix) {
|
|
@@ -378,10 +384,11 @@ function buildCoverageSnapshot({ attachedSetLine, runtimeLoadProofSnapshot, open
|
|
|
378
384
|
profiles
|
|
379
385
|
};
|
|
380
386
|
}
|
|
381
|
-
function buildHardeningSnapshot({ attachTruthLine, serveLine, routeFnLine, verdict, statusSignals }) {
|
|
387
|
+
function buildHardeningSnapshot({ attachTruthLine, serveLine, routeFnLine, surfaceLine, verdict, statusSignals }) {
|
|
382
388
|
const attachTruth = extractKeyValuePairs(attachTruthLine);
|
|
383
389
|
const serve = extractKeyValuePairs(serveLine);
|
|
384
390
|
const routeFn = extractKeyValuePairs(routeFnLine);
|
|
391
|
+
const surface = extractKeyValuePairs(surfaceLine);
|
|
385
392
|
return {
|
|
386
393
|
contract: "openclaw_operator_hardening_snapshot.v1",
|
|
387
394
|
generatedAt: new Date().toISOString(),
|
|
@@ -391,6 +398,7 @@ function buildHardeningSnapshot({ attachTruthLine, serveLine, routeFnLine, verdi
|
|
|
391
398
|
runtimeProven: statusSignals.runtimeProven,
|
|
392
399
|
serveActivePack: statusSignals.serveActivePack,
|
|
393
400
|
routeFnAvailable: statusSignals.routeFnAvailable,
|
|
401
|
+
surfaceConverged: statusSignals.surfaceConvergeState === "converged",
|
|
394
402
|
},
|
|
395
403
|
attachTruth: {
|
|
396
404
|
current: attachTruth.current ?? null,
|
|
@@ -399,6 +407,15 @@ function buildHardeningSnapshot({ attachTruthLine, serveLine, routeFnLine, verdi
|
|
|
399
407
|
runtime: attachTruth.runtime ?? null,
|
|
400
408
|
watcher: attachTruth.watcher ?? null,
|
|
401
409
|
},
|
|
410
|
+
surface: {
|
|
411
|
+
boundary: surface.boundary ?? null,
|
|
412
|
+
skew: surface.skew ?? null,
|
|
413
|
+
converge: surface.converge ?? null,
|
|
414
|
+
daemonSource: surface.daemonSource ?? null,
|
|
415
|
+
selectedHome: surface.selectedHome ?? null,
|
|
416
|
+
daemon: surface.daemon ?? null,
|
|
417
|
+
hook: surface.hook ?? null,
|
|
418
|
+
},
|
|
402
419
|
serve: {
|
|
403
420
|
state: serve.state ?? null,
|
|
404
421
|
failOpen: serve.failOpen ?? null,
|
|
@@ -450,6 +467,8 @@ function buildVerdict({ steps, gatewayStatus, pluginInspect, statusSignals, brea
|
|
|
450
467
|
&& statusSignals.runtimeProven
|
|
451
468
|
&& statusSignals.serveActivePack
|
|
452
469
|
&& statusSignals.routeFnAvailable;
|
|
470
|
+
const surfaceConverged = statusSignals.surfaceConvergeState === "converged";
|
|
471
|
+
const surfaceHalfConverged = statusSignals.surfaceConvergeState === "half_converged";
|
|
453
472
|
if (!statusSignals.loadProofReady)
|
|
454
473
|
runtimeTruthGaps.push("load_proof");
|
|
455
474
|
if (!statusSignals.runtimeProven)
|
|
@@ -458,6 +477,9 @@ function buildVerdict({ steps, gatewayStatus, pluginInspect, statusSignals, brea
|
|
|
458
477
|
runtimeTruthGaps.push("serve_active_pack");
|
|
459
478
|
if (!statusSignals.routeFnAvailable)
|
|
460
479
|
runtimeTruthGaps.push("route_fn");
|
|
480
|
+
if (surfaceHalfConverged) {
|
|
481
|
+
runtimeTruthGaps.push("surface_converged");
|
|
482
|
+
}
|
|
461
483
|
const warningCodes = [];
|
|
462
484
|
const warnings = [];
|
|
463
485
|
if (!statusSignals.statusOk) {
|
|
@@ -495,6 +517,14 @@ function buildVerdict({ steps, gatewayStatus, pluginInspect, statusSignals, brea
|
|
|
495
517
|
? "runtime-load-proof snapshot did not include the current openclaw home"
|
|
496
518
|
: "runtime-load-proof snapshot was missing");
|
|
497
519
|
}
|
|
520
|
+
if (surfaceHalfConverged) {
|
|
521
|
+
warningCodes.push(`surface_half_converged:${statusSignals.surfaceSkew ?? "unknown"}`);
|
|
522
|
+
warnings.push(`detailed status reported daemon-vs-installed-surface half-converged (${statusSignals.surfaceSkew ?? "unknown"})`);
|
|
523
|
+
}
|
|
524
|
+
else if (!surfaceConverged) {
|
|
525
|
+
warningCodes.push(`surface_unverified:${statusSignals.surfaceConvergeState ?? "unknown"}`);
|
|
526
|
+
warnings.push("detailed status did not fully prove daemon-vs-installed-surface convergence");
|
|
527
|
+
}
|
|
498
528
|
if (statusSignals.proofError !== null && statusSignals.proofError !== "none") {
|
|
499
529
|
warningCodes.push(`proof_error:${statusSignals.proofError}`);
|
|
500
530
|
warnings.push(`detailed status reported proofError=${statusSignals.proofError}`);
|
|
@@ -546,7 +576,7 @@ function buildVerdict({ steps, gatewayStatus, pluginInspect, statusSignals, brea
|
|
|
546
576
|
};
|
|
547
577
|
}
|
|
548
578
|
|
|
549
|
-
function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspectText, statusSignals, breadcrumbs, runtimeLoadProofSnapshot, surfaceLine, surfacesLine, hotfixLine, guardLine, feedbackLine, attributionLine, attributionCoverageLine, learningPathLine, learningFlowLine, learningHealthLine, coverageSnapshot, hardeningSnapshot }) {
|
|
579
|
+
function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspectText, statusSignals, breadcrumbs, runtimeLoadProofSnapshot, surfaceLine, surfacesLine, surfaceNoteLine, hotfixLine, guardLine, feedbackLine, attributionLine, attributionCoverageLine, learningPathLine, learningFlowLine, learningHealthLine, coverageSnapshot, hardeningSnapshot }) {
|
|
550
580
|
const passed = [];
|
|
551
581
|
const missing = [];
|
|
552
582
|
const warnings = Array.isArray(verdict.warnings) ? verdict.warnings : [];
|
|
@@ -574,11 +604,20 @@ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspec
|
|
|
574
604
|
if (statusSignals.routeFnAvailable) {
|
|
575
605
|
passed.push("detailed status reported routeFn available=yes");
|
|
576
606
|
}
|
|
607
|
+
if (statusSignals.surfaceConvergeState === "converged") {
|
|
608
|
+
passed.push("detailed status reported daemon-vs-installed-surface convergence");
|
|
609
|
+
}
|
|
577
610
|
if (breadcrumbs.afterBundleStart.some((entry) => entry.kind === "loaded")) {
|
|
578
611
|
passed.push("startup log contained a post-bundle [openclawbrain] BRAIN LOADED breadcrumb");
|
|
579
612
|
}
|
|
580
613
|
if (!statusSignals.loadProofReady)
|
|
581
614
|
missing.push("detailed status did not prove hook load");
|
|
615
|
+
if (statusSignals.surfaceConvergeState === "half_converged") {
|
|
616
|
+
missing.push(`detailed status reported daemon-vs-installed-surface half-converged (${statusSignals.surfaceSkew ?? "unknown"})`);
|
|
617
|
+
}
|
|
618
|
+
else if (statusSignals.surfaceConvergeState !== "converged") {
|
|
619
|
+
missing.push("detailed status did not fully prove daemon-vs-installed-surface convergence");
|
|
620
|
+
}
|
|
582
621
|
if (!breadcrumbs.afterBundleStart.some((entry) => entry.kind === "loaded"))
|
|
583
622
|
missing.push("no post-bundle startup breadcrumb was found");
|
|
584
623
|
if (runtimeLoadProofSnapshot.path === null)
|
|
@@ -609,6 +648,9 @@ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspec
|
|
|
609
648
|
...(surfacesLine === null
|
|
610
649
|
? ["- hotfix paths line not reported by detailed status"]
|
|
611
650
|
: [`- ${surfacesLine}`]),
|
|
651
|
+
...(surfaceNoteLine === null
|
|
652
|
+
? ["- hotfix detail line not reported by detailed status"]
|
|
653
|
+
: [`- ${surfaceNoteLine}`]),
|
|
612
654
|
...(hotfixLine === null
|
|
613
655
|
? ["- hotfix guidance line not reported by detailed status"]
|
|
614
656
|
: [`- ${hotfixLine}`]),
|
|
@@ -649,7 +691,8 @@ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspec
|
|
|
649
691
|
: coverageSnapshot.profiles.map((entry) => `- ${entry.current ? "*" : ""}${entry.label} coverage=${entry.coverageState} hook=${entry.hookFiles} config=${entry.configLoad} runtime=${entry.runtimeLoad} loadedAt=${entry.loadedAt ?? "none"}`)),
|
|
650
692
|
"",
|
|
651
693
|
"## Hardening snapshot",
|
|
652
|
-
`- status signals: statusOk=${hardeningSnapshot.statusSignals.statusOk} loadProofReady=${hardeningSnapshot.statusSignals.loadProofReady} runtimeProven=${hardeningSnapshot.statusSignals.runtimeProven} serveActivePack=${hardeningSnapshot.statusSignals.serveActivePack} routeFnAvailable=${hardeningSnapshot.statusSignals.routeFnAvailable}`,
|
|
694
|
+
`- status signals: statusOk=${hardeningSnapshot.statusSignals.statusOk} loadProofReady=${hardeningSnapshot.statusSignals.loadProofReady} runtimeProven=${hardeningSnapshot.statusSignals.runtimeProven} serveActivePack=${hardeningSnapshot.statusSignals.serveActivePack} routeFnAvailable=${hardeningSnapshot.statusSignals.routeFnAvailable} surfaceConverged=${hardeningSnapshot.statusSignals.surfaceConverged}`,
|
|
695
|
+
`- surface: boundary=${hardeningSnapshot.surface.boundary ?? "none"} skew=${hardeningSnapshot.surface.skew ?? "none"} converge=${hardeningSnapshot.surface.converge ?? "none"} daemonSource=${hardeningSnapshot.surface.daemonSource ?? "none"} daemon=${hardeningSnapshot.surface.daemon ?? "none"} hook=${hardeningSnapshot.surface.hook ?? "none"} selectedHome=${hardeningSnapshot.surface.selectedHome ?? "none"}`,
|
|
653
696
|
`- serve: state=${hardeningSnapshot.serve.state ?? "none"} failOpen=${hardeningSnapshot.serve.failOpen ?? "none"} hardFail=${hardeningSnapshot.serve.hardFail ?? "none"} usedRouteFn=${hardeningSnapshot.serve.usedRouteFn ?? "none"}`,
|
|
654
697
|
`- attachTruth: current=${hardeningSnapshot.attachTruth.current ?? "none"} hook=${hardeningSnapshot.attachTruth.hook ?? "none"} config=${hardeningSnapshot.attachTruth.config ?? "none"} runtime=${hardeningSnapshot.attachTruth.runtime ?? "none"}`,
|
|
655
698
|
`- proof verdict: ${hardeningSnapshot.verdict.verdict} severity=${hardeningSnapshot.verdict.severity} warnings=${hardeningSnapshot.verdict.warningCount}`,
|
|
@@ -702,6 +745,7 @@ export function buildProofCommandHelpSection() {
|
|
|
702
745
|
return {
|
|
703
746
|
usage: " openclawbrain proof --openclaw-home <path> [options]",
|
|
704
747
|
optionLines: [
|
|
748
|
+
" --openclaw-home <path> Target one explicit OpenClaw home (for example ./openclaw-cormorantai or ~/.openclaw).",
|
|
705
749
|
" --output-dir <path> Bundle directory for proof artifacts (proof only). Defaults to ./artifacts/operator-proof-<timestamp>.",
|
|
706
750
|
" --skip-install Capture proof without rerunning install first (proof only).",
|
|
707
751
|
" --skip-restart Capture proof without restarting OpenClaw first (proof only).",
|
|
@@ -937,6 +981,7 @@ export function captureOperatorProofBundle(options) {
|
|
|
937
981
|
const statusSignals = extractStatusSignals(statusCapture.stdout);
|
|
938
982
|
const surfaceLine = extractDetailedStatusLine(statusCapture.stdout, "surface");
|
|
939
983
|
const surfacesLine = extractDetailedStatusLine(statusCapture.stdout, "surfaces");
|
|
984
|
+
const surfaceNoteLine = extractDetailedStatusLine(statusCapture.stdout, "surfaceNote");
|
|
940
985
|
const hotfixLine = extractDetailedStatusLine(statusCapture.stdout, "hotfix");
|
|
941
986
|
const attachTruthLine = extractDetailedStatusLine(statusCapture.stdout, "attachTruth");
|
|
942
987
|
const attachedSetLine = extractDetailedStatusLine(statusCapture.stdout, "attachedSet");
|
|
@@ -978,6 +1023,7 @@ export function captureOperatorProofBundle(options) {
|
|
|
978
1023
|
attachTruthLine,
|
|
979
1024
|
serveLine,
|
|
980
1025
|
routeFnLine,
|
|
1026
|
+
surfaceLine,
|
|
981
1027
|
verdict,
|
|
982
1028
|
statusSignals,
|
|
983
1029
|
});
|
|
@@ -1004,6 +1050,7 @@ export function captureOperatorProofBundle(options) {
|
|
|
1004
1050
|
runtimeLoadProofError: runtimeLoadProofSnapshot.error,
|
|
1005
1051
|
surfaceLine,
|
|
1006
1052
|
surfacesLine,
|
|
1053
|
+
surfaceNoteLine,
|
|
1007
1054
|
hotfixLine,
|
|
1008
1055
|
guardLine,
|
|
1009
1056
|
learningFlowLine,
|
|
@@ -1025,6 +1072,7 @@ export function captureOperatorProofBundle(options) {
|
|
|
1025
1072
|
runtimeLoadProofSnapshot,
|
|
1026
1073
|
surfaceLine,
|
|
1027
1074
|
surfacesLine,
|
|
1075
|
+
surfaceNoteLine,
|
|
1028
1076
|
hotfixLine,
|
|
1029
1077
|
guardLine,
|
|
1030
1078
|
learningFlowLine,
|
|
@@ -1051,6 +1099,7 @@ export function captureOperatorProofBundle(options) {
|
|
|
1051
1099
|
statusSignals,
|
|
1052
1100
|
surfaceLine,
|
|
1053
1101
|
surfacesLine,
|
|
1102
|
+
surfaceNoteLine,
|
|
1054
1103
|
hotfixLine,
|
|
1055
1104
|
guardLine,
|
|
1056
1105
|
learningFlowLine,
|
package/package.json
CHANGED