@clawling/clawchat-plugin-openclaw 2026.7.6-4 → 2026.7.8-1

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.
@@ -278,6 +278,12 @@ export class LivewareSampleSupervisor {
278
278
  try {
279
279
  if (!deps.enabled)
280
280
  return;
281
+ // ensureLivewareCli downloads the CLI asynchronously on first boot;
282
+ // gate the whole flow on it or resolveLivewarePath() below races to null.
283
+ if (deps.cliReady)
284
+ await deps.cliReady;
285
+ if (this.stopped)
286
+ return;
281
287
  const key = { platform: deps.platform, accountId: deps.accountId };
282
288
  const row = deps.store.getLivewareSample(key);
283
289
  if (row?.status === "disabled")
@@ -336,7 +342,7 @@ export class LivewareSampleSupervisor {
336
342
  return;
337
343
  const livewarePath = deps.resolveLivewarePath();
338
344
  if (!livewarePath) {
339
- deps.log?.debug?.("liveware-sample: liveware CLI not ready; skip");
345
+ deps.log?.warn?.("liveware-sample: liveware CLI not ready; skip");
340
346
  return;
341
347
  }
342
348
  const token = deps.resolveToken();
@@ -395,7 +401,7 @@ export class LivewareSampleSupervisor {
395
401
  return;
396
402
  const livewarePath = deps.resolveLivewarePath();
397
403
  if (!livewarePath) {
398
- deps.log?.debug?.("liveware-sample: liveware CLI not ready; skip relaunch");
404
+ deps.log?.warn?.("liveware-sample: liveware CLI not ready; skip relaunch");
399
405
  return;
400
406
  }
401
407
  // The user deleting the app tile is an explicit opt-out — never reinstall.
@@ -668,7 +668,9 @@ export async function startOpenclawClawlingGateway(params) {
668
668
  log,
669
669
  });
670
670
  // Ensure the liveware CLI is installed (async, never blocks startup).
671
- void ensureLivewareCli({
671
+ // Keep the promise: the liveware-sample supervisor must await it, or a
672
+ // first boot races the download, sees no CLI, and silently skips forever.
673
+ const livewareCliReady = ensureLivewareCli({
672
674
  stateDir: runtime.state?.resolveStateDir?.(),
673
675
  log: {
674
676
  warn: (m) => log?.info?.(m),
@@ -800,6 +802,7 @@ export async function startOpenclawClawlingGateway(params) {
800
802
  sampleRoot: path.join(stateDirForSample ?? "", "clawchat", "liveware-sample"),
801
803
  resolveToken: () => account.token ?? "",
802
804
  resolveLivewarePath: () => resolveLivewarePath(stateDirForSample),
805
+ cliReady: livewareCliReady,
803
806
  listApps: async () => {
804
807
  const client = getConversationApiClient();
805
808
  return await client.listApps();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawling/clawchat-plugin-openclaw",
3
- "version": "2026.7.6-4",
3
+ "version": "2026.7.8-1",
4
4
  "description": "OpenClaw ClawChat channel plugin",
5
5
  "license": "MIT",
6
6
  "author": "CLAWLING PTE. LTD.",
@@ -349,6 +349,10 @@ export type LivewareSampleSupervisorDeps = {
349
349
  sampleRoot: string;
350
350
  resolveToken: () => string;
351
351
  resolveLivewarePath: () => string | null;
352
+ /** Settles when the liveware CLI self-download has finished (either way).
353
+ * start() awaits it before the CLI gate so a first boot doesn't lose the
354
+ * race against ensureLivewareCli and silently skip forever. */
355
+ cliReady?: Promise<void>;
352
356
  listApps: () => Promise<{ apps: { app_id?: string }[] }>;
353
357
  registerApp: (p: { name: string; appId: string; url: string }) => Promise<unknown>;
354
358
  notifyOwner: (text: string) => Promise<boolean>;
@@ -392,6 +396,10 @@ export class LivewareSampleSupervisor {
392
396
  const { deps } = this;
393
397
  try {
394
398
  if (!deps.enabled) return;
399
+ // ensureLivewareCli downloads the CLI asynchronously on first boot;
400
+ // gate the whole flow on it or resolveLivewarePath() below races to null.
401
+ if (deps.cliReady) await deps.cliReady;
402
+ if (this.stopped) return;
395
403
  const key = { platform: deps.platform, accountId: deps.accountId };
396
404
  const row = deps.store.getLivewareSample(key);
397
405
  if (row?.status === "disabled") return;
@@ -444,7 +452,7 @@ export class LivewareSampleSupervisor {
444
452
  const { deps } = this;
445
453
  if (this.stopped) return;
446
454
  const livewarePath = deps.resolveLivewarePath();
447
- if (!livewarePath) { deps.log?.debug?.("liveware-sample: liveware CLI not ready; skip"); return; }
455
+ if (!livewarePath) { deps.log?.warn?.("liveware-sample: liveware CLI not ready; skip"); return; }
448
456
  const token = deps.resolveToken();
449
457
  if (!token) { deps.log?.debug?.("liveware-sample: no token; skip"); return; }
450
458
  let apps: { apps: { app_id?: string }[] };
@@ -493,7 +501,7 @@ export class LivewareSampleSupervisor {
493
501
  const { deps } = this;
494
502
  if (this.stopped) return;
495
503
  const livewarePath = deps.resolveLivewarePath();
496
- if (!livewarePath) { deps.log?.debug?.("liveware-sample: liveware CLI not ready; skip relaunch"); return; }
504
+ if (!livewarePath) { deps.log?.warn?.("liveware-sample: liveware CLI not ready; skip relaunch"); return; }
497
505
  // The user deleting the app tile is an explicit opt-out — never reinstall.
498
506
  try {
499
507
  const apps = await deps.listApps();
package/src/runtime.ts CHANGED
@@ -981,7 +981,9 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
981
981
  log,
982
982
  });
983
983
  // Ensure the liveware CLI is installed (async, never blocks startup).
984
- void ensureLivewareCli({
984
+ // Keep the promise: the liveware-sample supervisor must await it, or a
985
+ // first boot races the download, sees no CLI, and silently skips forever.
986
+ const livewareCliReady = ensureLivewareCli({
985
987
  stateDir: runtime.state?.resolveStateDir?.(),
986
988
  log: {
987
989
  warn: (m) => log?.info?.(m),
@@ -1118,6 +1120,7 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
1118
1120
  sampleRoot: path.join(stateDirForSample ?? "", "clawchat", "liveware-sample"),
1119
1121
  resolveToken: () => account.token ?? "",
1120
1122
  resolveLivewarePath: () => resolveLivewarePath(stateDirForSample),
1123
+ cliReady: livewareCliReady,
1121
1124
  listApps: async () => {
1122
1125
  const client = getConversationApiClient();
1123
1126
  return await client.listApps();