@openclawbrain/openclaw 0.3.6 → 0.4.0

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.
Files changed (62) hide show
  1. package/README.md +23 -228
  2. package/dist/extension/index.js +3 -2
  3. package/dist/extension/index.js.map +1 -1
  4. package/dist/extension/runtime-guard.js +1 -1
  5. package/dist/extension/runtime-guard.js.map +1 -1
  6. package/dist/src/attachment-truth.d.ts +32 -22
  7. package/dist/src/attachment-truth.js +338 -186
  8. package/dist/src/index.d.ts +75 -1719
  9. package/dist/src/index.js +7 -6882
  10. package/dist/src/runtime-core.js +574 -0
  11. package/extension/index.ts +3 -2
  12. package/extension/runtime-guard.ts +1 -1
  13. package/openclaw.plugin.json +1 -1
  14. package/package.json +17 -17
  15. package/dist/src/attachment-truth.js.map +0 -1
  16. package/dist/src/cli.d.ts +0 -170
  17. package/dist/src/cli.js +0 -5583
  18. package/dist/src/cli.js.map +0 -1
  19. package/dist/src/daemon.d.ts +0 -70
  20. package/dist/src/daemon.js +0 -955
  21. package/dist/src/daemon.js.map +0 -1
  22. package/dist/src/import-export.d.ts +0 -36
  23. package/dist/src/import-export.js +0 -171
  24. package/dist/src/import-export.js.map +0 -1
  25. package/dist/src/index.js.map +0 -1
  26. package/dist/src/learning-spine.d.ts +0 -50
  27. package/dist/src/learning-spine.js.map +0 -1
  28. package/dist/src/local-session-passive-learning.d.ts +0 -61
  29. package/dist/src/local-session-passive-learning.js +0 -454
  30. package/dist/src/local-session-passive-learning.js.map +0 -1
  31. package/dist/src/ollama-client.d.ts +0 -46
  32. package/dist/src/ollama-client.js +0 -231
  33. package/dist/src/ollama-client.js.map +0 -1
  34. package/dist/src/openclaw-home-layout.d.ts +0 -17
  35. package/dist/src/openclaw-home-layout.js +0 -182
  36. package/dist/src/openclaw-home-layout.js.map +0 -1
  37. package/dist/src/openclaw-hook-truth.d.ts +0 -33
  38. package/dist/src/openclaw-hook-truth.js +0 -260
  39. package/dist/src/openclaw-hook-truth.js.map +0 -1
  40. package/dist/src/openclaw-plugin-install.d.ts +0 -40
  41. package/dist/src/openclaw-plugin-install.js +0 -282
  42. package/dist/src/provider-config.d.ts +0 -64
  43. package/dist/src/provider-config.js +0 -306
  44. package/dist/src/provider-config.js.map +0 -1
  45. package/dist/src/resolve-activation-root.d.ts +0 -27
  46. package/dist/src/resolve-activation-root.js +0 -190
  47. package/dist/src/resolve-activation-root.js.map +0 -1
  48. package/dist/src/semantic-metadata.d.ts +0 -5
  49. package/dist/src/semantic-metadata.js +0 -70
  50. package/dist/src/semantic-metadata.js.map +0 -1
  51. package/dist/src/session-store.d.ts +0 -168
  52. package/dist/src/session-store.js +0 -250
  53. package/dist/src/session-store.js.map +0 -1
  54. package/dist/src/session-tail.d.ts +0 -73
  55. package/dist/src/session-tail.js +0 -602
  56. package/dist/src/session-tail.js.map +0 -1
  57. package/dist/src/shadow-extension-proof.d.ts +0 -43
  58. package/dist/src/shadow-extension-proof.js +0 -218
  59. package/dist/src/shadow-extension-proof.js.map +0 -1
  60. package/dist/src/teacher-labeler.d.ts +0 -50
  61. package/dist/src/teacher-labeler.js +0 -424
  62. package/dist/src/teacher-labeler.js.map +0 -1
