function parseSessionDurationMs(raw: string): number { const normalized = normalizeOptionalLowercaseString(raw); if (!normalized) { thrownew Error("missing duration");
} if (SESSION_DURATION_OFF_VALUES.has(normalized)) { return0;
} if (/^\d+(?:\.\d+)?$/.test(normalized)) { const hours = Number(normalized); if (!Number.isFinite(hours) || hours < 0) { thrownew Error("invalid duration");
} return Math.round(hours * 60 * 60 * 1000);
} return parseDurationMs(normalized, { defaultUnit: "h" });
}
function formatSessionExpiry(expiresAt: number) { returnnew Date(expiresAt).toISOString();
}
function resolveSessionBindingDurationMs(
binding: SessionBindingRecord,
key: "idleTimeoutMs" | "maxAgeMs",
fallbackMs: number,
): number { const raw = binding.metadata?.[key]; if (typeof raw !== "number" || !Number.isFinite(raw)) { return fallbackMs;
} return Math.max(0, Math.floor(raw));
}
function resolveSessionBindingLastActivityAt(binding: SessionBindingRecord): number { const raw = binding.metadata?.lastActivityAt; if (typeof raw !== "number" || !Number.isFinite(raw)) { return binding.boundAt;
} return Math.max(Math.floor(raw), binding.boundAt);
}
function resolveSessionBindingBoundBy(binding: SessionBindingRecord): string { const raw = binding.metadata?.boundBy; return normalizeOptionalString(raw) ?? "";
}
function isSessionBindingRecord(
binding: UpdatedLifecycleBinding | SessionBindingRecord,
): binding is SessionBindingRecord { return"bindingId" in binding;
}
function resolveUpdatedLifecycleDurationMs(
binding: UpdatedLifecycleBinding | SessionBindingRecord,
key: "idleTimeoutMs" | "maxAgeMs",
): number | undefined { if (!isSessionBindingRecord(binding)) { const raw = binding[key]; if (typeof raw === "number" && Number.isFinite(raw)) { return Math.max(0, Math.floor(raw));
}
} if (!isSessionBindingRecord(binding)) { return undefined;
} const raw = binding.metadata?.[key]; if (typeof raw !== "number" || !Number.isFinite(raw)) { return undefined;
} return Math.max(0, Math.floor(raw));
}
const activeBinding = sessionBindingService.resolveByConversation(bindingContext); if (!activeBinding) { return {
shouldContinue: false,
reply: { text: "ℹ️ This conversation is not currently focused." },
};
}
const durationArgRaw = tokens.slice(1).join(""); if (!durationArgRaw) { if (action === SESSION_ACTION_IDLE) { if ( typeof idleExpiresAt === "number" &&
Number.isFinite(idleExpiresAt) &&
idleExpiresAt > Date.now()
) { return {
shouldContinue: false,
reply: {
text: `ℹ️ Idle timeout active (${formatThreadBindingDurationLabel(idleTimeoutMs)}, next auto-unfocus at ${formatSessionExpiry(idleExpiresAt)}).`,
},
};
} return {
shouldContinue: false,
reply: { text: "ℹ️ Idle timeout is currently disabled for this focused session." },
};
}
if ( typeof maxAgeExpiresAt === "number" &&
Number.isFinite(maxAgeExpiresAt) &&
maxAgeExpiresAt > Date.now()
) { return {
shouldContinue: false,
reply: {
text: `ℹ️ Max age active (${formatThreadBindingDurationLabel(maxAgeMs)}, hard auto-unfocus at ${formatSessionExpiry(maxAgeExpiresAt)}).`,
},
};
} return {
shouldContinue: false,
reply: { text: "ℹ️ Max age is currently disabled for this focused session." },
};
}
return {
shouldContinue: false,
reply: {
text:
action === SESSION_ACTION_IDLE
? `✅ Idle timeout set to ${formatThreadBindingDurationLabel(durationMs)} for ${updatedBindings.length} binding${updatedBindings.length === 1 ? "" : "s"} (next auto-unfocus at ${expiryLabel}).`
: `✅ Max age set to ${formatThreadBindingDurationLabel(durationMs)} for ${updatedBindings.length} binding${updatedBindings.length === 1 ? "" : "s"} (hard auto-unfocus at ${expiryLabel}).`,
},
};
};
export const handleRestartCommand: CommandHandler = async (params, allowTextCommands) => { if (!allowTextCommands) { returnnull;
} if (params.command.commandBodyNormalized !== "/restart") { returnnull;
} if (!params.command.isAuthorizedSender) {
logVerbose(
`Ignoring /restart from unauthorized sender: ${params.command.senderId || "<unknown>"}`,
); return { shouldContinue: false };
} const nonOwner = rejectNonOwnerCommand(params, "/restart"); if (nonOwner) { return nonOwner;
} if (!isRestartEnabled(params.cfg)) { return {
shouldContinue: false,
reply: {
text: "⚠️ /restart is disabled (commands.restart=false).",
},
};
} const hasSigusr1Listener = process.listenerCount("SIGUSR1") > 0; const sentinelPayload = buildRestartCommandSentinel(params); if (hasSigusr1Listener) {
let sentinelPath: string | null = null;
scheduleGatewaySigusr1Restart({
reason: "/restart",
emitHooks: sentinelPayload
? {
beforeEmit: async () => {
sentinelPath = await writeRestartSentinel(sentinelPayload);
},
afterEmitRejected: async () => {
await removeRestartSentinelFile(sentinelPath);
},
}
: undefined,
}); return {
shouldContinue: false,
reply: {
text: "⚙️ Restarting OpenClaw in-process (SIGUSR1); back in a few seconds.",
},
};
}
let sentinelPath: string | null = null; try { if (sentinelPayload) {
sentinelPath = await writeRestartSentinel(sentinelPayload);
}
} catch (err) {
logVerbose(`failed to write /restart sentinel: ${String(err)}`); return {
shouldContinue: false,
reply: {
text: "⚠️ Restart failed: could not persist the post-restart acknowledgement.",
},
};
} const restartMethod = triggerOpenClawRestart(); if (!restartMethod.ok) {
await removeRestartSentinelFile(sentinelPath); const detail = restartMethod.detail ? ` Details: ${restartMethod.detail}` : ""; return {
shouldContinue: false,
reply: {
text: `⚠️ Restart failed (${restartMethod.method}).${detail}`,
},
};
} return {
shouldContinue: false,
reply: {
text: `⚙️ Restarting OpenClaw via ${restartMethod.method}; give me a few seconds to come back online.`,
},
};
};
export { handleAbortTrigger, handleStopCommand };
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.11Bemerkung:
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.