mlclaw 0.3.5 → 0.3.7

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/Dockerfile CHANGED
@@ -2,7 +2,7 @@ ARG OPENCLAW_VERSION=2026.7.1
2
2
  ARG OPENCLAW_BASE_IMAGE=ghcr.io/openclaw/openclaw:${OPENCLAW_VERSION}
3
3
  ARG BROKERKIT_PLUGIN_VERSION=0.2.1
4
4
  ARG BROKERKIT_VERSION=hf-broker/v0.1.0
5
- ARG MLCLAW_RUNTIME_IMAGE=ghcr.io/osolmaz/mlclaw:0.3.5-openclaw-2026.7.1
5
+ ARG MLCLAW_RUNTIME_IMAGE=ghcr.io/osolmaz/mlclaw:0.3.7-openclaw-2026.7.1
6
6
 
7
7
  FROM golang:1.26.5-bookworm AS hf-broker-build
8
8
  ARG BROKERKIT_VERSION
package/README.md CHANGED
@@ -40,8 +40,12 @@ irm https://raw.githubusercontent.com/osolmaz/mlclaw/main/mlclaw.ps1 | iex
40
40
  ```
41
41
 
42
42
  You need a Hugging Face account and a token available through `HF_TOKEN`,
43
- `HF_TOKEN_PATH`, `$HF_HOME/token`, or `hf auth login`. You never paste that
44
- token into someone else's app; the bootstrapper runs locally.
43
+ `HF_TOKEN_PATH`, `$HF_HOME/token`, or `hf auth login`. If an interactive
44
+ bootstrap cannot find a token, it offers to install the official Hugging Face
45
+ CLI, asks whether you need to create an account, opens the appropriate browser
46
+ flow, and resumes after sign-in. Non-interactive runs never install software and
47
+ still require a token up front. You never paste that token into someone else's
48
+ app; the bootstrapper runs locally.
45
49
 
46
50
  ML Claw places the active Hugging Face token behind an in-container HF Broker.
47
51
  The broker owns the real token; OpenClaw receives only a separate agent
@@ -86,12 +90,13 @@ Choose a Hugging Face Router model with `--model`:
86
90
  ```bash
87
91
  npx mlclaw@latest bootstrap \
88
92
  --name mlclaw \
89
- --model huggingface/google/gemma-4-26B-A4B-it:deepinfra
93
+ --model huggingface/zai-org/GLM-5.2:fireworks-ai
90
94
  ```
91
95
 
92
96
  Recommended router-compatible options:
93
97
 
94
- - `huggingface/google/gemma-4-26B-A4B-it:deepinfra`: default quality target.
98
+ - `huggingface/zai-org/GLM-5.2:fireworks-ai`: default long-context model with tool support.
99
+ - `huggingface/google/gemma-4-26B-A4B-it:deepinfra`: lower-cost Gemma option with tool and structured-output support.
95
100
  - `huggingface/Qwen/Qwen3.6-35B-A3B:deepinfra`: strong Qwen 3.6 option with tool and structured-output support.
96
101
  - `huggingface/Qwen/Qwen3.6-27B:deepinfra`: live Qwen 3.6 option with tool and structured-output support.
97
102
  - `huggingface/zai-org/GLM-5.2:deepinfra`: long-context GLM option with tool and structured-output support.
@@ -102,10 +107,10 @@ Recommended router-compatible options:
102
107
  - `huggingface/deepseek-ai/DeepSeek-V4-Pro:deepinfra`: higher-quality long-context DeepSeek V4 option.
103
108
  - `huggingface/MiniMaxAI/MiniMax-M3:together`: long-context MiniMax option with tool and structured-output support.
104
109
 
105
- Fireworks alternatives are also included for GLM 5.2, Kimi K2.7 Code,
106
- GPT-OSS 120B and 20B, DeepSeek V4 Flash and Pro, and MiniMax M3. Use the
107
- provider suffix `:fireworks-ai`. The current Router catalog does not expose the
108
- Gemma 4 or Qwen 3.6 presets through Fireworks.
110
+ Fireworks options are also included for Kimi K2.7 Code, GPT-OSS 120B and 20B,
111
+ DeepSeek V4 Flash and Pro, and MiniMax M3. Use the provider suffix
112
+ `:fireworks-ai`. The current Router catalog does not expose the Gemma 4 or Qwen
113
+ 3.6 presets through Fireworks.
109
114
 
110
115
  ## Optional Telegram
111
116
 
@@ -210,9 +215,9 @@ merges every BrokerKit-compatible backend configured in
210
215
  cancel, or revoke requests. The plugin registers the Gateway tab, while ML Claw
211
216
  serves the immutable packaged UI from its trusted HTTP boundary and gives it a
212
217
  small popover inside the Gateway. Administrators decide requests directly in
213
- the sandboxed popover when `MLCLAW_BROKERKIT_POPOVER_DECISIONS=true`; otherwise
214
- the popover remains read-only and decisions use the standalone protected page.
215
- Both flows use a renewable, short-lived, admin-bound browser token.
218
+ the sandboxed popover by default. Set
219
+ `MLCLAW_BROKERKIT_POPOVER_DECISIONS=false` only to make the popover read-only.
220
+ The popover uses a renewable, short-lived, admin-bound browser token.
216
221
  Broker operator tokens remain in backend-only files and are never sent to the
217
222
  browser or OpenClaw. See
218
223
  [Operator Broker Configuration](docs/operator-brokers-config.md).
@@ -129,16 +129,19 @@ function normalizeAssetRef(value, fallback) {
129
129
  return normalized;
130
130
  }
131
131
 
132
+ // src/mlclaw-space-runtime/model-default.ts
133
+ var DEFAULT_MODEL_ID = "zai-org/GLM-5.2";
134
+ var DEFAULT_MODEL_PROVIDER = "fireworks-ai";
135
+ var DEFAULT_MODEL = `huggingface/${DEFAULT_MODEL_ID}:${DEFAULT_MODEL_PROVIDER}`;
136
+
132
137
  // src/mlclaw-space-runtime/model-choices.ts
133
138
  var DEFAULT_ROUTER_PROVIDER = "deepinfra";
134
- var DEFAULT_ROUTER_MODEL_ID = "google/gemma-4-26B-A4B-it";
135
- var DEFAULT_MODEL = formatOpenClawModelRef(DEFAULT_ROUTER_MODEL_ID, DEFAULT_ROUTER_PROVIDER);
136
139
  var PRESET_MODEL_CHOICES = [
137
140
  freezeChoice({
138
141
  modelId: "google/gemma-4-26B-A4B-it",
139
142
  provider: "deepinfra",
140
143
  label: "Gemma 4 26B A4B",
141
- note: "Default quality target on DeepInfra",
144
+ note: "Low-cost Gemma preset on DeepInfra",
142
145
  contextLength: 262144,
143
146
  pricing: { input: 0.07, output: 0.34 },
144
147
  supportsTools: true,
@@ -298,7 +301,7 @@ var PRESET_MODEL_CHOICES = [
298
301
  modelId: "zai-org/GLM-5.2",
299
302
  provider: "fireworks-ai",
300
303
  label: "GLM 5.2",
301
- note: "Long-context GLM alternative on Fireworks",
304
+ note: "Default long-context GLM preset on Fireworks",
302
305
  contextLength: 1048576,
303
306
  pricing: { input: 1.4, output: 4.4 },
304
307
  supportsTools: true,
@@ -5106,7 +5109,7 @@ function loadConfig(env = process.env) {
5106
5109
  brokerAgentSecret: readOptionalSecret(trim(env.MLCLAW_HF_BROKER_AGENT_SECRET_FILE)),
5107
5110
  brokerAgentSecretFile: trim(env.MLCLAW_HF_BROKER_AGENT_SECRET_FILE),
5108
5111
  operatorBrokers: loadOperatorBrokers(trim(env.MLCLAW_OPERATOR_BROKERS_FILE)),
5109
- brokerKitPopoverDecisions: env.MLCLAW_BROKERKIT_POPOVER_DECISIONS === "1" || env.MLCLAW_BROKERKIT_POPOVER_DECISIONS === "true",
5112
+ brokerKitPopoverDecisions: env.MLCLAW_BROKERKIT_POPOVER_DECISIONS !== "0" && env.MLCLAW_BROKERKIT_POPOVER_DECISIONS !== "false",
5110
5113
  hubUrl: trim(env.HF_ENDPOINT) ?? "https://huggingface.co",
5111
5114
  openaiCredentialFile: trim(env.MLCLAW_OPENAI_CREDENTIAL_FILE) ?? "/tmp/mlclaw-secrets/openai.env",
5112
5115
  openaiCredentialStoreFile,
package/dist/mlclaw.mjs CHANGED
@@ -1202,8 +1202,8 @@ var require_command = __commonJS({
1202
1202
  "node_modules/commander/lib/command.js"(exports) {
1203
1203
  var EventEmitter = __require("node:events").EventEmitter;
1204
1204
  var childProcess = __require("node:child_process");
1205
- var path15 = __require("node:path");
1206
- var fs15 = __require("node:fs");
1205
+ var path16 = __require("node:path");
1206
+ var fs16 = __require("node:fs");
1207
1207
  var process5 = __require("node:process");
1208
1208
  var { Argument: Argument2, humanReadableArgName } = require_argument();
1209
1209
  var { CommanderError: CommanderError2 } = require_error();
@@ -2197,7 +2197,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2197
2197
  * @param {string} subcommandName
2198
2198
  */
2199
2199
  _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
2200
- if (fs15.existsSync(executableFile)) return;
2200
+ if (fs16.existsSync(executableFile)) return;
2201
2201
  const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
2202
2202
  const executableMissing = `'${executableFile}' does not exist