@@ -0,0 +1,574 @@
1
+ import path from "node:path";
2
+ import process from "node:process";
3
+
4
+ import { compileRuntimeFromActivation } from "@openclawbrain/compiler";
5
+ import { CONTRACT_IDS } from "@openclawbrain/contracts";
6
+ import { inspectActivationState, loadPackFromActivation } from "@openclawbrain/pack-format";
7
+
8
+ import { appendServeTimeRouteDecisionLog } from "./learning-spine.js";
9
+
10
+ const DEFAULT_AGENT_ID = "openclaw-runtime";
11
+ const BRAIN_SERVE_HOT_PATH_TIMING_DETAIL =
12
+ "Measured inside compileRuntimeContext before serve-route logging; includes serve-path normalization, active-pack lookup, structural-budget resolution, route/candidate selection, and prompt assembly when run; excludes background scanner/embedder/teacher work, promotion, and runtime event-export writes.";
13
+
14
+ function toErrorMessage(error) {
15
+ return error instanceof Error ? error.message : String(error);
16
+ }
17
+
18
+ function normalizeNonEmptyString(value, fieldName) {
19
+ if (typeof value !== "string" || value.trim().length === 0) {
20
+ throw new Error(`${fieldName} is required`);
21
+ }
22
+
23
+ return value.trim();
24
+ }
25
+
26
+ function normalizeOptionalString(value) {
27
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
28
+ }
29
+
30
+ function normalizeNonNegativeInteger(value, fieldName, fallbackValue) {
31
+ if (value === undefined || value === null) {
32
+ return fallbackValue;
33
+ }
34
+
35
+ if (!Number.isInteger(value) || value < 0) {
36
+ throw new Error(`${fieldName} must be a non-negative integer`);
37
+ }
38
+
39
+ return value;
40
+ }
41
+
42
+ function normalizeMode(value) {
43
+ return value ?? "heuristic";
44
+ }
45
+
46
+ function normalizeCompileSelectionMode(value) {
47
+ if (value === undefined) {
48
+ return undefined;
49
+ }
50
+
51
+ if (value === "flat_rank_v1" || value === "graph_walk_v1") {
52
+ return value;
53
+ }
54
+
55
+ throw new Error(`selectionMode must be flat_rank_v1 or graph_walk_v1, received ${String(value)}`);
56
+ }
57
+
58
+ function normalizeRuntimeHints(value) {
59
+ if (value === undefined) {
60
+ return [];
61
+ }
62
+
63
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.trim().length === 0)) {
64
+ throw new Error("runtimeHints must be an array of non-empty strings");
65
+ }
66
+
67
+ return value.map((item) => item.trim());
68
+ }
69
+
70
+ function formatPromptContext(compileResponse) {
71
+ const lines = [
72
+ "[BRAIN_CONTEXT v1]",
73
+ `PACK_ID: ${compileResponse.packId}`,
74
+ `MODE: ${compileResponse.diagnostics.modeEffective}`,
75
+ ];
76
+
77
+ if (compileResponse.diagnostics.routerIdentity !== null) {
78
+ lines.push(`ROUTER: ${compileResponse.diagnostics.routerIdentity}`);
79
+ }
80
+
81
+ if (compileResponse.selectedContext.length > 0) {
82
+ lines.push("");
83
+ }
84
+
85
+ for (const block of compileResponse.selectedContext) {
86
+ lines.push(`SOURCE: ${block.source}`);
87
+ lines.push(`BLOCK_ID: ${block.id}`);
88
+ lines.push(block.text.trim());
89
+ lines.push("");
90
+ }
91
+
92
+ if (lines.at(-1) === "") {
93
+ lines.pop();
94
+ }
95
+
96
+ lines.push("[/BRAIN_CONTEXT]");
97
+
98
+ return `${lines.join("\n")}\n`;
99
+ }
100
+
101
+ function resolveActivationRootForFailure(value) {
102
+ return path.resolve(normalizeOptionalString(value) ?? ".");
103
+ }
104
+
105
+ function monotonicClockNs() {
106
+ return process.hrtime.bigint();
107
+ }
108
+
109
+ function elapsedMsFrom(startedAtNs, endedAtNs = monotonicClockNs()) {
110
+ return Number(endedAtNs - startedAtNs) / 1_000_000;
111
+ }
112
+
113
+ function roundHotPathTimingMs(value) {
114
+ return Math.round(value * 1_000) / 1_000;
115
+ }
116
+
117
+ function buildUnavailableBrainServeHotPathTiming(detail) {
118
+ return {
119
+ scope: "brain_serve_hot_path_only",
120
+ totalMs: null,
121
+ routeSelectionMs: null,
122
+ promptAssemblyMs: null,
123
+ otherMs: null,
124
+ backgroundWorkIncluded: false,
125
+ detail,
126
+ };
127
+ }
128
+
129
+ function buildBrainServeHotPathTiming(input) {
130
+ const totalMs = roundHotPathTimingMs(input.totalMs);
131
+ const routeSelectionMs =
132
+ input.routeSelectionMs === null ? null : roundHotPathTimingMs(input.routeSelectionMs);
133
+ const promptAssemblyMs =
134
+ input.promptAssemblyMs === null ? null : roundHotPathTimingMs(input.promptAssemblyMs);
135
+ const otherMs = roundHotPathTimingMs(
136
+ Math.max(0, input.totalMs - (input.routeSelectionMs ?? 0) - (input.promptAssemblyMs ?? 0)),
137
+ );
138
+
139
+ return {
140
+ scope: "brain_serve_hot_path_only",
141
+ totalMs,
142
+ routeSelectionMs,
143
+ promptAssemblyMs,
144
+ otherMs,
145
+ backgroundWorkIncluded: false,
146
+ detail: BRAIN_SERVE_HOT_PATH_TIMING_DETAIL,
147
+ };
148
+ }
149
+
150
+ function failOpenCompileResult(
151
+ error,
152
+ activationRoot,
153
+ timing = buildUnavailableBrainServeHotPathTiming("serve-path timing was unavailable"),
154
+ ) {
155
+ return {
156
+ ok: false,
157
+ fallbackToStaticContext: true,
158
+ hardRequirementViolated: false,
159
+ activationRoot: path.resolve(activationRoot),
160
+ error: toErrorMessage(error),
161
+ brainContext: "",
162
+ timing,
163
+ };
164
+ }
165
+
166
+ function classifyCompileFailure(
167
+ error,
168
+ activationRoot,
169
+ timing = buildUnavailableBrainServeHotPathTiming("serve-path timing was unavailable"),
170
+ ) {
171
+ const resolvedActivationRoot = path.resolve(activationRoot);
172
+
173
+ try {
174
+ const inspection = inspectActivationState(resolvedActivationRoot);
175
+ const active = inspection.active;
176
+
177
+ if (active !== null && active.routePolicy === "requires_learned_routing") {
178
+ const failureReason = active.findings.length > 0 ? active.findings.join("; ") : toErrorMessage(error);
179
+
180
+ return {
181
+ ok: false,
182
+ fallbackToStaticContext: false,
183
+ hardRequirementViolated: true,
184
+ activationRoot: resolvedActivationRoot,
185
+ error: `Learned-routing hotpath hard requirement violated for active pack ${active.packId} (routerIdentity=${active.routerIdentity ?? "null"}): ${failureReason}`,
186
+ brainContext: "",
187
+ timing,
188
+ };
189
+ }
190
+ } catch {
191
+ return failOpenCompileResult(error, resolvedActivationRoot, timing);
192
+ }
193
+
194
+ return failOpenCompileResult(error, resolvedActivationRoot, timing);
195
+ }
196
+
197
+ function uniqueNotes(notes) {
198
+ return [...new Set(notes.filter((note) => note.length > 0))];
199
+ }
200
+
201
+ function buildServeRouteLogFailOpenWarning(scope, error) {
202
+ return `learning spine serve route log failed open (${scope}): ${toErrorMessage(error)}`;
203
+ }
204
+
205
+ function buildServeRouteLogFailOpenNotes(scope, error) {
206
+ return [
207
+ "serve_route_log_status=fail_open",
208
+ `serve_route_log_scope=${scope}`,
209
+ `serve_route_log_error=${toErrorMessage(error)}`,
210
+ ];
211
+ }
212
+
213
+ function normalizeServeRouteChannel(value) {
214
+ if (typeof value !== "string") {
215
+ return undefined;
216
+ }
217
+
218
+ const trimmed = value.trim();
219
+ return trimmed.length > 0 ? trimmed : undefined;
220
+ }
221
+
222
+ function normalizeServeRouteMessage(value) {
223
+ return typeof value === "string" ? value.trim() : "";
224
+ }
225
+
226
+ function normalizeServeRouteInstalledEntryPath(value) {
227
+ if (typeof value !== "string") {
228
+ return null;
229
+ }
230
+
231
+ const trimmed = value.trim();
232
+ return trimmed.length === 0 ? null : path.resolve(trimmed);
233
+ }
234
+
235
+ function buildCompileServeRouteBreadcrumbs(input) {
236
+ return {
237
+ entrypoint: "compileRuntimeContext",
238
+ invocationSurface: input._serveRouteBreadcrumbs?.invocationSurface ?? "direct_compile_call",
239
+ hostEvent: input._serveRouteBreadcrumbs?.hostEvent ?? null,
240
+ installedEntryPath: normalizeServeRouteInstalledEntryPath(input._serveRouteBreadcrumbs?.installedEntryPath),
241
+ syntheticTurn: true,
242
+ };
243
+ }
244
+
245
+ function appendCompileServeRouteDecisionLog(input) {
246
+ if (input.compileInput._suppressServeLog) {
247
+ return;
248
+ }
249
+
250
+ if (!input.compileResult.ok && input.userMessage.length === 0) {
251
+ return;
252
+ }
253
+
254
+ const recordedAt = new Date().toISOString();
255
+ const sessionId = normalizeServeRouteChannel(input.compileInput.sessionId) ?? `ext-compile-${Date.now()}`;
256
+ const channel = normalizeServeRouteChannel(input.compileInput.channel) ?? "extension";
257
+ const syntheticTurn = {
258
+ sessionId,
259
+ channel,
260
+ userMessage: input.userMessage,
261
+ createdAt: recordedAt,
262
+ };
263
+
264
+ if (input.compileInput.maxContextBlocks !== undefined) {
265
+ syntheticTurn.maxContextBlocks = input.compileInput.maxContextBlocks;
266
+ }
267
+
268
+ if (input.compileInput.budgetStrategy === "fixed_v1" || input.compileInput.budgetStrategy === "empirical_v1") {
269
+ syntheticTurn.budgetStrategy = input.compileInput.budgetStrategy;
270
+ }
271
+
272
+ if (input.compileInput.mode === "heuristic" || input.compileInput.mode === "learned") {
273
+ syntheticTurn.mode = input.compileInput.mode;
274
+ }
275
+
276
+ if (input.compileInput.runtimeHints !== undefined) {
277
+ syntheticTurn.runtimeHints = input.compileInput.runtimeHints;
278
+ }
279
+
280
+ try {
281
+ appendServeTimeRouteDecisionLog({
282
+ activationRoot: input.activationRoot,
283
+ turn: syntheticTurn,
284
+ compileResult: input.compileResult,
285
+ recordedAt,
286
+ breadcrumbs: buildCompileServeRouteBreadcrumbs(input.compileInput),
287
+ });
288
+ } catch (error) {
289
+ if (input.compileResult.ok) {
290
+ input.compileResult.compileResponse.diagnostics.notes = uniqueNotes([
291
+ ...input.compileResult.compileResponse.diagnostics.notes,
292
+ ...buildServeRouteLogFailOpenNotes("compileRuntimeContext", error),
293
+ ]);
294
+ }
295
+
296
+ console.warn(
297
+ `[openclawbrain] ${buildServeRouteLogFailOpenWarning("compileRuntimeContext", error)} ` +
298
+ `(activationRoot=${input.activationRoot}, sessionId=${sessionId}, channel=${channel})`,
299
+ );
300
+ }
301
+ }
302
+
303
+ function clampInteger(value, minimum, maximum) {
304
+ return Math.min(maximum, Math.max(minimum, Math.round(value)));
305
+ }
306
+
307
+ function deriveEmpiricalStructuralBudget(input) {
308
+ const requestedStrategy = input.requestedStrategy ?? "fixed_v1";
309
+ const defaultMaxContextBlocks = input.defaultMaxContextBlocks ?? 4;
310
+ const minimumMaxContextBlocks = input.minimumMaxContextBlocks ?? 2;
311
+ const maximumMaxContextBlocks = input.maximumMaxContextBlocks ?? 6;
312
+
313
+ if (input.requestedMaxContextBlocks !== undefined) {
314
+ const maxContextBlocks = clampInteger(input.requestedMaxContextBlocks, 0, Number.MAX_SAFE_INTEGER);
315
+
316
+ return {
317
+ requestedStrategy,
318
+ effectiveStrategy: requestedStrategy,
319
+ maxContextBlocks,
320
+ defaultMaxContextBlocks,
321
+ evidence: { split: 0, merge: 0, prune: 0, connect: 0 },
322
+ evidenceTotal: 0,
323
+ tendencies: { split: 0, merge: 0, prune: 0, connect: 0 },
324
+ notes: [
325
+ `requested_budget_strategy=${requestedStrategy}`,
326
+ `requested_max_context_blocks=${maxContextBlocks}`,
327
+ `resolved_budget_strategy=${requestedStrategy}`,
328
+ `resolved_max_context_blocks=${maxContextBlocks}`,
329
+ "structural_budget_source=caller_override",
330
+ ],
331
+ };
332
+ }
333
+
334
+ if (requestedStrategy !== "empirical_v1") {
335
+ return {
336
+ requestedStrategy,
337
+ effectiveStrategy: requestedStrategy,
338
+ maxContextBlocks: defaultMaxContextBlocks,
339
+ defaultMaxContextBlocks,
340
+ evidence: { split: 0, merge: 0, prune: 0, connect: 0 },
341
+ evidenceTotal: 0,
342
+ tendencies: { split: 0, merge: 0, prune: 0, connect: 0 },
343
+ notes: [
344
+ `requested_budget_strategy=${requestedStrategy}`,
345
+ `resolved_budget_strategy=${requestedStrategy}`,
346
+ `resolved_max_context_blocks=${defaultMaxContextBlocks}`,
347
+ `structural_budget_source=${requestedStrategy === "fixed_v1" ? "fixed_default" : "fixed_fallback"}`,
348
+ ],
349
+ };
350
+ }
351
+
352
+ const evidence = {
353
+ split: Math.max(0, input.evolution?.structuralOps.split ?? 0),
354
+ merge: Math.max(0, input.evolution?.structuralOps.merge ?? 0),
355
+ prune: Math.max(
356
+ 0,
357
+ Math.max(input.evolution?.structuralOps.prune ?? 0, input.evolution?.prunedBlockIds.length ?? 0),
358
+ ),
359
+ connect: Math.max(0, input.evolution?.structuralOps.connect ?? 0),
360
+ };
361
+ const evidenceTotal = evidence.split + evidence.merge + evidence.prune + evidence.connect;
362
+
363
+ if (evidenceTotal === 0) {
364
+ return {
365
+ requestedStrategy,
366
+ effectiveStrategy: "fixed_v1",
367
+ maxContextBlocks: defaultMaxContextBlocks,
368
+ defaultMaxContextBlocks,
369
+ evidence,
370
+ evidenceTotal,
371
+ tendencies: { split: 0, merge: 0, prune: 0, connect: 0 },
372
+ notes: [
373
+ `requested_budget_strategy=${requestedStrategy}`,
374
+ "resolved_budget_strategy=fixed_v1",
375
+ `resolved_max_context_blocks=${defaultMaxContextBlocks}`,
376
+ "structural_budget_source=no_evidence_fallback",
377
+ ],
378
+ };
379
+ }
380
+
381
+ const tendencies = {
382
+ split: evidence.split / evidenceTotal,
383
+ merge: evidence.merge / evidenceTotal,
384
+ prune: evidence.prune / evidenceTotal,
385
+ connect: evidence.connect / evidenceTotal,
386
+ };
387
+ const expansionPressure = tendencies.split + tendencies.connect;
388
+ const contractionPressure = tendencies.merge + tendencies.prune;
389
+ const directionalPressure = expansionPressure - contractionPressure;
390
+ const maxContextBlocks = clampInteger(
391
+ defaultMaxContextBlocks + directionalPressure * 2,
392
+ minimumMaxContextBlocks,
393
+ maximumMaxContextBlocks,
394
+ );
395
+
396
+ return {
397
+ requestedStrategy,
398
+ effectiveStrategy: requestedStrategy,
399
+ maxContextBlocks,
400
+ defaultMaxContextBlocks,
401
+ evidence,
402
+ evidenceTotal,
403
+ tendencies,
404
+ notes: [
405
+ `requested_budget_strategy=${requestedStrategy}`,
406
+ `resolved_budget_strategy=${requestedStrategy}`,
407
+ `resolved_max_context_blocks=${maxContextBlocks}`,
408
+ "structural_budget_source=graph_evolution_empirical_v1",
409
+ `structural_budget_evidence=split:${evidence.split},merge:${evidence.merge},prune:${evidence.prune},connect:${evidence.connect},total:${evidenceTotal}`,
410
+ `structural_budget_tendencies=split:${tendencies.split.toFixed(4)},merge:${tendencies.merge.toFixed(4)},prune:${tendencies.prune.toFixed(4)},connect:${tendencies.connect.toFixed(4)}`,
411
+ `structural_budget_pressures=expand:${expansionPressure.toFixed(4)},contract:${contractionPressure.toFixed(4)},directional:${directionalPressure.toFixed(4)}`,
412
+ ],
413
+ };
414
+ }
415
+
416
+ function resolveCompileBudget(target, input) {
417
+ const pack = loadPackFromActivation(target.activationRoot, "active");
418
+
419
+ return deriveEmpiricalStructuralBudget({
420
+ requestedStrategy: input.budgetStrategy ?? "empirical_v1",
421
+ ...(input.maxContextBlocks !== undefined ? { requestedMaxContextBlocks: input.maxContextBlocks } : {}),
422
+ ...(pack?.graph.evolution !== undefined ? { evolution: pack.graph.evolution } : {}),
423
+ defaultMaxContextBlocks: 4,
424
+ minimumMaxContextBlocks: 2,
425
+ maximumMaxContextBlocks: 6,
426
+ });
427
+ }
428
+
429
+ function resolveActivePackForCompile(activationRoot) {
430
+ const resolvedActivationRoot = path.resolve(normalizeNonEmptyString(activationRoot, "activationRoot"));
431
+ const inspection = inspectActivationState(resolvedActivationRoot);
432
+ const activePointer = inspection.pointers.active;
433
+
434
+ if (inspection.active === null || activePointer === null) {
435
+ throw new Error(`No active pack pointer found in ${resolvedActivationRoot}`);
436
+ }
437
+
438
+ if (!inspection.active.activationReady) {
439
+ throw new Error(`Active pack is not activation-ready: ${inspection.active.findings.join("; ")}`);
440
+ }
441
+
442
+ return {
443
+ activationRoot: resolvedActivationRoot,
444
+ activePointer,
445
+ inspection: inspection.active,
446
+ };
447
+ }
448
+
449
+ export function compileRuntimeContext(input) {
450
+ const totalStartedAtNs = monotonicClockNs();
451
+ const fallbackActivationRoot = resolveActivationRootForFailure(input.activationRoot);
452
+ let activationRoot = fallbackActivationRoot;
453
+ let agentId = process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
454
+ let runtimeHints = [];
455
+ let selectionMode;
456
+ let userMessage = "";
457
+ let maxContextChars;
458
+ let mode = "heuristic";
459
+ let routeSelectionStartedAtNs = null;
460
+ let routeSelectionMs = null;
461
+ let promptAssemblyStartedAtNs = null;
462
+ let promptAssemblyMs = null;
463
+ let result;
464
+
465
+ try {
466
+ activationRoot = path.resolve(normalizeNonEmptyString(input.activationRoot, "activationRoot"));
467
+ agentId = normalizeOptionalString(input.agentId) ?? process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
468
+ runtimeHints = normalizeRuntimeHints(input.runtimeHints);
469
+ selectionMode = normalizeCompileSelectionMode(input.selectionMode);
470
+ userMessage = normalizeNonEmptyString(input.message, "message");
471
+ maxContextChars =
472
+ input.maxContextChars !== undefined
473
+ ? normalizeNonNegativeInteger(input.maxContextChars, "maxContextChars", input.maxContextChars)
474
+ : undefined;
475
+ mode = normalizeMode(input.mode);
476
+ } catch (error) {
477
+ result = failOpenCompileResult(
478
+ error,
479
+ fallbackActivationRoot,
480
+ buildBrainServeHotPathTiming({
481
+ totalMs: elapsedMsFrom(totalStartedAtNs),
482
+ routeSelectionMs,
483
+ promptAssemblyMs,
484
+ }),
485
+ );
486
+ appendCompileServeRouteDecisionLog({
487
+ compileInput: input,
488
+ activationRoot: result.activationRoot,
489
+ compileResult: result,
490
+ userMessage: normalizeServeRouteMessage(input.message),
491
+ });
492
+ return result;
493
+ }
494
+
495
+ try {
496
+ const target = resolveActivePackForCompile(activationRoot);
497
+ const resolvedBudget = resolveCompileBudget(target, input);
498
+ routeSelectionStartedAtNs = monotonicClockNs();
499
+ const compile = compileRuntimeFromActivation(
500
+ activationRoot,
501
+ {
502
+ contract: CONTRACT_IDS.runtimeCompile,
503
+ agentId,
504
+ userMessage,
505
+ maxContextBlocks: resolvedBudget.maxContextBlocks,
506
+ ...(maxContextChars !== undefined ? { maxContextChars } : {}),
507
+ modeRequested: mode,
508
+ activePackId: target.activePointer.packId,
509
+ ...(input.compactionMode !== undefined ? { compactionMode: input.compactionMode } : {}),
510
+ ...(runtimeHints.length > 0 ? { runtimeHints } : {}),
511
+ },
512
+ {
513
+ ...(selectionMode !== undefined ? { selectionMode } : {}),
514
+ },
515
+ );
516
+ routeSelectionMs = elapsedMsFrom(routeSelectionStartedAtNs);
517
+ const compileResponse = {
518
+ ...compile.response,
519
+ diagnostics: {
520
+ ...compile.response.diagnostics,
521
+ notes: uniqueNotes([
522
+ ...compile.response.diagnostics.notes,
523
+ ...resolvedBudget.notes,
524
+ "OpenClaw remains the runtime owner",
525
+ ]),
526
+ },
527
+ };
528
+ promptAssemblyStartedAtNs = monotonicClockNs();
529
+ const brainContext = formatPromptContext(compileResponse);
530
+ promptAssemblyMs = elapsedMsFrom(promptAssemblyStartedAtNs);
531
+ result = {
532
+ ok: true,
533
+ fallbackToStaticContext: false,
534
+ hardRequirementViolated: false,
535
+ activationRoot,
536
+ activePackId: compile.target.packId,
537
+ packRootDir: path.resolve(target.activePointer.packRootDir),
538
+ compileResponse,
539
+ brainContext,
540
+ timing: buildBrainServeHotPathTiming({
541
+ totalMs: elapsedMsFrom(totalStartedAtNs),
542
+ routeSelectionMs,
543
+ promptAssemblyMs,
544
+ }),
545
+ };
546
+ } catch (error) {
547
+ if (routeSelectionStartedAtNs !== null && routeSelectionMs === null) {
548
+ routeSelectionMs = elapsedMsFrom(routeSelectionStartedAtNs);
549
+ }
550
+
551
+ if (promptAssemblyStartedAtNs !== null && promptAssemblyMs === null) {
552
+ promptAssemblyMs = elapsedMsFrom(promptAssemblyStartedAtNs);
553
+ }
554
+
555
+ result = classifyCompileFailure(
556
+ error,
557
+ activationRoot,
558
+ buildBrainServeHotPathTiming({
559
+ totalMs: elapsedMsFrom(totalStartedAtNs),
560
+ routeSelectionMs,
561
+ promptAssemblyMs,
562
+ }),
563
+ );
564
+ }
565
+
566
+ appendCompileServeRouteDecisionLog({
567
+ compileInput: input,
568
+ activationRoot: result.activationRoot,
569
+ compileResult: result,
570
+ userMessage,
571
+ });
572
+
573
+ return result;
574
+ }
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * OpenClawBrain extension template — canonical, pre-built, versioned with the package.
3
3
  *
