@openclawbrain/cli 0.4.21 → 0.4.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/cli.js CHANGED
@@ -33,6 +33,11 @@ const OPENCLAWBRAIN_EMBEDDER_MODEL_ENV = "OPENCLAWBRAIN_EMBEDDER_MODEL";
33
33
  const OPENCLAWBRAIN_INSTALL_SKIP_EMBEDDER_PROVISION_ENV = "OPENCLAWBRAIN_INSTALL_SKIP_EMBEDDER_PROVISION";
34
34
  const LEGACY_COMPAT_PACKAGE_NAME = "@jonathangu/openclawbrain";
35
35
  const INSTALL_COMPATIBLE_LOCAL_TEACHER_MODEL_PREFIXES = [
36
+ "unsloth-qwen3.5-27b:q4_k_m",
37
+ "unsloth-qwen3.5-27b",
38
+ "qwen3.5:32b",
39
+ "qwen3.5:27b",
40
+ "qwen3.5:14b",
36
41
  "qwen3.5:9b",
37
42
  "qwen3.5:8b",
38
43
  "qwen3:8b",
@@ -5111,7 +5116,13 @@ function listWatchRuntimeEventExportBundleRoots(scanRoot) {
5111
5116
  .map((entry) => path.join(scanRoot, entry.name))
5112
5117
  .sort((left, right) => left.localeCompare(right));
5113
5118
  }
5114
- async function replayWatchScanRootIntoTeacherLoop(teacherLoop, scanRoot) {
5119
+ async function replayWatchScanRootIntoTeacherLoop(teacherLoop, scanRoot, options = {}) {
5120
+ if (options.skip === true) {
5121
+ return {
5122
+ replayedBundleCount: 0,
5123
+ replayedEventCount: 0
5124
+ };
5125
+ }
5115
5126
  const seenExportDigests = new Set();
5116
5127
  const bundles = listWatchRuntimeEventExportBundleRoots(scanRoot)
5117
5128
  .map((rootDir) => {
@@ -5733,6 +5744,7 @@ export async function createWatchCommandRuntime(input) {
5733
5744
  const restoredSeenExportCount = restoredTeacherState.snapshot.state?.seenExportDigests.length ?? 0;
5734
5745
  log(`Restored teacher snapshot: seen=${restoredSeenExportCount} artifacts=${restoredTeacherState.snapshot.teacher.artifactCount}`);
5735
5746
  }
5747
+ const restoredSeenExportCount = restoredTeacherState.snapshot?.state?.seenExportDigests.length ?? 0;
5736
5748
  const resolvedWatchProfileScope = input.profileRoots === undefined
5737
5749
  ? resolveWatchProfileRootsForActivationRoot(activationRoot)
5738
5750
  : {
@@ -5774,7 +5786,13 @@ export async function createWatchCommandRuntime(input) {
5774
5786
  replayedEventCount: 0
5775
5787
  };
5776
5788
  try {
5777
- replayState = await replayWatchScanRootIntoTeacherLoop(teacherLoop, scanRoot);
5789
+ const skipStoredReplay = restoredSeenExportCount > 0 && startupWarnings.length === 0;
5790
+ if (skipStoredReplay) {
5791
+ log(`Stored replay skipped: restored teacher snapshot already tracks ${restoredSeenExportCount} export digest${restoredSeenExportCount === 1 ? "" : "s"}.`);
5792
+ }
5793
+ replayState = await replayWatchScanRootIntoTeacherLoop(teacherLoop, scanRoot, {
5794
+ skip: skipStoredReplay
5795
+ });
5778
5796
  }
5779
5797
  catch (error) {
5780
5798
  const message = formatWatchError(error);
@@ -928,13 +928,15 @@ export function advanceAlwaysOnLearningRuntime(input) {
928
928
  const schedule = selectScheduledSlices(pending, current.learnedEventExport, cadence);
929
929
  const selectedSlices = schedule.selected;
930
930
  const learnedEventExport = mergeNormalizedEventExports(current.learnedEventExport, selectedSlices);
931
- const runtimeGraphSnapshot = buildRuntimeGraphSnapshot({
932
- ...input,
933
- state: {
934
- ...current,
935
- structuralController
936
- }
937
- });
931
+ const runtimeGraphSnapshot = selectedSlices.length === 0
932
+ ? null
933
+ : buildRuntimeGraphSnapshot({
934
+ ...input,
935
+ state: {
936
+ ...current,
937
+ structuralController
938
+ }
939
+ });
938
940
  const runtimeGraph = runtimeGraphSnapshot?.graph ?? current.runtimeGraph;
939
941
  const runtimePlasticity = runtimeGraphSnapshot?.plasticity ?? current.runtimePlasticity;
940
942
  const sparseFeedbackObservedAt = input.builtAt ?? learnedEventExport?.range.lastCreatedAt ?? learnedEventExport?.range.firstCreatedAt ?? current.lastMaterializedAt ?? "1970-01-01T00:00:00.000Z";
@@ -171,6 +171,35 @@ function parseOpenClawSessionRecord(value, lineNumber) {
171
171
  timestamp: expectString(record.timestamp, `${lineNumber}.timestamp`)
172
172
  };
173
173
  }
174
+ case "compaction": {
175
+ const data = {};
176
+ if (record.summary !== undefined) {
177
+ data.summary = expectString(record.summary, `${lineNumber}.summary`);
178
+ }
179
+ if (record.firstKeptEntryId !== undefined) {
180
+ data.firstKeptEntryId = expectString(record.firstKeptEntryId, `${lineNumber}.firstKeptEntryId`);
181
+ }
182
+ if (record.tokensBefore !== undefined) {
183
+ data.tokensBefore = expectNumber(record.tokensBefore, `${lineNumber}.tokensBefore`);
184
+ }
185
+ if (record.details !== undefined) {
186
+ data.details = expectRecord(record.details, `${lineNumber}.details`);
187
+ }
188
+ if (record.fromHook !== undefined) {
189
+ if (typeof record.fromHook !== "boolean") {
190
+ throw new Error(`${lineNumber}.fromHook must be a boolean`);
191
+ }
192
+ data.fromHook = record.fromHook;
193
+ }
194
+ return {
195
+ type: "custom",
196
+ customType: "openclaw.compaction",
197
+ data,
198
+ id: expectString(record.id, `${lineNumber}.id`),
199
+ parentId: expectNullableString(record.parentId, `${lineNumber}.parentId`),
200
+ timestamp: expectString(record.timestamp, `${lineNumber}.timestamp`)
201
+ };
202
+ }
174
203
  case "message":
175
204
  return {
176
205
  type,
@@ -185,7 +214,9 @@ function parseOpenClawSessionRecord(value, lineNumber) {
185
214
  }
186
215
  function parseMessagePayload(value, path) {
187
216
  const payload = expectRecord(value, path);
188
- const content = expectArray(payload.content, `${path}.content`).map((entry, index) => parseContentPart(entry, `${path}.content[${index}]`));
217
+ const content = typeof payload.content === "string"
218
+ ? [{ type: "text", text: payload.content }]
219
+ : expectArray(payload.content, `${path}.content`).map((entry, index) => parseContentPart(entry, `${path}.content[${index}]`));
189
220
  return {
190
221
  ...payload,
191
222
  role: expectString(payload.role, `${path}.role`),
@@ -267,4 +298,4 @@ function expectNumber(value, path) {
267
298
  }
268
299
  return value;
269
300
  }
270
- //# sourceMappingURL=session-store.js.map
301
+ //# sourceMappingURL=session-store.js.map
@@ -383,6 +383,7 @@ export class OpenClawLocalSessionTail {
383
383
  const firstPoll = this.initialized === false;
384
384
  const warnings = [];
385
385
  const changes = [];
386
+ const observedKeys = new Set();
386
387
  const sources = discoverOpenClawSessionStores({
387
388
  ...(this.homeDir === undefined ? {} : { homeDir: this.homeDir }),
388
389
  ...(this.profileRoots === undefined ? {} : { profileRoots: this.profileRoots })
@@ -409,9 +410,21 @@ export class OpenClawLocalSessionTail {
409
410
  continue;
410
411
  }
411
412
  const key = cursorKey(source.indexPath, sessionKey);
413
+ observedKeys.add(key);
412
414
  const existing = this.cursorBySession.get(key) ?? null;
413
415
  const sessionFile = typeof entry.sessionFile === "string" && entry.sessionFile.trim().length > 0 ? path.resolve(entry.sessionFile) : null;
414
416
  if (sessionFile === null) {
417
+ const nextCursor = createCursor(source.indexPath, sessionKey, entry.sessionId, null, entry.updatedAt, 0, 0);
418
+ this.cursorBySession.set(key, nextCursor);
419
+ const changed = existing === null ||
420
+ existing.sessionId !== entry.sessionId ||
421
+ existing.sessionFile !== null ||
422
+ existing.updatedAt !== entry.updatedAt ||
423
+ existing.rawRecordCount !== 0 ||
424
+ existing.bridgedEventCount !== 0;
425
+ if (!changed) {
426
+ continue;
427
+ }
415
428
  changes.push(createChange({
416
429
  source,
417
430
  sessionKey,
@@ -425,6 +438,17 @@ export class OpenClawLocalSessionTail {
425
438
  continue;
426
439
  }
427
440
  if (!existsSync(sessionFile)) {
441
+ const nextCursor = createCursor(source.indexPath, sessionKey, entry.sessionId, sessionFile, entry.updatedAt, 0, 0);
442
+ this.cursorBySession.set(key, nextCursor);
443
+ const changed = existing === null ||
444
+ existing.sessionId !== entry.sessionId ||
445
+ existing.sessionFile !== sessionFile ||
446
+ existing.updatedAt !== entry.updatedAt ||
447
+ existing.rawRecordCount !== 0 ||
448
+ existing.bridgedEventCount !== 0;
449
+ if (!changed) {
450
+ continue;
451
+ }
428
452
  changes.push(createChange({
429
453
  source,
430
454
  sessionKey,
@@ -535,6 +559,17 @@ export class OpenClawLocalSessionTail {
535
559
  }));
536
560
  }
537
561
  }
562
+ let prunedCursorCount = 0;
563
+ for (const key of [...this.cursorBySession.keys()]) {
564
+ if (observedKeys.has(key)) {
565
+ continue;
566
+ }
567
+ this.cursorBySession.delete(key);
568
+ prunedCursorCount += 1;
569
+ }
570
+ if (prunedCursorCount > 0) {
571
+ warnings.push(`session tail pruned ${prunedCursorCount} stale cursor entr${prunedCursorCount === 1 ? "y" : "ies"}`);
572
+ }
538
573
  this.initialized = true;
539
574
  const noopReason = firstPoll && !changes.some((change) => change.scannedEventExport !== null)
540
575
  ? "seeded_existing_sessions"
@@ -599,4 +634,4 @@ export class OpenClawLocalSessionTail {
599
634
  export function createOpenClawLocalSessionTail(input = {}) {
600
635
  return new OpenClawLocalSessionTail(input);
601
636
  }
602
- //# sourceMappingURL=session-tail.js.map
637
+ //# sourceMappingURL=session-tail.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclawbrain/cli",
3
- "version": "0.4.21",
3
+ "version": "0.4.22",
4
4
  "description": "OpenClawBrain operator CLI package with install/status helpers, daemon controls, and import/export tooling.",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",