@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.
@@ -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 extensionIndex = path.join(path.resolve(openclawHome), "extensions", "openclawbrain", "index.ts");
72
- if (!existsSync(extensionIndex)) {
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(extensionIndex);
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 extensionIndex = path.join(openclawHome, "extensions", "openclawbrain", "index.ts");
86
- if (!existsSync(extensionIndex)) {
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(extensionIndex);
94
+ const found = extractActivationRootFromExtension(installedPlugin.selectedInstall.loaderEntryPath);
90
95
  probes.push({
91
96
  openclawHome,
92
- extensionIndex,
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.extensionIndex} is unresolved`}`);
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 extensionsDir = path.join(resolvedOpenclawHome, "extensions");
14
- const extensionDir = path.join(extensionsDir, extensionId);
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 (!existsSync(extensionDir)) {
19
- throw new Error(`[shadow-extension-load-proof] Installed extension dir is missing: ${extensionDir}`);
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 plugin id ${JSON.stringify(extensionId)} at ${packageJsonPath} ` +
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, "runtime-guard.js");
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, "loader entry");
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
- let extractedMessage = "";
97
+ const promptFallback = extractTextContent(event.prompt);
98
+ let extractedMessage = promptFallback ?? "";
98
99
 
99
100
  if (messages.length === 0) {
100
- warnings.push(
101
- failOpenDiagnostic(
102
- "runtime-messages-empty",
103
- "before_prompt_build event.messages is empty",
104
- `event=${describeValue(event)}`
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(
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "openclawbrain",
3
+ "name": "OpenClawBrain",
4
+ "description": "Learned memory and context from OpenClawBrain",
5
+ "version": "0.3.6",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {}
10
+ }
11
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openclawbrain/openclaw",
3
- "version": "0.3.4",
4
- "description": "Primary OpenClawBrain front door for OpenClaw attach, compile, event export, status, and rollback.",
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": "./dist/src/cli.js",
57
- "openclawbrain-ops": "./dist/src/cli.js"
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
+ }