4
- * The placeholder __ACTIVATION_ROOT__ is replaced by `openclawbrain install`
4
+ * The placeholder __ACTIVATION_ROOT__ is replaced by
5
+ * `@openclawbrain/cli`'s `openclawbrain install`
5
6
  * with the real activation root path at install time.
6
7
  *
7
8
  * Design constraints:
@@ -67,7 +68,7 @@ function announceStartupBreadcrumb(): void {
67
68
  if (isActivationRootPlaceholder(ACTIVATION_ROOT)) {
68
69
  warnOnce(
69
70
  "startup-brain-not-yet-loaded",
70
- "[openclawbrain] BRAIN NOT YET LOADED: install has not pinned ACTIVATION_ROOT yet. Run: openclawbrain install --openclaw-home <path>"
71
+ "[openclawbrain] BRAIN NOT YET LOADED: install has not pinned ACTIVATION_ROOT yet. Install @openclawbrain/cli, then run: openclawbrain install --openclaw-home <path>"
71
72
  );
72
73
  return;
73
74
  }
@@ -145,7 +145,7 @@ export function createBeforePromptBuildHandler(input: {
145
145
  key: "activation-root-placeholder",
146
146
  once: true,
147
147
  message:
148
- "[openclawbrain] BRAIN NOT YET LOADED: ACTIVATION_ROOT is still a placeholder. Run: openclawbrain install --openclaw-home <path>"
148
+ "[openclawbrain] BRAIN NOT YET LOADED: ACTIVATION_ROOT is still a placeholder. Install @openclawbrain/cli, then run: openclawbrain install --openclaw-home <path>"
149
149
  });
150
150
  return {};
151
151
  }
