@openclawbrain/openclaw 0.3.4 → 0.3.6
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/README.md +57 -4
- package/dist/extension/runtime-guard.js +6 -3
- package/dist/src/attachment-truth.js +7 -2
- package/dist/src/cli.js +143 -83
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.js +30 -6
- package/dist/src/openclaw-hook-truth.d.ts +8 -0
- package/dist/src/openclaw-hook-truth.js +134 -28
- package/dist/src/openclaw-plugin-install.d.ts +40 -0
- package/dist/src/openclaw-plugin-install.js +282 -0
- package/dist/src/resolve-activation-root.js +14 -9
- package/dist/src/shadow-extension-proof.d.ts +3 -0
- package/dist/src/shadow-extension-proof.js +23 -23
- package/extension/runtime-guard.ts +12 -9
- package/openclaw.plugin.json +11 -0
- package/package.json +16 -7
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { existsSync, readFileSync } from "node:fs";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { describeOpenClawHomeInspection, discoverOpenClawHomes, formatOpenClawHomeLayout, inspectOpenClawHome } from "./openclaw-home-layout.js";
|
|
16
|
+
import { findInstalledOpenClawBrainPlugin } from "./openclaw-plugin-install.js";
|
|
16
17
|
function getHomeDir() {
|
|
17
18
|
return process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
18
19
|
}
|
|
@@ -68,11 +69,13 @@ function extractActivationRootFromExtension(filePath) {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
function readActivationRootFromOpenClawHome(openclawHome) {
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
72
|
+
const installedPlugin = findInstalledOpenClawBrainPlugin(openclawHome);
|
|
73
|
+
if (installedPlugin.selectedInstall === null ||
|
|
74
|
+
installedPlugin.selectedInstall.loaderEntryPath === null ||
|
|
75
|
+
installedPlugin.selectedInstall.runtimeGuardPath === null) {
|
|
73
76
|
return null;
|
|
74
77
|
}
|
|
75
|
-
return extractActivationRootFromExtension(
|
|
78
|
+
return extractActivationRootFromExtension(installedPlugin.selectedInstall.loaderEntryPath);
|
|
76
79
|
}
|
|
77
80
|
/**
|
|
78
81
|
* Scan discoverable ~/.openclaw* directories for installed hooks and record
|
|
@@ -82,14 +85,16 @@ function scanInstalledProfileActivationRoots() {
|
|
|
82
85
|
const probes = [];
|
|
83
86
|
for (const inspection of discoverOpenClawHomes(path.resolve(getHomeDir()))) {
|
|
84
87
|
const openclawHome = inspection.openclawHome;
|
|
85
|
-
const
|
|
86
|
-
if (
|
|
88
|
+
const installedPlugin = findInstalledOpenClawBrainPlugin(openclawHome);
|
|
89
|
+
if (installedPlugin.selectedInstall === null ||
|
|
90
|
+
installedPlugin.selectedInstall.loaderEntryPath === null ||
|
|
91
|
+
installedPlugin.selectedInstall.runtimeGuardPath === null) {
|
|
87
92
|
continue;
|
|
88
93
|
}
|
|
89
|
-
const found = extractActivationRootFromExtension(
|
|
94
|
+
const found = extractActivationRootFromExtension(installedPlugin.selectedInstall.loaderEntryPath);
|
|
90
95
|
probes.push({
|
|
91
96
|
openclawHome,
|
|
92
|
-
|
|
97
|
+
extensionEntryPath: installedPlugin.selectedInstall.loaderEntryPath,
|
|
93
98
|
activationRoot: found.activationRoot,
|
|
94
99
|
diagnostic: found.diagnostic,
|
|
95
100
|
inspection
|
|
@@ -109,7 +114,7 @@ function buildUnpinnedResolutionRefusal(input) {
|
|
|
109
114
|
details.push(` - ${probe.openclawHome} [${inspectionSummary}] -> ${probe.activationRoot}`);
|
|
110
115
|
continue;
|
|
111
116
|
}
|
|
112
|
-
details.push(` - ${probe.openclawHome} [${inspectionSummary}] -> unresolved: ${probe.diagnostic ?? `installed extension ${probe.
|
|
117
|
+
details.push(` - ${probe.openclawHome} [${inspectionSummary}] -> unresolved: ${probe.diagnostic ?? `installed extension ${probe.extensionEntryPath} is unresolved`}`);
|
|
113
118
|
}
|
|
114
119
|
return [
|
|
115
120
|
"Refusing to auto-select an activation root from unpinned host state.",
|
|
@@ -182,4 +187,4 @@ export function resolveActivationRoot(options = {}) {
|
|
|
182
187
|
}
|
|
183
188
|
throw new Error(`No brain found. ${buildInstallGuidance()}`);
|
|
184
189
|
}
|
|
185
|
-
//# sourceMappingURL=resolve-activation-root.js.map
|
|
190
|
+
//# sourceMappingURL=resolve-activation-root.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type OpenClawBrainInstallLayout } from "./openclaw-plugin-install.js";
|
|
1
2
|
export interface InstalledExtensionPackageJson {
|
|
2
3
|
name?: unknown;
|
|
3
4
|
version?: unknown;
|
|
@@ -19,6 +20,7 @@ export interface ShadowProfileExtensionInstall {
|
|
|
19
20
|
openclawHome: string;
|
|
20
21
|
extensionsDir: string;
|
|
21
22
|
extensionDir: string;
|
|
23
|
+
installLayout: OpenClawBrainInstallLayout;
|
|
22
24
|
manifestPath: string;
|
|
23
25
|
packageJsonPath: string;
|
|
24
26
|
loaderEntryPath: string;
|
|
@@ -26,6 +28,7 @@ export interface ShadowProfileExtensionInstall {
|
|
|
26
28
|
manifest: InstalledPluginManifest;
|
|
27
29
|
packageJson: InstalledExtensionPackageJson;
|
|
28
30
|
configuredEntries: string[];
|
|
31
|
+
additionalInstalls: import("./openclaw-plugin-install.js").OpenClawBrainInstalledPlugin[];
|
|
29
32
|
}
|
|
30
33
|
export interface ShadowProfileExtensionLoadProof extends ShadowProfileExtensionInstall {
|
|
31
34
|
runtimeGuardExportNames: string[];
|
|
@@ -2,6 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { describeOpenClawBrainInstallLayout, findInstalledOpenClawBrainPlugin } from "./openclaw-plugin-install.js";
|
|
5
6
|
const REQUIRED_RUNTIME_GUARD_EXPORTS = [
|
|
6
7
|
"createBeforePromptBuildHandler",
|
|
7
8
|
"isActivationRootPlaceholder",
|
|
@@ -10,26 +11,19 @@ const REQUIRED_RUNTIME_GUARD_EXPORTS = [
|
|
|
10
11
|
];
|
|
11
12
|
export function inspectInstalledOpenClawBrainExtension(openclawHome, extensionId = "openclawbrain") {
|
|
12
13
|
const resolvedOpenclawHome = path.resolve(openclawHome);
|
|
13
|
-
const
|
|
14
|
-
const
|
|
14
|
+
const installedPlugin = findInstalledOpenClawBrainPlugin(resolvedOpenclawHome, extensionId);
|
|
15
|
+
const extensionsDir = installedPlugin.extensionsDir;
|
|
15
16
|
if (!existsSync(extensionsDir)) {
|
|
16
17
|
throw new Error(`[shadow-extension-load-proof] OpenClaw extensions dir is missing: ${extensionsDir}`);
|
|
17
18
|
}
|
|
18
|
-
if (
|
|
19
|
-
throw new Error(`[shadow-extension-load-proof] Installed extension dir is missing
|
|
20
|
-
}
|
|
21
|
-
const manifestPath = path.join(extensionDir, "openclaw.plugin.json");
|
|
22
|
-
const packageJsonPath = path.join(extensionDir, "package.json");
|
|
23
|
-
const runtimeGuardPath = path.join(extensionDir, "runtime-guard.js");
|
|
24
|
-
if (!existsSync(manifestPath)) {
|
|
25
|
-
throw new Error(`[shadow-extension-load-proof] Plugin manifest missing: ${manifestPath}`);
|
|
26
|
-
}
|
|
27
|
-
if (!existsSync(packageJsonPath)) {
|
|
28
|
-
throw new Error(`[shadow-extension-load-proof] Package manifest missing: ${packageJsonPath}`);
|
|
29
|
-
}
|
|
30
|
-
if (!existsSync(runtimeGuardPath)) {
|
|
31
|
-
throw new Error(`[shadow-extension-load-proof] Installed runtime-guard.js is missing: ${runtimeGuardPath}`);
|
|
19
|
+
if (installedPlugin.selectedInstall === null) {
|
|
20
|
+
throw new Error(`[shadow-extension-load-proof] Installed extension dir is missing for plugin ${JSON.stringify(extensionId)} under ${extensionsDir}`);
|
|
32
21
|
}
|
|
22
|
+
const selectedInstall = installedPlugin.selectedInstall;
|
|
23
|
+
const extensionDir = selectedInstall.extensionDir;
|
|
24
|
+
const manifestPath = selectedInstall.manifestPath;
|
|
25
|
+
const packageJsonPath = selectedInstall.packageJsonPath;
|
|
26
|
+
const runtimeGuardPath = selectedInstall.runtimeGuardPath;
|
|
33
27
|
const manifest = readRequiredJson(manifestPath, "plugin manifest");
|
|
34
28
|
if (manifest.id !== extensionId) {
|
|
35
29
|
throw new Error(`[shadow-extension-load-proof] Plugin manifest id must be ${JSON.stringify(extensionId)} at ${manifestPath} ` +
|
|
@@ -41,12 +35,16 @@ export function inspectInstalledOpenClawBrainExtension(openclawHome, extensionId
|
|
|
41
35
|
const packageJson = readRequiredJson(packageJsonPath, "package manifest");
|
|
42
36
|
const configuredEntries = readConfiguredEntries(packageJson, packageJsonPath);
|
|
43
37
|
const loaderEntryPath = resolveLoaderEntryPath(extensionDir, configuredEntries);
|
|
38
|
+
const resolvedRuntimeGuardPath = runtimeGuardPath ?? path.join(path.dirname(loaderEntryPath), "runtime-guard.js");
|
|
39
|
+
if (!existsSync(resolvedRuntimeGuardPath)) {
|
|
40
|
+
throw new Error(`[shadow-extension-load-proof] Installed runtime-guard.js is missing: ${resolvedRuntimeGuardPath}`);
|
|
41
|
+
}
|
|
44
42
|
if (packageJson.type !== "module") {
|
|
45
43
|
throw new Error(`[shadow-extension-load-proof] Installed package manifest must declare \"type\": \"module\" at ${packageJsonPath} ` +
|
|
46
44
|
`(received=${describeValue(packageJson.type)})`);
|
|
47
45
|
}
|
|
48
|
-
if (packageJson.name !== extensionId) {
|
|
49
|
-
throw new Error(`[shadow-extension-load-proof] Installed package manifest name must match
|
|
46
|
+
if (packageJson.name !== extensionId && packageJson.name !== "@openclawbrain/openclaw") {
|
|
47
|
+
throw new Error(`[shadow-extension-load-proof] Installed package manifest name must match ${JSON.stringify(extensionId)} or \"@openclawbrain/openclaw\" at ${packageJsonPath} ` +
|
|
50
48
|
`(received=${describeValue(packageJson.name)})`);
|
|
51
49
|
}
|
|
52
50
|
if (typeof packageJson.version === "string" &&
|
|
@@ -59,25 +57,27 @@ export function inspectInstalledOpenClawBrainExtension(openclawHome, extensionId
|
|
|
59
57
|
openclawHome: resolvedOpenclawHome,
|
|
60
58
|
extensionsDir,
|
|
61
59
|
extensionDir,
|
|
60
|
+
installLayout: selectedInstall.installLayout,
|
|
62
61
|
manifestPath,
|
|
63
62
|
packageJsonPath,
|
|
64
63
|
loaderEntryPath,
|
|
65
|
-
runtimeGuardPath,
|
|
64
|
+
runtimeGuardPath: resolvedRuntimeGuardPath,
|
|
66
65
|
manifest,
|
|
67
66
|
packageJson,
|
|
68
|
-
configuredEntries
|
|
67
|
+
configuredEntries,
|
|
68
|
+
additionalInstalls: installedPlugin.additionalInstalls
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
export async function proveInstalledOpenClawBrainExtensionLoad(openclawHome, extensionId = "openclawbrain") {
|
|
72
72
|
const inspected = inspectInstalledOpenClawBrainExtension(openclawHome, extensionId);
|
|
73
|
-
const runtimeGuardModule = await importWithHelpfulError(inspected.runtimeGuardPath,
|
|
73
|
+
const runtimeGuardModule = await importWithHelpfulError(inspected.runtimeGuardPath, `runtime-guard.js (${describeOpenClawBrainInstallLayout(inspected.installLayout)})`);
|
|
74
74
|
const runtimeGuardExportNames = Object.keys(runtimeGuardModule).sort((left, right) => left.localeCompare(right));
|
|
75
75
|
const missingRuntimeGuardExports = REQUIRED_RUNTIME_GUARD_EXPORTS.filter((exportName) => !runtimeGuardExportNames.includes(exportName));
|
|
76
76
|
if (missingRuntimeGuardExports.length > 0) {
|
|
77
77
|
throw new Error(`[shadow-extension-load-proof] Installed runtime-guard.js is missing required exports ` +
|
|
78
78
|
`${missingRuntimeGuardExports.join(", ")} at ${inspected.runtimeGuardPath}`);
|
|
79
79
|
}
|
|
80
|
-
const loaderModule = await importWithHelpfulError(inspected.loaderEntryPath,
|
|
80
|
+
const loaderModule = await importWithHelpfulError(inspected.loaderEntryPath, `loader entry (${describeOpenClawBrainInstallLayout(inspected.installLayout)})`);
|
|
81
81
|
if (typeof loaderModule.default !== "function") {
|
|
82
82
|
throw new Error(`[shadow-extension-load-proof] Installed loader entry default export must be a function at ${inspected.loaderEntryPath} ` +
|
|
83
83
|
`(received=${describeValue(loaderModule.default)})`);
|
|
@@ -215,4 +215,4 @@ function describeValue(value) {
|
|
|
215
215
|
function isRecord(value) {
|
|
216
216
|
return typeof value === "object" && value !== null;
|
|
217
217
|
}
|
|
218
|
-
//# sourceMappingURL=shadow-extension-proof.js.map
|
|
218
|
+
//# sourceMappingURL=shadow-extension-proof.js.map
|
|
@@ -94,19 +94,22 @@ export function normalizePromptBuildEvent(event: unknown): { ok: true; event: No
|
|
|
94
94
|
const warnings: ExtensionDiagnostic[] = [];
|
|
95
95
|
const sessionId = normalizeOptionalScalarField(event.sessionId, "sessionId", warnings);
|
|
96
96
|
const channel = normalizeOptionalScalarField(event.channel, "channel", warnings);
|
|
97
|
-
|
|
97
|
+
const promptFallback = extractTextContent(event.prompt);
|
|
98
|
+
let extractedMessage = promptFallback ?? "";
|
|
98
99
|
|
|
99
100
|
if (messages.length === 0) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
if (extractedMessage.length === 0) {
|
|
102
|
+
warnings.push(
|
|
103
|
+
failOpenDiagnostic(
|
|
104
|
+
"runtime-messages-empty",
|
|
105
|
+
"before_prompt_build event.messages is empty",
|
|
106
|
+
`event=${describeValue(event)}`
|
|
107
|
+
)
|
|
108
|
+
);
|
|
109
|
+
}
|
|
107
110
|
} else {
|
|
108
111
|
const lastMessage = messages.at(-1);
|
|
109
|
-
extractedMessage = extractPromptMessage(lastMessage) ?? "";
|
|
112
|
+
extractedMessage = extractPromptMessage(lastMessage) ?? promptFallback ?? "";
|
|
110
113
|
if (extractedMessage.length === 0) {
|
|
111
114
|
warnings.push(
|
|
112
115
|
failOpenDiagnostic(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclawbrain/openclaw",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.6",
|
|
4
|
+
"description": "Canonical OpenClawBrain front door for OpenClaw attach, compile, event export, status, and rollback.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
7
7
|
"types": "./dist/src/index.d.ts",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"keywords": [
|
|
12
12
|
"openclawbrain",
|
|
13
13
|
"openclaw",
|
|
14
|
-
"front-door",
|
|
14
|
+
"canonical-front-door",
|
|
15
|
+
"operator-lifecycle",
|
|
15
16
|
"route-fn",
|
|
16
17
|
"integration",
|
|
17
18
|
"typescript"
|
|
@@ -39,7 +40,8 @@
|
|
|
39
40
|
"files": [
|
|
40
41
|
"dist/src",
|
|
41
42
|
"dist/extension",
|
|
42
|
-
"extension"
|
|
43
|
+
"extension",
|
|
44
|
+
"openclaw.plugin.json"
|
|
43
45
|
],
|
|
44
46
|
"publishConfig": {
|
|
45
47
|
"access": "public"
|
|
@@ -53,12 +55,19 @@
|
|
|
53
55
|
"@openclawbrain/event-export": "^0.3.4"
|
|
54
56
|
},
|
|
55
57
|
"bin": {
|
|
56
|
-
"openclawbrain": "
|
|
57
|
-
"openclawbrain-ops": "
|
|
58
|
+
"openclawbrain": "dist/src/cli.js",
|
|
59
|
+
"openclawbrain-ops": "dist/src/cli.js"
|
|
60
|
+
},
|
|
61
|
+
"openclaw": {
|
|
62
|
+
"extensions": [
|
|
63
|
+
"./dist/extension/index.js"
|
|
64
|
+
]
|
|
58
65
|
},
|
|
59
66
|
"scripts": {
|
|
60
67
|
"build": "rm -rf dist && tsc -b",
|
|
61
68
|
"clean": "rm -rf dist && tsc -b --clean",
|
|
69
|
+
"prepublishOnly": "npm run release:verify",
|
|
70
|
+
"release:verify": "npm test && node ../../scripts/verify-openclaw-package-tarball.mjs",
|
|
62
71
|
"test": "node --test dist/test/*.test.js"
|
|
63
72
|
}
|
|
64
|
-
}
|
|
73
|
+
}
|