2203
2203
  - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
@@ -2215,11 +2215,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
2215
2215
  let launchWithNode = false;
2216
2216
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2217
2217
  function findFile(baseDir, baseName) {
2218
- const localBin = path15.resolve(baseDir, baseName);
2219
- if (fs15.existsSync(localBin)) return localBin;
2220
- if (sourceExt.includes(path15.extname(baseName))) return void 0;
2218
+ const localBin = path16.resolve(baseDir, baseName);
2219
+ if (fs16.existsSync(localBin)) return localBin;
2220
+ if (sourceExt.includes(path16.extname(baseName))) return void 0;
2221
2221
  const foundExt = sourceExt.find(
2222
- (ext) => fs15.existsSync(`${localBin}${ext}`)
2222
+ (ext) => fs16.existsSync(`${localBin}${ext}`)
2223
2223
  );
2224
2224
  if (foundExt) return `${localBin}${foundExt}`;
2225
2225
  return void 0;
@@ -2231,21 +2231,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
2231
2231
  if (this._scriptPath) {
2232
2232
  let resolvedScriptPath;
2233
2233
  try {
2234
- resolvedScriptPath = fs15.realpathSync(this._scriptPath);
2234
+ resolvedScriptPath = fs16.realpathSync(this._scriptPath);
2235
2235
  } catch {
2236
2236
  resolvedScriptPath = this._scriptPath;
2237
2237
  }
2238
- executableDir = path15.resolve(
2239
- path15.dirname(resolvedScriptPath),
2238
+ executableDir = path16.resolve(
2239
+ path16.dirname(resolvedScriptPath),
2240
2240
  executableDir
2241
2241
  );
2242
2242
  }
2243
2243
  if (executableDir) {
2244
2244
  let localFile = findFile(executableDir, executableFile);
2245
2245
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2246
- const legacyName = path15.basename(
2246
+ const legacyName = path16.basename(
2247
2247
  this._scriptPath,
2248
- path15.extname(this._scriptPath)
2248
+ path16.extname(this._scriptPath)
2249
2249
  );
2250
2250
  if (legacyName !== this._name) {
2251
2251
  localFile = findFile(
@@ -2256,7 +2256,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2256
2256
  }
2257
2257
  executableFile = localFile || executableFile;
2258
2258
  }
2259
- launchWithNode = sourceExt.includes(path15.extname(executableFile));
2259
+ launchWithNode = sourceExt.includes(path16.extname(executableFile));
2260
2260
  let proc;
2261
2261
  if (process5.platform !== "win32") {
2262
2262
  if (launchWithNode) {
@@ -3171,7 +3171,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3171
3171
  * @return {Command}
3172
3172
  */
3173
3173
  nameFromFilename(filename) {
3174
- this._name = path15.basename(filename, path15.extname(filename));
3174
+ this._name = path16.basename(filename, path16.extname(filename));
3175
3175
  return this;
3176
3176
  }
3177
3177
  /**
@@ -3185,9 +3185,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3185
3185
  * @param {string} [path]
3186
3186
  * @return {(string|null|Command)}
3187
3187
  */
3188
- executableDir(path16) {
3189
- if (path16 === void 0) return this._executableDir;
3190
- this._executableDir = path16;
3188
+ executableDir(path17) {
3189
+ if (path17 === void 0) return this._executableDir;
3190
+ this._executableDir = path17;
3191
3191
  return this;
3192
3192
  }
3193
3193
  /**
@@ -8952,7 +8952,7 @@ var init_cli = __esm({
8952
8952
  });
8953
8953
 
8954
8954
  // src/mlclaw/cli.ts
8955
- import fs14 from "node:fs/promises";
8955
+ import fs15 from "node:fs/promises";
8956
8956
  import { realpathSync } from "node:fs";
8957
8957
  import process4 from "node:process";
8958
8958
  import { randomBytes } from "node:crypto";
@@ -9587,9 +9587,103 @@ async function handleSkillflag(argv, opts) {
9587
9587
  }
9588
9588
 
9589
9589
  // src/mlclaw/auth.ts
9590
- import fs10 from "node:fs/promises";
9590
+ import fs11 from "node:fs/promises";
9591
+ import os4 from "node:os";
9592
+ import path12 from "node:path";
9593
+
9594
+ // src/mlclaw/hf-cli.ts
9595
+ import { spawn } from "node:child_process";
9596
+ import fs10, { constants as fsConstants } from "node:fs/promises";
9591
9597
  import os3 from "node:os";
9592
9598
  import path11 from "node:path";
9599
+ var HF_CLI_INSTALL_URL = "https://hf.co/cli/install.sh";
9600
+ var HF_ACCOUNT_CREATE_URL = "https://huggingface.co/join";
9601
+ var HF_CLI_INSTALL_COMMAND = `curl -LsSf ${HF_CLI_INSTALL_URL} | bash`;
9602
+ function createSystemHfCli(env = process.env) {
9603
+ return {
9604
+ findExecutable: async () => await findHfExecutable(env),
9605
+ install: async () => await installHfCli(env),
9606
+ login: async (executable) => await runInherited(executable, ["auth", "login"], env),
9607
+ openUrl: async (url) => await openUrl(url, env)
9608
+ };
9609
+ }
9610
+ async function findHfExecutable(env) {
9611
+ const fromPath = await hfCommandPath(env);
9612
+ if (fromPath) {
9613
+ return fromPath;
9614
+ }
9615
+ const home = env.HOME || os3.homedir();
9616
+ const candidates = [
9617
+ env.HF_CLI_BIN_DIR && path11.join(env.HF_CLI_BIN_DIR, "hf"),
9618
+ path11.join(home, ".local", "bin", "hf")
9619
+ ].filter((candidate) => Boolean(candidate));
9620
+ for (const candidate of candidates) {
9621
+ try {
9622
+ await fs10.access(candidate, fsConstants.X_OK);
9623
+ return candidate;
9624
+ } catch {
9625
+ }
9626
+ }
9627
+ return void 0;
9628
+ }
9629
+ async function hfCommandPath(env) {
9630
+ return await new Promise((resolve) => {
9631
+ const child = spawn("sh", ["-c", "command -v hf"], {
9632
+ env,
9633
+ stdio: ["ignore", "pipe", "ignore"]
9634
+ });
9635
+ let output = "";
9636
+ child.stdout?.setEncoding("utf8");
9637
+ child.stdout?.on("data", (chunk) => {
9638
+ output += chunk;
9639
+ });
9640
+ child.once("error", () => resolve(void 0));
9641
+ child.once("close", (code) => resolve(code === 0 ? output.trim() || void 0 : void 0));
9642
+ });
9643
+ }
9644
+ async function installHfCli(env) {
9645
+ if (process.platform !== "darwin" && process.platform !== "linux") {
9646
+ throw new Error(`automatic Hugging Face CLI installation is not supported on ${process.platform}`);
9647
+ }
9648
+ const response = await fetch(HF_CLI_INSTALL_URL, { redirect: "follow" });
9649
+ if (!response.ok) {
9650
+ throw new Error(`failed to download the Hugging Face CLI installer: HTTP ${response.status}`);
9651
+ }
9652
+ const temporaryDirectory = await fs10.mkdtemp(path11.join(os3.tmpdir(), "mlclaw-hf-cli-"));
9653
+ const installerPath = path11.join(temporaryDirectory, "install.sh");
9654
+ try {
9655
+ await fs10.writeFile(installerPath, await response.text(), { mode: 448 });
9656
+ await runInherited("bash", [installerPath], env);
9657
+ } finally {
9658
+ await fs10.rm(temporaryDirectory, { recursive: true, force: true });
9659
+ }
9660
+ }
9661
+ async function runInherited(command, args, env) {
9662
+ await new Promise((resolve, reject) => {
9663
+ const child = spawn(command, args, { env, stdio: "inherit" });
9664
+ child.once("error", reject);
9665
+ child.once("close", (code, signal) => {
9666
+ if (code === 0) {
9667
+ resolve();
9668
+ return;
9669
+ }
9670
+ reject(new Error(`${command} exited ${signal ? `after signal ${signal}` : `with status ${code ?? "unknown"}`}`));
9671
+ });
9672
+ });
9673
+ }
9674
+ async function openUrl(url, env) {
9675
+ const command = process.platform === "darwin" ? "open" : process.platform === "linux" ? "xdg-open" : void 0;
9676
+ if (!command) {
9677
+ return false;
9678
+ }
9679
+ return await new Promise((resolve) => {
9680
+ const child = spawn(command, [url], { env, stdio: "ignore" });
9681
+ child.once("error", () => resolve(false));
9682
+ child.once("close", (code) => resolve(code === 0));
9683
+ });
9684
+ }
9685
+
9686
+ // src/mlclaw/auth.ts
9593
9687
  async function readToken(env = process.env) {
9594
9688
  const fromEnv = env.HF_TOKEN?.trim();
9595
9689
  if (fromEnv) {
@@ -9597,13 +9691,13 @@ async function readToken(env = process.env) {
9597
9691
  }
9598
9692
  const candidates = [
9599
9693
  env.HF_TOKEN_PATH,
9600
- env.HF_HOME && path11.join(env.HF_HOME, "token"),
9601
- path11.join(os3.homedir(), ".cache", "huggingface", "token"),
9602
- path11.join(os3.homedir(), ".huggingface", "token")
9694
+ env.HF_HOME && path12.join(env.HF_HOME, "token"),
9695
+ path12.join(os4.homedir(), ".cache", "huggingface", "token"),
9696
+ path12.join(os4.homedir(), ".huggingface", "token")
9603
9697
  ].filter((value) => Boolean(value));
9604
9698
  for (const candidate of candidates) {
9605
9699
  try {
9606
- const token = (await fs10.readFile(candidate, "utf8")).trim();
9700
+ const token = (await fs11.readFile(candidate, "utf8")).trim();
9607
9701
  if (token) {
9608
9702
  return token;
9609
9703
  }
@@ -9612,6 +9706,62 @@ async function readToken(env = process.env) {
9612
9706
  }
9613
9707
  throw new Error("HF token not found. Set HF_TOKEN or run `hf auth login` once.");
9614
9708
  }
9709
+ async function ensureHfToken(params) {
9710
+ let missingTokenError;
9711
+ try {
9712
+ return await params.readToken();
9713
+ } catch (error) {
9714
+ missingTokenError = error;
9715
+ }
9716
+ if (!params.prompt.isInteractive()) {
9717
+ throw missingTokenError;
9718
+ }
9719
+ let executable = await params.hfCli.findExecutable();
9720
+ if (!executable) {
9721
+ params.prompt.note(
9722
+ `ML Claw uses the official Hugging Face CLI to sign you in.
9723
+
9724
+ Manual install command:
9725
+ ${HF_CLI_INSTALL_COMMAND}`,
9726
+ "Hugging Face CLI required"
9727
+ );
9728
+ const install = await params.prompt.confirm("Install the Hugging Face CLI now?", true);
9729
+ if (!install) {
9730
+ throw new Error(`Hugging Face CLI installation was declined. Install it with: ${HF_CLI_INSTALL_COMMAND}`);
9731
+ }
9732
+ await params.hfCli.install();
9733
+ executable = await params.hfCli.findExecutable();
9734
+ if (!executable) {
9735
+ throw new Error(
9736
+ `Hugging Face CLI was installed but could not be found. Open a new terminal or run: ${HF_CLI_INSTALL_COMMAND}`
9737
+ );
9738
+ }
9739
+ }
9740
+ const hasAccount = await params.prompt.confirm("Do you already have a Hugging Face account?", true);
9741
+ if (!hasAccount) {
9742
+ const opened = await params.hfCli.openUrl(HF_ACCOUNT_CREATE_URL);
9743
+ params.prompt.note(
9744
+ `${opened ? "A browser was opened for account creation." : "Create your account in a browser."}
9745
+
9746
+ ${HF_ACCOUNT_CREATE_URL}`,
9747
+ "Create a Hugging Face account"
9748
+ );
9749
+ const accountCreated = await params.prompt.confirm("Have you created your Hugging Face account?", false);
9750
+ if (!accountCreated) {
9751
+ throw new Error(`Create a Hugging Face account at ${HF_ACCOUNT_CREATE_URL}, then run ML Claw again`);
9752
+ }
9753
+ }
9754
+ params.prompt.note(
9755
+ "Complete Hugging Face sign-in in the browser. ML Claw will resume automatically afterward.",
9756
+ "Hugging Face sign-in"
9757
+ );
9758
+ await params.hfCli.login(executable);
9759
+ try {
9760
+ return await params.readToken();
9761
+ } catch {
9762
+ throw new Error("Hugging Face sign-in completed, but no local token was found. Run `hf auth login` and try again.");
9763
+ }
9764
+ }
9615
9765
 
9616
9766
  // src/mlclaw/docker.ts
9617
9767
  import { execFile } from "node:child_process";
@@ -9756,9 +9906,9 @@ function parseGatewayLocation(value) {
9756
9906
 
9757
9907
  // src/mlclaw/git.ts
9758
9908
  import { execFile as execFile2 } from "node:child_process";
9759
- import fs12 from "node:fs/promises";
9760
- import os4 from "node:os";
9761
- import path13 from "node:path";
9909
+ import fs13 from "node:fs/promises";
9910
+ import os5 from "node:os";
9911
+ import path14 from "node:path";
9762
9912
  import { fileURLToPath as fileURLToPath3 } from "node:url";
9763
9913
  import { promisify as promisify2 } from "node:util";
9764
9914
 
@@ -13582,10 +13732,10 @@ var CurrentXorbInfo = class {
13582
13732
  hash: computeXorbHash(xorbChunksCleaned),
13583
13733
  chunks: xorbChunksCleaned,
13584
13734
  id: this.id,
13585
- files: Object.entries(this.fileProcessedBytes).map(([path15, processedBytes]) => ({
13586
- path: path15,
13587
- progress: processedBytes / this.fileSize[path15],
13588
- lastSentProgress: ((this.fileUploadedBytes[path15] ?? 0) + (processedBytes - (this.fileUploadedBytes[path15] ?? 0)) * PROCESSING_PROGRESS_RATIO) / this.fileSize[path15]
13735
+ files: Object.entries(this.fileProcessedBytes).map(([path16, processedBytes]) => ({
13736
+ path: path16,
13737
+ progress: processedBytes / this.fileSize[path16],
13738
+ lastSentProgress: ((this.fileUploadedBytes[path16] ?? 0) + (processedBytes - (this.fileUploadedBytes[path16] ?? 0)) * PROCESSING_PROGRESS_RATIO) / this.fileSize[path16]
13589
13739
  }))
13590
13740
  };
13591
13741
  }
@@ -14458,7 +14608,7 @@ var BucketClient = class {
14458
14608
  if (paths.length === 0) {
14459
14609
  return;
14460
14610
  }
14461
- await this.batch(paths.map((path15) => ({ type: "deleteFile", path: path15 })));
14611
+ await this.batch(paths.map((path16) => ({ type: "deleteFile", path: path16 })));
14462
14612
  }
14463
14613
  async batch(operations) {
14464
14614
  const body = `${operations.map((op) => JSON.stringify(op)).join("\n")}
@@ -14474,8 +14624,8 @@ var BucketClient = class {
14474
14624
  * any other failure (including bucket/auth errors), so a missing object is
14475
14625
  * never conflated with an unreachable bucket.
14476
14626
  */
14477
- async downloadFile(path15) {
14478
- const url = `${this.hubUrl}/buckets/${this.bucket}/resolve/${encodeURIComponent(path15)}`;
14627
+ async downloadFile(path16) {
14628
+ const url = `${this.hubUrl}/buckets/${this.bucket}/resolve/${encodeURIComponent(path16)}`;
14479
14629
  const response = await this.fetchWithRetry(url);
14480
14630
  if (response.status === 404) {
14481
14631
  await this.assertBucketAccessible();
@@ -14759,9 +14909,9 @@ var HubApi = class {
14759
14909
  encoding: "base64"
14760
14910
  }
14761
14911
  })),
14762
- ...(params.deletePaths ?? []).map((path15) => ({
14912
+ ...(params.deletePaths ?? []).map((path16) => ({
14763
14913
  key: "deletedFile",
14764
- value: { path: path15 }
14914
+ value: { path: path16 }
14765
14915
  }))
14766
14916
  ].map((entry) => JSON.stringify(entry)).join("\n");
14767
14917
  await this.request(`/api/spaces/${repoId}/commit/${encodeURIComponent(params.branch ?? "main")}`, {
@@ -14833,8 +14983,8 @@ function sseDataToText(raw) {
14833
14983
  }
14834
14984
 
14835
14985
  // src/mlclaw/runtime-image.ts
14836
- import fs11 from "node:fs";
14837
- import path12 from "node:path";
14986
+ import fs12 from "node:fs";
14987
+ import path13 from "node:path";
14838
14988
  import { fileURLToPath as fileURLToPath2 } from "node:url";
14839
14989
  var DEFAULT_OPENCLAW_VERSION = "2026.7.1";
14840
14990
  var DEFAULT_BROKERKIT_PLUGIN_VERSION = "0.2.1";
@@ -14873,17 +15023,17 @@ function packageConfigString(key, fallback) {
14873
15023
  return typeof value === "string" && value.trim() ? value.trim() : fallback;
14874
15024
  }
14875
15025
  function readPackageMetadata() {
14876
- let dir = path12.dirname(fileURLToPath2(import.meta.url));
15026
+ let dir = path13.dirname(fileURLToPath2(import.meta.url));
14877
15027
  while (true) {
14878
- const candidate = path12.join(dir, "package.json");
15028
+ const candidate = path13.join(dir, "package.json");
14879
15029
  try {
14880
- return JSON.parse(fs11.readFileSync(candidate, "utf8"));
15030
+ return JSON.parse(fs12.readFileSync(candidate, "utf8"));
14881
15031
  } catch (err) {
14882
15032
  if (!isMissingFileError(err)) {
14883
15033
  throw err;
14884
15034
  }
14885
15035
  }
14886
- const parent = path12.dirname(dir);
15036
+ const parent = path13.dirname(dir);
14887
15037
  if (parent === dir) {
14888
15038
  throw new Error("could not find package.json while resolving default runtime image");
14889
15039
  }
@@ -14897,12 +15047,12 @@ function isMissingFileError(err) {
14897
15047
  // src/mlclaw/git.ts
14898
15048
  var execFileAsync2 = promisify2(execFile2);
14899
15049
  async function pushTemplateToSpace(params) {
14900
- const tempRoot = await fs12.mkdtemp(path13.join(os4.tmpdir(), "mlclaw-space-"));
15050
+ const tempRoot = await fs13.mkdtemp(path14.join(os5.tmpdir(), "mlclaw-space-"));
14901
15051
  try {
14902
15052
  const sourceDir = params.sourceDir ?? process.env.MLCLAW_SOURCE_DIR ?? await findPackagedSourceRoot();
14903
15053
  const templateRev = await currentTemplateRev(sourceDir);
14904
- const outDir = path13.join(tempRoot, "space");
14905
- await fs12.mkdir(outDir, { recursive: true });
15054
+ const outDir = path14.join(tempRoot, "space");
15055
+ await fs13.mkdir(outDir, { recursive: true });
14906
15056
  await generateSpaceRepo(sourceDir, outDir, {
14907
15057
  ...params.runtimeImage ? { runtimeImage: params.runtimeImage } : {}
14908
15058
  });
@@ -14920,7 +15070,7 @@ async function pushTemplateToSpace(params) {
14920
15070
  });
14921
15071
  return { templateRev };
14922
15072
  } finally {
14923
- await fs12.rm(tempRoot, { recursive: true, force: true });
15073
+ await fs13.rm(tempRoot, { recursive: true, force: true });
14924
15074
  }
14925
15075
  }
14926
15076
  async function currentTemplateRev(sourceDir) {
@@ -14933,7 +15083,7 @@ async function currentTemplateRev(sourceDir) {
14933
15083
  }
14934
15084
  } catch {
14935
15085
  }
14936
- const pkg = JSON.parse(await fs12.readFile(path13.join(sourceDir, "package.json"), "utf8"));
15086
+ const pkg = JSON.parse(await fs13.readFile(path14.join(sourceDir, "package.json"), "utf8"));
14937
15087
  return `npm:${pkg.name ?? "mlclaw"}@${pkg.version ?? "unknown"}`;
14938
15088
  }
14939
15089
  async function generateSpaceRepo(sourceDir, outDir, options = {}) {
@@ -14959,13 +15109,13 @@ async function generateSpaceRepo(sourceDir, outDir, options = {}) {
14959
15109
  );
14960
15110
  }
14961
15111
  for (const [from, to] of copies) {
14962
- await copyExisting(path13.join(sourceDir, from), path13.join(outDir, to));
15112
+ await copyExisting(path14.join(sourceDir, from), path14.join(outDir, to));
14963
15113
  }
14964
- const hfLogoPng = await fs12.readFile(path13.join(sourceDir, "assets/hf-logo.png"));
14965
- await fs12.writeFile(path13.join(outDir, "assets/hf-logo.png.base64"), `${hfLogoPng.toString("base64")}
15114
+ const hfLogoPng = await fs13.readFile(path14.join(sourceDir, "assets/hf-logo.png"));
15115
+ await fs13.writeFile(path14.join(outDir, "assets/hf-logo.png.base64"), `${hfLogoPng.toString("base64")}
14966
15116
  `, "utf8");
14967
- await fs12.writeFile(
14968
- path13.join(outDir, "Dockerfile"),
15117
+ await fs13.writeFile(
15118
+ path14.join(outDir, "Dockerfile"),
14969
15119
  options.runtimeImage ? imageDockerfile(options.runtimeImage) : bundledDockerfile(),
14970
15120
  "utf8"
14971
15121
  );
@@ -15053,13 +15203,13 @@ CMD ["/app/entrypoint.sh"]
15053
15203
  `;
15054
15204
  }
15055
15205
  async function findPackagedSourceRoot() {
15056
- const start = path13.dirname(fileURLToPath3(import.meta.url));
15206
+ const start = path14.dirname(fileURLToPath3(import.meta.url));
15057
15207
  let dir = start;
15058
15208
  while (true) {
15059
15209
  if (await hasPackagedSourceFiles(dir)) {
15060
15210
  return dir;
15061
15211
  }
15062
- const parent = path13.dirname(dir);
15212
+ const parent = path14.dirname(dir);
15063
15213
  if (parent === dir) {
15064
15214
  throw new Error("Could not find packaged ML Claw source files. Reinstall the mlclaw npm package.");
15065
15215
  }
@@ -15076,20 +15226,20 @@ async function hasPackagedSourceFiles(dir) {
15076
15226
  "src/hf-bucket-client/client.ts"
15077
15227
  ];
15078
15228
  try {
15079
- await Promise.all(required.map((file) => fs12.access(path13.join(dir, file))));
15229
+ await Promise.all(required.map((file) => fs13.access(path14.join(dir, file))));
15080
15230
  return true;
15081
15231
  } catch {
15082
15232
  return false;
15083
15233
  }
15084
15234
  }
15085
15235
  async function copyExisting(from, to) {
15086
- const stat = await fs12.stat(from);
15087
- await fs12.mkdir(path13.dirname(to), { recursive: true });
15236
+ const stat = await fs13.stat(from);
15237
+ await fs13.mkdir(path14.dirname(to), { recursive: true });
15088
15238
  if (stat.isDirectory()) {
15089
- await fs12.cp(from, to, { recursive: true });
15239
+ await fs13.cp(from, to, { recursive: true });
15090
15240
  } else {
15091
- await fs12.copyFile(from, to);
15092
- await fs12.chmod(to, stat.mode);
15241
+ await fs13.copyFile(from, to);
15242
+ await fs13.chmod(to, stat.mode);
15093
15243
  }
15094
15244
  }
15095
15245
  async function readFilesForCommit(root) {
@@ -15097,24 +15247,24 @@ async function readFilesForCommit(root) {
15097
15247
  for (const relativePath of await listFiles(root)) {
15098
15248
  files.push({
15099
15249
  path: relativePath,
15100
- content: await fs12.readFile(path13.join(root, relativePath))
15250
+ content: await fs13.readFile(path14.join(root, relativePath))
15101
15251
  });
15102
15252
  }
15103
15253
  return files;
15104
15254
  }
15105
15255
  async function listFiles(root, dir = "") {
15106
- const absoluteDir = path13.join(root, dir);
15107
- const entries = await fs12.readdir(absoluteDir, { withFileTypes: true });
15256
+ const absoluteDir = path14.join(root, dir);
15257
+ const entries = await fs13.readdir(absoluteDir, { withFileTypes: true });
15108
15258
  const files = [];
15109
15259
  for (const entry of entries) {
15110
- const relativePath = path13.posix.join(dir.split(path13.sep).join(path13.posix.sep), entry.name);
15111
- const absolutePath = path13.join(root, relativePath);
15260
+ const relativePath = path14.posix.join(dir.split(path14.sep).join(path14.posix.sep), entry.name);
15261
+ const absolutePath = path14.join(root, relativePath);
15112
15262
  if (entry.isDirectory()) {
15113
15263
  files.push(...await listFiles(root, relativePath));
15114
15264
  } else if (entry.isFile()) {
15115
15265
  files.push(relativePath);
15116
15266
  } else {
15117
- const stat = await fs12.stat(absolutePath);
15267
+ const stat = await fs13.stat(absolutePath);
15118
15268
  if (stat.isFile()) {
15119
15269
  files.push(relativePath);
15120
15270
  }
@@ -15180,10 +15330,15 @@ async function assertNoLiveForeignLease(params) {
15180
15330
  );
15181
15331
  }
15182
15332
 
15333
+ // src/mlclaw-space-runtime/model-default.ts
15334
+ var DEFAULT_MODEL_ID = "zai-org/GLM-5.2";
15335
+ var DEFAULT_MODEL_PROVIDER = "fireworks-ai";
15336
+ var DEFAULT_MODEL = `huggingface/${DEFAULT_MODEL_ID}:${DEFAULT_MODEL_PROVIDER}`;
15337
+
15183
15338
  // src/mlclaw/local-config.ts
15184
- import fs13 from "node:fs/promises";
15185
- import os5 from "node:os";
15186
- import path14 from "node:path";
15339
+ import fs14 from "node:fs/promises";
15340
+ import os6 from "node:os";
15341
+ import path15 from "node:path";
15187
15342
  function defaultConfigRoot(env = process.env) {
15188
15343
  const explicit = env.MLCLAW_CONFIG_HOME?.trim();
15189
15344
  if (explicit) {
@@ -15191,32 +15346,32 @@ function defaultConfigRoot(env = process.env) {
15191
15346
  }
15192
15347
  const xdg = env.XDG_CONFIG_HOME?.trim();
15193
15348
  if (xdg) {
15194
- return path14.join(xdg, "mlclaw");
15349
+ return path15.join(xdg, "mlclaw");
15195
15350
  }
15196
- return path14.join(os5.homedir(), ".config", "mlclaw");
15351
+ return path15.join(os6.homedir(), ".config", "mlclaw");
15197
15352
  }
15198
15353
  function localConfigPaths(root) {
15199
15354
  return {
15200
15355
  root,
15201
- deploymentsDir: path14.join(root, "deployments"),
15202
- secretsDir: path14.join(root, "secrets")
15356
+ deploymentsDir: path15.join(root, "deployments"),
15357
+ secretsDir: path15.join(root, "secrets")
15203
15358
  };
15204
15359
  }
15205
15360
  function manifestPath(root, agent) {
15206
- return path14.join(localConfigPaths(root).deploymentsDir, `${agent}.json`);
15361
+ return path15.join(localConfigPaths(root).deploymentsDir, `${agent}.json`);
15207
15362
  }
15208
15363
  function secretEnvPath(root, agent) {
15209
- return path14.join(localConfigPaths(root).secretsDir, `${agent}.env`);
15364
+ return path15.join(localConfigPaths(root).secretsDir, `${agent}.env`);
15210
15365
  }
15211
15366
  async function writeManifest(root, manifest) {
15212
15367
  const file = manifestPath(root, manifest.agent);
15213
- await fs13.mkdir(path14.dirname(file), { recursive: true });
15214
- await fs13.writeFile(file, `${JSON.stringify(manifest, null, 2)}
15368
+ await fs14.mkdir(path15.dirname(file), { recursive: true });
15369
+ await fs14.writeFile(file, `${JSON.stringify(manifest, null, 2)}
15215
15370
  `, "utf8");
15216
15371
  }
15217
15372
  async function readManifest(root, agent) {
15218
15373
  const file = manifestPath(root, agent);
15219
- const parsed = JSON.parse(await fs13.readFile(file, "utf8"));
15374
+ const parsed = JSON.parse(await fs14.readFile(file, "utf8"));
15220
15375
  if (parsed.version !== 1) {
15221
15376
  throw new Error(`unsupported deployment manifest version in ${file}`);
15222
15377
  }
@@ -15224,7 +15379,7 @@ async function readManifest(root, agent) {
15224
15379
  }
15225
15380
  async function manifestExists(root, agent) {
15226
15381
  try {
15227
- await fs13.access(manifestPath(root, agent));
15382
+ await fs14.access(manifestPath(root, agent));
15228
15383
  return true;
15229
15384
  } catch {
15230
15385
  return false;
@@ -15236,12 +15391,12 @@ function renderSecretEnv(values) {
15236
15391
  }
15237
15392
  async function writeSecretEnv(root, agent, values) {
15238
15393
  const file = secretEnvPath(root, agent);
15239
- await fs13.mkdir(path14.dirname(file), { recursive: true, mode: 448 });
15240
- await fs13.writeFile(file, renderSecretEnv(values), { encoding: "utf8", mode: 384 });
15241
- await fs13.chmod(file, 384);
15394
+ await fs14.mkdir(path15.dirname(file), { recursive: true, mode: 448 });
15395
+ await fs14.writeFile(file, renderSecretEnv(values), { encoding: "utf8", mode: 384 });
15396
+ await fs14.chmod(file, 384);
15242
15397
  }
15243
15398
  async function readSecretEnv(root, agent) {
15244
- return parseSecretEnv(await fs13.readFile(secretEnvPath(root, agent), "utf8"));
15399
+ return parseSecretEnv(await fs14.readFile(secretEnvPath(root, agent), "utf8"));
15245
15400
  }
15246
15401
  function parseSecretEnv(raw) {
15247
15402
  const out = {};
@@ -15319,7 +15474,7 @@ function delay(ms) {
15319
15474
  }
15320
15475
 
15321
15476
  // src/mlclaw/cli.ts
15322
- var DEFAULT_MODEL = "huggingface/google/gemma-4-26B-A4B-it:deepinfra";
15477
+ var DEFAULT_MODEL2 = DEFAULT_MODEL;
15323
15478
  var DEFAULT_HARDWARE = "cpu-basic";
15324
15479
  var TELEGRAM_HARDWARE = "cpu-upgrade";
15325
15480
  var TELEGRAM_SLEEP_TIME = -1;
@@ -15352,6 +15507,7 @@ function createRuntime(overrides = {}) {
15352
15507
  stdout: overrides.stdout ?? console,
15353
15508
  stderr: overrides.stderr ?? console,
15354
15509
  readToken: overrides.readToken ?? readToken,
15510
+ hfCli: overrides.hfCli ?? createSystemHfCli(overrides.env ?? process4.env),
15355
15511
  hubFactory: overrides.hubFactory ?? ((token) => new HubApi({ token })),
15356
15512
  pushTemplateToSpace: overrides.pushTemplateToSpace ?? pushTemplateToSpace,
15357
15513
  getTelegramBot: overrides.getTelegramBot ?? getTelegramBot,
@@ -15367,7 +15523,7 @@ function createProgram(runtimeOverrides = {}) {
15367
15523
  program2.name("mlclaw").description("Deploy OpenClaw to a Hugging Face Space and private bucket").showHelpAfterError().exitOverride((err) => {
15368
15524
  throw err;
15369
15525
  });
15370
- program2.command("bootstrap", { isDefault: true }).description("Create or update a Hugging Face OpenClaw deployment").option("--owner <owner>", "Hugging Face user or organization").option("--name <name>", "Agent and runtime resource base name").option("--bucket <owner/bucket>", "State bucket to create or adopt").option("--gateway <local|space>", "Where the live gateway runs").option("--telegram-token <token>", "Optional Telegram bot token").option("--telegram-token-file <path>", "File containing TELEGRAM_BOT_TOKEN=... or a raw token").option("--telegram-user-id <id>", "Allowed Telegram user ID").option("--telegram-api-root <url>", "Telegram API root override").option("--telegram-proxy <url>", "Telegram proxy URL override").option("--hardware <flavor>", "Hugging Face Space hardware flavor").option("--sleep-time <seconds>", "Space sleep timeout in seconds; -1 means never sleep", parseInteger).option("--model <model>", "OpenClaw model identifier", DEFAULT_MODEL).option("--runtime-image <image>", "ML Claw runtime image").option("--bundled-runtime", "Generate a bundled Space runtime instead of using the prebuilt ML Claw image", false).option("--public-space", "Create the Hugging Face Space as public instead of private", false).addOption(new Option("--gateway-token <token>").hideHelp()).option("--router-token <token>", "Hugging Face Router inference token for Space gateway model calls").option("--router-token-file <path>", "File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token").option("--docker-context <name>", "Docker context for local gateway mode").option("--no-pull", "Do not docker pull before starting a local gateway").option("--takeover", "Start even if a stale runtime lease is present", false).option("--yes", "Confirm paid hardware prompts for automation", false).action(async (opts) => {
15526
+ program2.command("bootstrap", { isDefault: true }).description("Create or update a Hugging Face OpenClaw deployment").option("--owner <owner>", "Hugging Face user or organization").option("--name <name>", "Agent and runtime resource base name").option("--bucket <owner/bucket>", "State bucket to create or adopt").option("--gateway <local|space>", "Where the live gateway runs").option("--telegram-token <token>", "Optional Telegram bot token").option("--telegram-token-file <path>", "File containing TELEGRAM_BOT_TOKEN=... or a raw token").option("--telegram-user-id <id>", "Allowed Telegram user ID").option("--telegram-api-root <url>", "Telegram API root override").option("--telegram-proxy <url>", "Telegram proxy URL override").option("--hardware <flavor>", "Hugging Face Space hardware flavor").option("--sleep-time <seconds>", "Space sleep timeout in seconds; -1 means never sleep", parseInteger).option("--model <model>", "OpenClaw model identifier", DEFAULT_MODEL2).option("--runtime-image <image>", "ML Claw runtime image").option("--bundled-runtime", "Generate a bundled Space runtime instead of using the prebuilt ML Claw image", false).option("--public-space", "Create the Hugging Face Space as public instead of private", false).addOption(new Option("--gateway-token <token>").hideHelp()).option("--router-token <token>", "Hugging Face Router inference token for Space gateway model calls").option("--router-token-file <path>", "File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token").option("--docker-context <name>", "Docker context for local gateway mode").option("--no-pull", "Do not docker pull before starting a local gateway").option("--takeover", "Start even if a stale runtime lease is present", false).option("--yes", "Confirm paid hardware prompts for automation", false).action(async (opts) => {
15371
15527
  await bootstrap(opts, runtime);
15372
15528
  });
15373
15529
  program2.command("update").description("Regenerate and upload current ML Claw Space files").argument("<owner/space>", "Hugging Face Space repo ID").option("--runtime-image <image>", "Runtime image to write into the generated Space Dockerfile").option("--bundled-runtime", "Generate a bundled Space runtime instead of using the prebuilt ML Claw image", false).option("--router-token <token>", "Dedicated Hugging Face Router inference token").option("--router-token-file <path>", "File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token").option("--force", "Update even if the Space does not look like ML Claw", false).action(async (repoId, opts) => {
@@ -15430,7 +15586,15 @@ async function main(argv = process4.argv.slice(2), runtimeOverrides = {}) {
15430
15586
  async function bootstrap(opts, runtime) {
15431
15587
  runtime.prompt.intro("ML Claw bootstrap");
15432
15588
  const requestedGatewayLocation = opts.gateway ? parseGatewayLocation(opts.gateway) : void 0;
15433
- const hfToken = await runtime.readToken(runtime.env);
15589
+ const hfToken = await ensureHfToken({
15590
+ readToken: async () => await runtime.readToken(runtime.env),
15591
+ hfCli: runtime.hfCli,
15592
+ prompt: {
15593
+ isInteractive: runtime.prompt.isInteractive,
15594
+ note: runtime.prompt.note,
15595
+ confirm: async (message, initialValue) => await promptConfirm(message, initialValue, runtime)
15596
+ }
15597
+ });
15434
15598
  const hub = runtime.hubFactory(hfToken);
15435
15599
  const me2 = await hub.whoami();
15436
15600
  const owner = opts.owner ?? me2.name;
@@ -15438,7 +15602,7 @@ async function bootstrap(opts, runtime) {
15438
15602
  const bot = telegramToken ? await runtime.getTelegramBot(telegramToken, opts.telegramApiRoot) : void 0;
15439
15603
  let agentName = slugifyAgentName(opts.name ?? bot?.username ?? await promptAgentName(runtime));
15440
15604
  const telegramUserId = telegramToken ? opts.telegramUserId ?? runtime.env.TELEGRAM_ALLOWED_USERS ?? await promptRequired("Telegram allowed user ID", runtime) : void 0;
15441
- const model = opts.model ?? DEFAULT_MODEL;
15605
+ const model = opts.model ?? DEFAULT_MODEL2;
15442
15606
  const runtimeImage = resolveRuntimeImage(opts.runtimeImage, runtime.env);
15443
15607
  const templateRuntimeImage = resolveSpaceRuntimeImage(opts, runtime.env);
15444
15608
  let plan;
@@ -16527,7 +16691,7 @@ async function update(repoId, opts, hub, hfToken, runtime) {
16527
16691
  await ensureUpdateRouterToken({
16528
16692
  repoId,
16529
16693
  agentName,
16530
- model: variables.get("OPENCLAW_MODEL")?.value ?? DEFAULT_MODEL,
16694
+ model: variables.get("OPENCLAW_MODEL")?.value ?? DEFAULT_MODEL2,
16531
16695
  opts,
16532
16696
  hub,
16533
16697
  runtime
@@ -16699,7 +16863,7 @@ async function doctor(repoId, opts, hub, runtime) {
16699
16863
  }
16700
16864
  const staleTokenSecrets = ["HF_TOKEN", "HUGGINGFACE_HUB_TOKEN"].filter((key) => secrets.has(key));
16701
16865
  if (staleTokenSecrets.length > 0) {
16702
- const model = variables.get("OPENCLAW_MODEL")?.value ?? DEFAULT_MODEL;
16866
+ const model = variables.get("OPENCLAW_MODEL")?.value ?? DEFAULT_MODEL2;
16703
16867
  const canDelete = canDeleteBroadTokenSecrets({
16704
16868
  model,
16705
16869
  routerTokenPresent: hasBrokerOrRouterTokenSecretMap(secrets)
@@ -16967,7 +17131,7 @@ async function readOptionalTelegramToken(opts, runtime) {
16967
17131
  return direct;
16968
17132
  }
16969
17133
  if (opts.telegramTokenFile) {
16970
- const raw = await fs14.readFile(opts.telegramTokenFile, "utf8");
17134
+ const raw = await fs15.readFile(opts.telegramTokenFile, "utf8");
16971
17135
  const match = raw.match(/(?:^|\n)\s*TELEGRAM_BOT_TOKEN\s*=\s*['"]?([^'"\n]+)['"]?/);
16972
17136
  return (match?.[1] ?? raw.trim()).trim();
16973
17137
  }
@@ -16989,7 +17153,7 @@ async function readOptionalRouterTokenFile(file) {
16989
17153
  if (!file) {
16990
17154
  return void 0;
16991
17155
  }
16992
- const raw = await fs14.readFile(file, "utf8");
17156
+ const raw = await fs15.readFile(file, "utf8");
16993
17157
  const parsed = parseSecretEnv(raw);
16994
17158
  return nonEmpty(parsed.MLCLAW_ROUTER_TOKEN) ?? nonEmpty(parsed.HF_ROUTER_TOKEN) ?? nonEmpty(raw);
16995
17159
  }
@@ -17105,7 +17269,7 @@ export {
17105
17269
  DEFAULT_GATEWAY_LOCATION,
17106
17270
  DEFAULT_HARDWARE,
17107
17271
  DEFAULT_LOCAL_PORT,
17108
- DEFAULT_MODEL,
17272
+ DEFAULT_MODEL2 as DEFAULT_MODEL,
17109
17273
  DEFAULT_SPACE_OPENCLAW_PORT,
17110
17274
  LOCAL_LIVE_DIR,
17111
17275
  LOCAL_VOLUME_MOUNT_PATH,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlclaw",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "license": "MIT",
5
5
  "config": {
6
6
  "openclawVersion": "2026.7.1",
@@ -55,8 +55,8 @@
55
55
  "pack:check": "node scripts/check-package.mjs",
56
56
  "prepack": "npm run build",
57
57
  "check:secrets": "node scripts/check-secrets.mjs",
58
- "format": "prettier --check eslint.config.mjs vitest.config.ts vitest.stryker.config.ts package.json README.md src/hf-state-sync/archive.ts src/hf-state-sync/cli.ts src/hf-state-sync/paths.ts src/hf-state-sync/prepare.ts src/hf-state-sync/stage-worker.ts src/hf-state-sync/supervise.ts src/mlclaw-space-runtime/delegated-brokerkit.ts src/mlclaw-space-runtime/delegated-revisions.ts src/mlclaw-space-runtime/operator-brokers.ts src/mlclaw-space-runtime/openclaw-config.ts src/mlclaw-space-runtime/app.ts src/mlclaw-space-runtime/config.ts src/mlclaw-space-runtime/openai-credentials.ts src/mlclaw-space-runtime/server.ts src/mlclaw-space-runtime/shell.ts src/mlclaw-control-ui/src/main.tsx src/mlclaw-control-ui/src/styles.css src/mlclaw-control-ui/src/components/ui/utils.ts src/mlclaw/git.ts test/hf-state-sync.archive.test.ts test/hf-state-sync.roundtrip.test.ts test/hf-state-sync.supervise.test.ts test/mlclaw.brokerkit-agent-tools.test.ts test/mlclaw.bundle.test.ts test/mlclaw.delegated-brokerkit.test.ts test/mlclaw.generate-space.test.ts test/mlclaw.operator-brokers.test.ts test/mlclaw.runtime-image.test.ts test/mlclaw.space-runtime.test.ts docs/operator-brokers-config.md",
59
- "format:write": "prettier --write eslint.config.mjs vitest.config.ts vitest.stryker.config.ts package.json README.md src/hf-state-sync/archive.ts src/hf-state-sync/cli.ts src/hf-state-sync/paths.ts src/hf-state-sync/prepare.ts src/hf-state-sync/stage-worker.ts src/hf-state-sync/supervise.ts src/mlclaw-space-runtime/delegated-brokerkit.ts src/mlclaw-space-runtime/delegated-revisions.ts src/mlclaw-space-runtime/operator-brokers.ts src/mlclaw-space-runtime/openclaw-config.ts src/mlclaw-space-runtime/app.ts src/mlclaw-space-runtime/config.ts src/mlclaw-space-runtime/openai-credentials.ts src/mlclaw-space-runtime/server.ts src/mlclaw-space-runtime/shell.ts src/mlclaw-control-ui/src/main.tsx src/mlclaw-control-ui/src/styles.css src/mlclaw-control-ui/src/components/ui/utils.ts src/mlclaw/git.ts test/hf-state-sync.archive.test.ts test/hf-state-sync.roundtrip.test.ts test/hf-state-sync.supervise.test.ts test/mlclaw.brokerkit-agent-tools.test.ts test/mlclaw.bundle.test.ts test/mlclaw.delegated-brokerkit.test.ts test/mlclaw.generate-space.test.ts test/mlclaw.operator-brokers.test.ts test/mlclaw.runtime-image.test.ts test/mlclaw.space-runtime.test.ts docs/operator-brokers-config.md",
58
+ "format": "prettier --check eslint.config.mjs vitest.config.ts vitest.stryker.config.ts package.json README.md src/hf-state-sync/archive.ts src/hf-state-sync/cli.ts src/hf-state-sync/paths.ts src/hf-state-sync/prepare.ts src/hf-state-sync/stage-worker.ts src/hf-state-sync/supervise.ts src/mlclaw/auth.ts src/mlclaw/hf-cli.ts src/mlclaw-space-runtime/delegated-brokerkit.ts src/mlclaw-space-runtime/delegated-revisions.ts src/mlclaw-space-runtime/operator-brokers.ts src/mlclaw-space-runtime/openclaw-config.ts src/mlclaw-space-runtime/app.ts src/mlclaw-space-runtime/config.ts src/mlclaw-space-runtime/openai-credentials.ts src/mlclaw-space-runtime/server.ts src/mlclaw-space-runtime/shell.ts src/mlclaw-control-ui/src/main.tsx src/mlclaw-control-ui/src/styles.css src/mlclaw-control-ui/src/components/ui/utils.ts src/mlclaw/git.ts test/hf-state-sync.archive.test.ts test/hf-state-sync.roundtrip.test.ts test/hf-state-sync.supervise.test.ts test/mlclaw.auth.test.ts test/mlclaw.brokerkit-agent-tools.test.ts test/mlclaw.bundle.test.ts test/mlclaw.delegated-brokerkit.test.ts test/mlclaw.generate-space.test.ts test/mlclaw.operator-brokers.test.ts test/mlclaw.runtime-image.test.ts test/mlclaw.space-runtime.test.ts docs/operator-brokers-config.md",
59
+ "format:write": "prettier --write eslint.config.mjs vitest.config.ts vitest.stryker.config.ts package.json README.md src/hf-state-sync/archive.ts src/hf-state-sync/cli.ts src/hf-state-sync/paths.ts src/hf-state-sync/prepare.ts src/hf-state-sync/stage-worker.ts src/hf-state-sync/supervise.ts src/mlclaw/auth.ts src/mlclaw/hf-cli.ts src/mlclaw-space-runtime/delegated-brokerkit.ts src/mlclaw-space-runtime/delegated-revisions.ts src/mlclaw-space-runtime/operator-brokers.ts src/mlclaw-space-runtime/openclaw-config.ts src/mlclaw-space-runtime/app.ts src/mlclaw-space-runtime/config.ts src/mlclaw-space-runtime/openai-credentials.ts src/mlclaw-space-runtime/server.ts src/mlclaw-space-runtime/shell.ts src/mlclaw-control-ui/src/main.tsx src/mlclaw-control-ui/src/styles.css src/mlclaw-control-ui/src/components/ui/utils.ts src/mlclaw/git.ts test/hf-state-sync.archive.test.ts test/hf-state-sync.roundtrip.test.ts test/hf-state-sync.supervise.test.ts test/mlclaw.auth.test.ts test/mlclaw.brokerkit-agent-tools.test.ts test/mlclaw.bundle.test.ts test/mlclaw.delegated-brokerkit.test.ts test/mlclaw.generate-space.test.ts test/mlclaw.operator-brokers.test.ts test/mlclaw.runtime-image.test.ts test/mlclaw.space-runtime.test.ts docs/operator-brokers-config.md",
60
60
  "lint": "eslint --max-warnings 0 src/mlclaw-space-runtime/delegated-brokerkit.ts src/mlclaw-space-runtime/delegated-revisions.ts src/mlclaw-space-runtime/operator-brokers.ts src/mlclaw-space-runtime/openclaw-config.ts",
61
61
  "coverage": "vitest run --coverage",
62
62
  "dry": "slophammer-ts dry .",