@@ -2,7 +2,7 @@
2
2
  "id": "openclawbrain",
3
3
  "name": "OpenClawBrain",
4
4
  "description": "Learned memory and context from OpenClawBrain",
5
- "version": "0.3.6",
5
+ "version": "0.4.0",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openclawbrain/openclaw",
3
- "version": "0.3.6",
4
- "description": "Canonical OpenClawBrain front door for OpenClaw attach, compile, event export, status, and rollback.",
3
+ "version": "0.4.0",
4
+ "description": "OpenClawBrain plugin/runtime payload for OpenClaw. Operator CLI and install helpers move to @openclawbrain/cli.",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
7
7
  "types": "./dist/src/index.d.ts",
@@ -11,11 +11,10 @@
11
11
  "keywords": [
12
12
  "openclawbrain",
13
13
  "openclaw",
14
- "canonical-front-door",
15
- "operator-lifecycle",
14
+ "plugin",
15
+ "runtime",
16
16
  "route-fn",
17
- "integration",
18
- "typescript"
17
+ "integration"
19
18
  ],
20
19
  "repository": {
21
20
  "type": "git",
@@ -38,10 +37,17 @@
38
37
  "./package.json": "./package.json"
39
38
  },
40
39
  "files": [
41
- "dist/src",
40
+ "dist/src/index.js",
41
+ "dist/src/index.d.ts",
42
+ "dist/src/runtime-core.js",
43
+ "dist/src/attachment-truth.js",
44
+ "dist/src/attachment-truth.d.ts",
45
+ "dist/src/learning-spine.js",
42
46
  "dist/extension",
43
47
  "extension",
44
- "openclaw.plugin.json"
48
+ "openclaw.plugin.json",
49
+ "README.md",
50
+ "LICENSE"
45
51
  ],
46
52
  "publishConfig": {
47
53
  "access": "public"
@@ -49,14 +55,8 @@
49
55
  "dependencies": {
50
56
  "@openclawbrain/compiler": "^0.3.4",
51
57
  "@openclawbrain/contracts": "^0.3.4",
52
- "@openclawbrain/events": "^0.3.4",
53
58
  "@openclawbrain/learner": "^0.3.4",
54
- "@openclawbrain/pack-format": "^0.3.4",
55
- "@openclawbrain/event-export": "^0.3.4"
56
- },
57
- "bin": {
58
- "openclawbrain": "dist/src/cli.js",
59
- "openclawbrain-ops": "dist/src/cli.js"
59
+ "@openclawbrain/pack-format": "^0.3.4"
60
60
  },
61
61
  "openclaw": {
62
62
  "extensions": [
@@ -64,8 +64,8 @@
64
64
  ]
65
65
  },
66
66
  "scripts": {
67
- "build": "rm -rf dist && tsc -b",
68
- "clean": "rm -rf dist && tsc -b --clean",
67
+ "build": "tsc -p tsconfig.extension.json",
68
+ "clean": "rm -rf dist/extension",
69
69
  "prepublishOnly": "npm run release:verify",
70
70
  "release:verify": "npm test && node ../../scripts/verify-openclaw-package-tarball.mjs",
71
71
  "test": "node --test dist/test/*.test.js"