mlclaw 0.4.6 → 0.4.8

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/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 path17 = __require("node:path");
1206
- var fs17 = __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 (fs17.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 = path17.resolve(baseDir, baseName);
2219
- if (fs17.existsSync(localBin)) return localBin;
2220
- if (sourceExt.includes(path17.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) => fs17.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 = fs17.realpathSync(this._scriptPath);
2234
+ resolvedScriptPath = fs16.realpathSync(this._scriptPath);
2235
2235
  } catch {
2236
2236
  resolvedScriptPath = this._scriptPath;
2237
2237
  }
2238
- executableDir = path17.resolve(
2239
- path17.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 = path17.basename(
2246
+ const legacyName = path16.basename(
2247
2247
  this._scriptPath,
2248
- path17.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(path17.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 = path17.basename(filename, path17.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(path18) {
3189
- if (path18 === void 0) return this._executableDir;
3190
- this._executableDir = path18;
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 fs16 from "node:fs/promises";
8955
+ import fs15 from "node:fs/promises";
8956
8956
  import { realpathSync } from "node:fs";
8957
8957
  import os8 from "node:os";
8958
8958
  import process4 from "node:process";
@@ -10124,10 +10124,10 @@ function parseGatewayLocation(value) {
10124
10124
 
10125
10125
  // src/mlclaw/git.ts
10126
10126
  import { execFile as execFile2 } from "node:child_process";
10127
- import fs13 from "node:fs/promises";
10127
+ import fs12 from "node:fs/promises";
10128
10128
  import os5 from "node:os";
10129
- import path14 from "node:path";
10130
- import { fileURLToPath as fileURLToPath3 } from "node:url";
10129
+ import path13 from "node:path";
10130
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
10131
10131
  import { promisify as promisify2 } from "node:util";
10132
10132
 
10133
10133
  // src/vendor/hfjs-xet/error.ts
@@ -13950,10 +13950,10 @@ var CurrentXorbInfo = class {
13950
13950
  hash: computeXorbHash(xorbChunksCleaned),
13951
13951
  chunks: xorbChunksCleaned,
13952
13952
  id: this.id,
13953
- files: Object.entries(this.fileProcessedBytes).map(([path17, processedBytes]) => ({
13954
- path: path17,
13955
- progress: processedBytes / this.fileSize[path17],
13956
- lastSentProgress: ((this.fileUploadedBytes[path17] ?? 0) + (processedBytes - (this.fileUploadedBytes[path17] ?? 0)) * PROCESSING_PROGRESS_RATIO) / this.fileSize[path17]
13953
+ files: Object.entries(this.fileProcessedBytes).map(([path16, processedBytes]) => ({
13954
+ path: path16,
13955
+ progress: processedBytes / this.fileSize[path16],
13956
+ lastSentProgress: ((this.fileUploadedBytes[path16] ?? 0) + (processedBytes - (this.fileUploadedBytes[path16] ?? 0)) * PROCESSING_PROGRESS_RATIO) / this.fileSize[path16]
13957
13957
  }))
13958
13958
  };
13959
13959
  }
@@ -14826,7 +14826,7 @@ var BucketClient = class {
14826
14826
  if (paths.length === 0) {
14827
14827
  return;
14828
14828
  }
14829
- await this.batch(paths.map((path17) => ({ type: "deleteFile", path: path17 })));
14829
+ await this.batch(paths.map((path16) => ({ type: "deleteFile", path: path16 })));
14830
14830
  }
14831
14831
  async batch(operations) {
14832
14832
  const body = `${operations.map((op) => JSON.stringify(op)).join("\n")}
@@ -14842,8 +14842,8 @@ var BucketClient = class {
14842
14842
  * any other failure (including bucket/auth errors), so a missing object is
14843
14843
  * never conflated with an unreachable bucket.
14844
14844
  */
14845
- async downloadFile(path17) {
14846
- const url = `${this.hubUrl}/buckets/${this.bucket}/resolve/${encodeURIComponent(path17)}`;
14845
+ async downloadFile(path16) {
14846
+ const url = `${this.hubUrl}/buckets/${this.bucket}/resolve/${encodeURIComponent(path16)}`;
14847
14847
  const response = await this.fetchWithRetry(url);
14848
14848
  if (response.status === 404) {
14849
14849
  await this.assertBucketAccessible();
@@ -14945,19 +14945,19 @@ var HubApi = class {
14945
14945
  async deploymentControlStore(owner, deploymentId) {
14946
14946
  const repoId = `${owner}/mlclaw-control-${deploymentId.replaceAll("-", "")}`;
14947
14947
  await this.ensurePrivateModelRepo(repoId);
14948
- const path17 = "control-lease.json";
14948
+ const path16 = "control-lease.json";
14949
14949
  return {
14950
- read: async () => await this.readModelDocument(repoId, path17),
14951
- compareAndSwap: async (expectedRevision, value) => await this.commitModelDocument(repoId, path17, expectedRevision, value)
14950
+ read: async () => await this.readModelDocument(repoId, path16),
14951
+ compareAndSwap: async (expectedRevision, value) => await this.commitModelDocument(repoId, path16, expectedRevision, value)
14952
14952
  };
14953
14953
  }
14954
14954
  async deploymentClaimStore(owner) {
14955
14955
  const repoId = `${owner}/mlclaw-control-claims`;
14956
14956
  await this.ensurePrivateModelRepo(repoId);
14957
- const path17 = "control-lease.json";
14957
+ const path16 = "control-lease.json";
14958
14958
  return {
14959
- read: async () => await this.readModelDocument(repoId, path17),
14960
- compareAndSwap: async (expectedRevision, value) => await this.commitModelDocument(repoId, path17, expectedRevision, value)
14959
+ read: async () => await this.readModelDocument(repoId, path16),
14960
+ compareAndSwap: async (expectedRevision, value) => await this.commitModelDocument(repoId, path16, expectedRevision, value)
14961
14961
  };
14962
14962
  }
14963
14963
  async createDockerSpace(repoId, options) {
@@ -14968,7 +14968,7 @@ var HubApi = class {
14968
14968
  organization: owner === me2.name ? null : owner,
14969
14969
  type: "space",
14970
14970
  sdk: "docker",
14971
- private: options?.private !== false
14971
+ visibility: options?.visibility ?? "protected"
14972
14972
  };
14973
14973
  if (options?.hardware) {
14974
14974
  payload.hardware = options.hardware;
@@ -15001,8 +15001,19 @@ var HubApi = class {
15001
15001
  }
15002
15002
  }
15003
15003
  async getSpaceVisibility(repoId) {
15004
- const info = await this.requestJson(`/api/spaces/${repoId}`);
15005
- return info.private === true ? "private" : "public";
15004
+ const [owner] = splitRepoId(repoId);
15005
+ const me2 = await this.whoami();
15006
+ let url = owner === me2.name ? `${this.hubUrl}/api/settings/repositories` : `${this.hubUrl}/api/organizations/${encodeURIComponent(owner)}/settings/repositories`;
15007
+ while (url) {
15008
+ const response = await this.request(url);
15009
+ const repositories = await response.json();
15010
+ const visibility = repositories.find((repo) => repo.id === repoId && repo.type === "space")?.visibility;
15011
+ if (visibility === "private" || visibility === "protected" || visibility === "public") {
15012
+ return visibility;
15013
+ }
15014
+ url = nextLink(response.headers.get("link"));
15015
+ }
15016
+ throw new Error(`Hub repository settings omitted Space visibility for ${repoId}`);
15006
15017
  }
15007
15018
  async updateSpaceVisibility(repoId, visibility) {
15008
15019
  await this.requestJson(`/api/spaces/${repoId}/settings`, {
@@ -15174,9 +15185,9 @@ var HubApi = class {
15174
15185
  encoding: "base64"
15175
15186
  }
15176
15187
  })),
15177
- ...(params.deletePaths ?? []).map((path17) => ({
15188
+ ...(params.deletePaths ?? []).map((path16) => ({
15178
15189
  key: "deletedFile",
15179
- value: { path: path17 }
15190
+ value: { path: path16 }
15180
15191
  }))
15181
15192
  ].map((entry) => JSON.stringify(entry)).join("\n");
15182
15193
  await this.request(`/api/spaces/${repoId}/commit/${encodeURIComponent(params.branch ?? "main")}`, {
@@ -15206,10 +15217,10 @@ var HubApi = class {
15206
15217
  if (info.sha) return;
15207
15218
  await this.commitModelDocument(repoId, "README.md", "", "# ML Claw deployment control\n");
15208
15219
  }
15209
- async readModelDocument(repoId, path17) {
15220
+ async readModelDocument(repoId, path16) {
15210
15221
  const info = await this.requestJson(`/api/models/${repoId}`);
15211
15222
  if (!info.sha) throw new Error(`control repository ${repoId} has no revision`);
15212
- const url = `${this.hubUrl}/${repoId}/resolve/${info.sha}/${path17.split("/").map(encodeURIComponent).join("/")}`;
15223
+ const url = `${this.hubUrl}/${repoId}/resolve/${info.sha}/${path16.split("/").map(encodeURIComponent).join("/")}`;
15213
15224
  const response = await this.fetchImpl(url, {
15214
15225
  headers: { Authorization: `Bearer ${this.token}` }
15215
15226
  });
@@ -15217,16 +15228,16 @@ var HubApi = class {
15217
15228
  if (!response.ok) throw new HubApiError2(response.status, url, await response.text());
15218
15229
  return { value: JSON.parse(await response.text()), revision: info.sha };
15219
15230
  }
15220
- async commitModelDocument(repoId, path17, parentCommit, value) {
15231
+ async commitModelDocument(repoId, path16, parentCommit, value) {
15221
15232
  const header = {
15222
15233
  summary: value === null ? "Release deployment control" : "Update deployment control",
15223
15234
  description: "ML Claw deployment reconciliation state"
15224
15235
  };
15225
15236
  if (parentCommit) header.parentCommit = parentCommit;
15226
- const operation = value === null ? { key: "deletedFile", value: { path: path17 } } : {
15237
+ const operation = value === null ? { key: "deletedFile", value: { path: path16 } } : {
15227
15238
  key: "file",
15228
15239
  value: {
15229
- path: path17,
15240
+ path: path16,
15230
15241
  content: Buffer.from(typeof value === "string" ? value : `${JSON.stringify(value, null, 2)}
15231
15242
  `).toString(
15232
15243
  "base64"
@@ -15370,21 +15381,22 @@ function nextLink(header) {
15370
15381
  return null;
15371
15382
  }
15372
15383
 
15384
+ // src/mlclaw/release-config.generated.ts
15385
+ var RELEASE_CONFIG = {
15386
+ "packageVersion": "0.4.8",
15387
+ "openclawVersion": "2026.7.1",
15388
+ "brokerkitVersion": "hf-broker/v0.4.2",
15389
+ "brokerkitPluginVersion": "0.3.4",
15390
+ "runtimeImageRepository": "ghcr.io/huggingface/mlclaw"
15391
+ };
15392
+
15373
15393
  // src/mlclaw/runtime-image.ts
15374
- import fs12 from "node:fs";
15375
- import path13 from "node:path";
15376
- import { fileURLToPath as fileURLToPath2 } from "node:url";
15377
- var DEFAULT_OPENCLAW_VERSION = "2026.7.1";
15378
- var DEFAULT_BROKERKIT_PLUGIN_VERSION = "0.3.2";
15379
- var DEFAULT_BROKERKIT_VERSION = "hf-broker/v0.4.0";
15380
- var DEFAULT_RUNTIME_IMAGE_REPOSITORY = "ghcr.io/huggingface/mlclaw";
15381
- var PACKAGE_METADATA = readPackageMetadata();
15382
- var PACKAGE_VERSION = packageString("version", "unknown");
15383
- var OPENCLAW_VERSION = packageConfigString("openclawVersion", DEFAULT_OPENCLAW_VERSION);
15394
+ var PACKAGE_VERSION = RELEASE_CONFIG.packageVersion;
15395
+ var OPENCLAW_VERSION = RELEASE_CONFIG.openclawVersion;
15384
15396
  var OPENCLAW_BASE_IMAGE = `ghcr.io/openclaw/openclaw:${OPENCLAW_VERSION}`;
15385
- var BROKERKIT_PLUGIN_VERSION = packageConfigString("brokerkitPluginVersion", DEFAULT_BROKERKIT_PLUGIN_VERSION);
15386
- var BROKERKIT_VERSION = packageConfigString("brokerkitVersion", DEFAULT_BROKERKIT_VERSION);
15387
- var RUNTIME_IMAGE_REPOSITORY = packageConfigString("runtimeImageRepository", DEFAULT_RUNTIME_IMAGE_REPOSITORY);
15397
+ var BROKERKIT_PLUGIN_VERSION = RELEASE_CONFIG.brokerkitPluginVersion;
15398
+ var BROKERKIT_VERSION = RELEASE_CONFIG.brokerkitVersion;
15399
+ var RUNTIME_IMAGE_REPOSITORY = RELEASE_CONFIG.runtimeImageRepository;
15388
15400
  var DEFAULT_RUNTIME_IMAGE_TAG = `${PACKAGE_VERSION}-openclaw-${OPENCLAW_VERSION}`;
15389
15401
  var DEFAULT_RUNTIME_IMAGE = `${RUNTIME_IMAGE_REPOSITORY}:${DEFAULT_RUNTIME_IMAGE_TAG}`;
15390
15402
  function resolveRuntimeImage(value, env = process.env) {
@@ -15402,45 +15414,16 @@ function resolveSpaceRuntimeImage(opts, env = process.env) {
15402
15414
  function bundledSpaceRuntimeRef(templateRev) {
15403
15415
  return `bundled:${templateRev}`;
15404
15416
  }
15405
- function packageString(key, fallback) {
15406
- const value = PACKAGE_METADATA[key];
15407
- return typeof value === "string" && value.trim() ? value.trim() : fallback;
15408
- }
15409
- function packageConfigString(key, fallback) {
15410
- const value = PACKAGE_METADATA.config?.[key];
15411
- return typeof value === "string" && value.trim() ? value.trim() : fallback;
15412
- }
15413
- function readPackageMetadata() {
15414
- let dir = path13.dirname(fileURLToPath2(import.meta.url));
15415
- while (true) {
15416
- const candidate = path13.join(dir, "package.json");
15417
- try {
15418
- return JSON.parse(fs12.readFileSync(candidate, "utf8"));
15419
- } catch (err) {
15420
- if (!isMissingFileError(err)) {
15421
- throw err;
15422
- }
15423
- }
15424
- const parent = path13.dirname(dir);
15425
- if (parent === dir) {
15426
- throw new Error("could not find package.json while resolving default runtime image");
15427
- }
15428
- dir = parent;
15429
- }
15430
- }
15431
- function isMissingFileError(err) {
15432
- return err instanceof Error && "code" in err && err.code === "ENOENT";
15433
- }
15434
15417
 
15435
15418
  // src/mlclaw/git.ts
15436
15419
  var execFileAsync2 = promisify2(execFile2);
15437
15420
  async function pushTemplateToSpace(params) {
15438
- const tempRoot = await fs13.mkdtemp(path14.join(os5.tmpdir(), "mlclaw-space-"));
15421
+ const tempRoot = await fs12.mkdtemp(path13.join(os5.tmpdir(), "mlclaw-space-"));
15439
15422
  try {
15440
15423
  const sourceDir = params.sourceDir ?? process.env.MLCLAW_SOURCE_DIR ?? await findPackagedSourceRoot();
15441
15424
  const templateRev = await currentTemplateRev(sourceDir);
15442
- const outDir = path14.join(tempRoot, "space");
15443
- await fs13.mkdir(outDir, { recursive: true });
15425
+ const outDir = path13.join(tempRoot, "space");
15426
+ await fs12.mkdir(outDir, { recursive: true });
15444
15427
  await generateSpaceRepo(sourceDir, outDir, {
15445
15428
  ...params.runtimeImage ? { runtimeImage: params.runtimeImage } : {}
15446
15429
  });
@@ -15458,7 +15441,7 @@ async function pushTemplateToSpace(params) {
15458
15441
  });
15459
15442
  return { templateRev };
15460
15443
  } finally {
15461
- await fs13.rm(tempRoot, { recursive: true, force: true });
15444
+ await fs12.rm(tempRoot, { recursive: true, force: true });
15462
15445
  }
15463
15446
  }
15464
15447
  async function currentTemplateRev(sourceDir) {
@@ -15471,7 +15454,7 @@ async function currentTemplateRev(sourceDir) {
15471
15454
  }
15472
15455
  } catch {
15473
15456
  }
15474
- const pkg = JSON.parse(await fs13.readFile(path14.join(sourceDir, "package.json"), "utf8"));
15457
+ const pkg = JSON.parse(await fs12.readFile(path13.join(sourceDir, "package.json"), "utf8"));
15475
15458
  return `npm:${pkg.name ?? "mlclaw"}@${pkg.version ?? "unknown"}`;
15476
15459
  }
15477
15460
  async function generateSpaceRepo(sourceDir, outDir, options = {}) {
@@ -15497,13 +15480,13 @@ async function generateSpaceRepo(sourceDir, outDir, options = {}) {
15497
15480
  );
15498
15481
  }
15499
15482
  for (const [from, to] of copies) {
15500
- await copyExisting(path14.join(sourceDir, from), path14.join(outDir, to));
15483
+ await copyExisting(path13.join(sourceDir, from), path13.join(outDir, to));
15501
15484
  }
15502
- const hfLogoPng = await fs13.readFile(path14.join(sourceDir, "assets/hf-logo.png"));
15503
- await fs13.writeFile(path14.join(outDir, "assets/hf-logo.png.base64"), `${hfLogoPng.toString("base64")}
15485
+ const hfLogoPng = await fs12.readFile(path13.join(sourceDir, "assets/hf-logo.png"));
15486
+ await fs12.writeFile(path13.join(outDir, "assets/hf-logo.png.base64"), `${hfLogoPng.toString("base64")}
15504
15487
  `, "utf8");
15505
- await fs13.writeFile(
15506
- path14.join(outDir, "Dockerfile"),
15488
+ await fs12.writeFile(
15489
+ path13.join(outDir, "Dockerfile"),
15507
15490
  options.runtimeImage ? imageDockerfile(options.runtimeImage) : bundledDockerfile(),
15508
15491
  "utf8"
15509
15492
  );
@@ -15591,13 +15574,13 @@ CMD ["/app/entrypoint.sh"]
15591
15574
  `;
15592
15575
  }
15593
15576
  async function findPackagedSourceRoot() {
15594
- const start = path14.dirname(fileURLToPath3(import.meta.url));
15577
+ const start = path13.dirname(fileURLToPath2(import.meta.url));
15595
15578
  let dir = start;
15596
15579
  while (true) {
15597
15580
  if (await hasPackagedSourceFiles(dir)) {
15598
15581
  return dir;
15599
15582
  }
15600
- const parent = path14.dirname(dir);
15583
+ const parent = path13.dirname(dir);
15601
15584
  if (parent === dir) {
15602
15585
  throw new Error("Could not find packaged ML Claw source files. Reinstall the mlclaw npm package.");
15603
15586
  }
@@ -15614,20 +15597,20 @@ async function hasPackagedSourceFiles(dir) {
15614
15597
  "src/hf-bucket-client/client.ts"
15615
15598
  ];
15616
15599
  try {
15617
- await Promise.all(required.map((file) => fs13.access(path14.join(dir, file))));
15600
+ await Promise.all(required.map((file) => fs12.access(path13.join(dir, file))));
15618
15601
  return true;
15619
15602
  } catch {
15620
15603
  return false;
15621
15604
  }
15622
15605
  }
15623
15606
  async function copyExisting(from, to) {
15624
- const stat = await fs13.stat(from);
15625
- await fs13.mkdir(path14.dirname(to), { recursive: true });
15607
+ const stat = await fs12.stat(from);
15608
+ await fs12.mkdir(path13.dirname(to), { recursive: true });
15626
15609
  if (stat.isDirectory()) {
15627
- await fs13.cp(from, to, { recursive: true });
15610
+ await fs12.cp(from, to, { recursive: true });
15628
15611
  } else {
15629
- await fs13.copyFile(from, to);
15630
- await fs13.chmod(to, stat.mode);
15612
+ await fs12.copyFile(from, to);
15613
+ await fs12.chmod(to, stat.mode);
15631
15614
  }
15632
15615
  }
15633
15616
  async function readFilesForCommit(root) {
@@ -15635,24 +15618,24 @@ async function readFilesForCommit(root) {
15635
15618
  for (const relativePath of await listFiles(root)) {
15636
15619
  files.push({
15637
15620
  path: relativePath,
15638
- content: await fs13.readFile(path14.join(root, relativePath))
15621
+ content: await fs12.readFile(path13.join(root, relativePath))
15639
15622
  });
15640
15623
  }
15641
15624
  return files;
15642
15625
  }
15643
15626
  async function listFiles(root, dir = "") {
15644
- const absoluteDir = path14.join(root, dir);
15645
- const entries = await fs13.readdir(absoluteDir, { withFileTypes: true });
15627
+ const absoluteDir = path13.join(root, dir);
15628
+ const entries = await fs12.readdir(absoluteDir, { withFileTypes: true });
15646
15629
  const files = [];
15647
15630
  for (const entry of entries) {
15648
- const relativePath = path14.posix.join(dir.split(path14.sep).join(path14.posix.sep), entry.name);
15649
- const absolutePath = path14.join(root, relativePath);
15631
+ const relativePath = path13.posix.join(dir.split(path13.sep).join(path13.posix.sep), entry.name);
15632
+ const absolutePath = path13.join(root, relativePath);
15650
15633
  if (entry.isDirectory()) {
15651
15634
  files.push(...await listFiles(root, relativePath));
15652
15635
  } else if (entry.isFile()) {
15653
15636
  files.push(relativePath);
15654
15637
  } else {
15655
- const stat = await fs13.stat(absolutePath);
15638
+ const stat = await fs12.stat(absolutePath);
15656
15639
  if (stat.isFile()) {
15657
15640
  files.push(relativePath);
15658
15641
  }
@@ -15731,9 +15714,9 @@ function deriveLocalAccessToken(sessionSecret) {
15731
15714
  }
15732
15715
 
15733
15716
  // src/mlclaw/local-config.ts
15734
- import fs14 from "node:fs/promises";
15717
+ import fs13 from "node:fs/promises";
15735
15718
  import os6 from "node:os";
15736
- import path15 from "node:path";
15719
+ import path14 from "node:path";
15737
15720
  import { createHash as createHash2 } from "node:crypto";
15738
15721
 
15739
15722
  // node_modules/zod/v3/external.js
@@ -16214,8 +16197,8 @@ function getErrorMap() {
16214
16197
 
16215
16198
  // node_modules/zod/v3/helpers/parseUtil.js
16216
16199
  var makeIssue = (params) => {
16217
- const { data, path: path17, errorMaps, issueData } = params;
16218
- const fullPath = [...path17, ...issueData.path || []];
16200
+ const { data, path: path16, errorMaps, issueData } = params;
16201
+ const fullPath = [...path16, ...issueData.path || []];
16219
16202
  const fullIssue = {
16220
16203
  ...issueData,
16221
16204
  path: fullPath
@@ -16331,11 +16314,11 @@ var errorUtil;
16331
16314
 
16332
16315
  // node_modules/zod/v3/types.js
16333
16316
  var ParseInputLazyPath = class {
16334
- constructor(parent, value, path17, key) {
16317
+ constructor(parent, value, path16, key) {
16335
16318
  this._cachedPath = [];
16336
16319
  this.parent = parent;
16337
16320
  this.data = value;
16338
- this._path = path17;
16321
+ this._path = path16;
16339
16322
  this._key = key;
16340
16323
  }
16341
16324
  get path() {
@@ -19841,14 +19824,14 @@ var manifestFields = {
19841
19824
  model: external_exports.string().min(1).max(512),
19842
19825
  runtimeImage: external_exports.string().min(1).max(1024),
19843
19826
  brokerCredential: external_exports.object({
19844
- profileId: external_exports.literal("hf-broker-complete-v1"),
19827
+ credentialKind: external_exports.literal("fine_grained_user_token"),
19845
19828
  account: external_exports.string().min(1).max(128),
19846
19829
  fingerprintSha256: external_exports.string().regex(/^[a-f0-9]{64}$/),
19847
19830
  verifiedAt: external_exports.string().datetime()
19848
19831
  }).strict().optional(),
19849
19832
  credentialKeySha256: external_exports.string().regex(/^[a-f0-9]{64}$/).optional(),
19850
19833
  tailscaleMode: external_exports.enum(["off", "direct", "serve"]).optional(),
19851
- spaceVisibility: external_exports.enum(["private", "public"]).optional(),
19834
+ spaceVisibility: external_exports.enum(["private", "protected", "public"]).optional(),
19852
19835
  spaceHardware: external_exports.string().min(1).max(128).optional(),
19853
19836
  spaceSleepTime: external_exports.number().int().min(-1).optional(),
19854
19837
  recoveredWithoutCredentialKey: external_exports.boolean().optional(),
@@ -19873,24 +19856,24 @@ function defaultConfigRoot(env = process.env) {
19873
19856
  }
19874
19857
  const xdg = env.XDG_CONFIG_HOME?.trim();
19875
19858
  if (xdg) {
19876
- return path15.join(xdg, "mlclaw");
19859
+ return path14.join(xdg, "mlclaw");
19877
19860
  }
19878
- return path15.join(os6.homedir(), ".config", "mlclaw");
19861
+ return path14.join(os6.homedir(), ".config", "mlclaw");
19879
19862
  }
19880
19863
  function localConfigPaths(root) {
19881
19864
  return {
19882
19865
  root,
19883
- deploymentsDir: path15.join(root, "deployments"),
19884
- secretsDir: path15.join(root, "secrets"),
19885
- operationsDir: path15.join(root, "operations"),
19886
- locksDir: path15.join(root, "locks")
19866
+ deploymentsDir: path14.join(root, "deployments"),
19867
+ secretsDir: path14.join(root, "secrets"),
19868
+ operationsDir: path14.join(root, "operations"),
19869
+ locksDir: path14.join(root, "locks")
19887
19870
  };
19888
19871
  }
19889
19872
  function manifestPath(root, agent) {
19890
- return path15.join(localConfigPaths(root).deploymentsDir, `${assertAgentName(agent)}.json`);
19873
+ return path14.join(localConfigPaths(root).deploymentsDir, `${assertAgentName(agent)}.json`);
19891
19874
  }
19892
19875
  function secretEnvPath(root, agent) {
19893
- return path15.join(localConfigPaths(root).secretsDir, `${assertAgentName(agent)}.env`);
19876
+ return path14.join(localConfigPaths(root).secretsDir, `${assertAgentName(agent)}.env`);
19894
19877
  }
19895
19878
  async function writeManifest(root, input) {
19896
19879
  const manifest = input.version === 1 ? importLegacyManifest(legacyManifestSchema.parse(input)) : manifestSchema.parse(input);
@@ -19900,7 +19883,7 @@ async function writeManifest(root, input) {
19900
19883
  }
19901
19884
  async function readManifest(root, agent) {
19902
19885
  const file = manifestPath(root, agent);
19903
- const raw = JSON.parse(await fs14.readFile(file, "utf8"));
19886
+ const raw = JSON.parse(await fs13.readFile(file, "utf8"));
19904
19887
  const version = raw && typeof raw === "object" && "version" in raw ? raw.version : void 0;
19905
19888
  const parsed = version === 1 ? legacyManifestSchema.parse(raw) : manifestSchema.parse(raw);
19906
19889
  if (parsed.version === 1) {
@@ -19913,7 +19896,7 @@ async function readManifest(root, agent) {
19913
19896
  }
19914
19897
  async function listManifests(root) {
19915
19898
  const dir = localConfigPaths(root).deploymentsDir;
19916
- const entries = await fs14.readdir(dir, { withFileTypes: true }).catch((error) => {
19899
+ const entries = await fs13.readdir(dir, { withFileTypes: true }).catch((error) => {
19917
19900
  if (error.code === "ENOENT") return [];
19918
19901
  throw error;
19919
19902
  });
@@ -19924,7 +19907,7 @@ async function listManifests(root) {
19924
19907
  }
19925
19908
  async function manifestExists(root, agent) {
19926
19909
  try {
19927
- await fs14.access(manifestPath(root, agent));
19910
+ await fs13.access(manifestPath(root, agent));
19928
19911
  return true;
19929
19912
  } catch {
19930
19913
  return false;
@@ -19939,7 +19922,7 @@ async function writeSecretEnv(root, agent, values) {
19939
19922
  await writePrivateFile(file, renderSecretEnv(values));
19940
19923
  }
19941
19924
  async function readSecretEnv(root, agent) {
19942
- return parseSecretEnv(await fs14.readFile(secretEnvPath(root, agent), "utf8"));
19925
+ return parseSecretEnv(await fs13.readFile(secretEnvPath(root, agent), "utf8"));
19943
19926
  }
19944
19927
  function parseSecretEnv(raw) {
19945
19928
  const out = {};
@@ -19971,17 +19954,17 @@ function importLegacyManifest(manifest) {
19971
19954
  return { ...manifest, version: 2, deploymentId, desiredGeneration: 0 };
19972
19955
  }
19973
19956
  async function writePrivateFile(file, content) {
19974
- await fs14.mkdir(path15.dirname(file), { recursive: true, mode: 448 });
19957
+ await fs13.mkdir(path14.dirname(file), { recursive: true, mode: 448 });
19975
19958
  const temporary = `${file}.${process.pid}.${Date.now()}.tmp`;
19976
- await fs14.writeFile(temporary, content, { encoding: "utf8", mode: 384, flag: "wx" });
19977
- await fs14.rename(temporary, file);
19978
- await fs14.chmod(file, 384);
19959
+ await fs13.writeFile(temporary, content, { encoding: "utf8", mode: 384, flag: "wx" });
19960
+ await fs13.rename(temporary, file);
19961
+ await fs13.chmod(file, 384);
19979
19962
  }
19980
19963
 
19981
19964
  // src/mlclaw/deployment-state.ts
19982
- import fs15 from "node:fs/promises";
19965
+ import fs14 from "node:fs/promises";
19983
19966
  import os7 from "node:os";
19984
- import path16 from "node:path";
19967
+ import path15 from "node:path";
19985
19968
  import { randomUUID } from "node:crypto";
19986
19969
  var DEPLOYMENT_PATH = ".mlclaw/deployment.json";
19987
19970
  var DESIRED_STATE_PATH = ".mlclaw/desired-state.json";
@@ -20013,7 +19996,7 @@ var desiredStateSchema = external_exports.object({
20013
19996
  runtimeImage: external_exports.string().min(1).max(1024),
20014
19997
  space: external_exports.object({
20015
19998
  repo: external_exports.string().min(3).max(256),
20016
- visibility: external_exports.enum(["private", "public"]),
19999
+ visibility: external_exports.enum(["private", "protected", "public"]),
20017
20000
  hardware: external_exports.string().min(1).max(128).optional(),
20018
20001
  sleepTime: external_exports.number().int().min(-1).optional()
20019
20002
  }).strict()
@@ -20067,7 +20050,7 @@ function deploymentIdentity(manifest, statePrefix = "openclaw-state") {
20067
20050
  createdAt: manifest.createdAt
20068
20051
  });
20069
20052
  }
20070
- function deploymentDesiredState(manifest, visibility = manifest.spaceVisibility ?? "private") {
20053
+ function deploymentDesiredState(manifest, visibility = manifest.spaceVisibility ?? "protected") {
20071
20054
  return desiredStateSchema.parse({
20072
20055
  schemaVersion: 1,
20073
20056
  deploymentId: manifest.deploymentId,
@@ -20128,7 +20111,7 @@ function newOperation(manifest, now) {
20128
20111
  }
20129
20112
  async function writeOperation(root, client, operation) {
20130
20113
  const parsed = operationSchema.parse(operation);
20131
- const local = path16.join(localConfigPaths(root).operationsDir, `${parsed.operationId}.json`);
20114
+ const local = path15.join(localConfigPaths(root).operationsDir, `${parsed.operationId}.json`);
20132
20115
  await atomicPrivateWrite(local, stringify(parsed));
20133
20116
  await client.uploadFiles([jsonBlob(`.mlclaw/operations/${parsed.operationId}.json`, parsed)]);
20134
20117
  }
@@ -20144,13 +20127,13 @@ async function updateOperation(root, client, operation, state, now, detail) {
20144
20127
  }
20145
20128
  async function readResumableOperation(root, deploymentId, targetGeneration) {
20146
20129
  const directory = localConfigPaths(root).operationsDir;
20147
- const entries = await fs15.readdir(directory, { withFileTypes: true }).catch((error) => {
20130
+ const entries = await fs14.readdir(directory, { withFileTypes: true }).catch((error) => {
20148
20131
  if (error.code === "ENOENT") return [];
20149
20132
  throw error;
20150
20133
  });
20151
20134
  const operations = await Promise.all(
20152
20135
  entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => {
20153
- const raw = await fs15.readFile(path16.join(directory, entry.name), "utf8");
20136
+ const raw = await fs14.readFile(path15.join(directory, entry.name), "utf8");
20154
20137
  return operationSchema.parse(JSON.parse(raw));
20155
20138
  })
20156
20139
  );
@@ -20159,12 +20142,12 @@ async function readResumableOperation(root, deploymentId, targetGeneration) {
20159
20142
  ).sort((a, b2) => b2.updatedAt.localeCompare(a.updatedAt))[0] ?? null;
20160
20143
  }
20161
20144
  async function withDeploymentLock(root, deploymentId, task) {
20162
- const file = path16.join(localConfigPaths(root).locksDir, `${deploymentId}.lock`);
20163
- await fs15.mkdir(path16.dirname(file), { recursive: true, mode: 448 });
20145
+ const file = path15.join(localConfigPaths(root).locksDir, `${deploymentId}.lock`);
20146
+ await fs14.mkdir(path15.dirname(file), { recursive: true, mode: 448 });
20164
20147
  const token = randomUUID();
20165
20148
  const lock = stringify({ pid: process.pid, host: os7.hostname(), token, createdAt: (/* @__PURE__ */ new Date()).toISOString() });
20166
20149
  try {
20167
- await fs15.writeFile(file, lock, { flag: "wx", mode: 384 });
20150
+ await fs14.writeFile(file, lock, { flag: "wx", mode: 384 });
20168
20151
  } catch (error) {
20169
20152
  if (error.code !== "EEXIST") throw error;
20170
20153
  if (!await replaceStaleLocalLock(file, lock)) {
@@ -20187,38 +20170,38 @@ async function withDeploymentLock(root, deploymentId, task) {
20187
20170
  async function replaceStaleLocalLock(file, replacement) {
20188
20171
  const guard = `${file}.reclaim`;
20189
20172
  try {
20190
- await fs15.mkdir(guard);
20173
+ await fs14.mkdir(guard);
20191
20174
  } catch (error) {
20192
20175
  if (error.code === "EEXIST") return false;
20193
20176
  throw error;
20194
20177
  }
20195
20178
  try {
20196
- const [raw, stat] = await Promise.all([fs15.readFile(file, "utf8"), fs15.stat(file)]);
20179
+ const [raw, stat] = await Promise.all([fs14.readFile(file, "utf8"), fs14.stat(file)]);
20197
20180
  const value = JSON.parse(raw);
20198
20181
  if (value.host !== os7.hostname() || typeof value.pid !== "number") return false;
20199
20182
  const createdAt = typeof value.createdAt === "string" ? Date.parse(value.createdAt) : Number.NaN;
20200
20183
  const lastRefresh = Number.isFinite(createdAt) ? Math.max(createdAt, stat.mtimeMs) : stat.mtimeMs;
20201
20184
  if (processIsAlive(value.pid) && Date.now() - lastRefresh <= LOCAL_LOCK_STALE_MS) return false;
20202
- await fs15.rm(file);
20203
- await fs15.writeFile(file, replacement, { flag: "wx", mode: 384 });
20185
+ await fs14.rm(file);
20186
+ await fs14.writeFile(file, replacement, { flag: "wx", mode: 384 });
20204
20187
  return true;
20205
20188
  } catch {
20206
20189
  return false;
20207
20190
  } finally {
20208
- await fs15.rm(guard, { recursive: true, force: true });
20191
+ await fs14.rm(guard, { recursive: true, force: true });
20209
20192
  }
20210
20193
  }
20211
20194
  async function refreshOwnedLocalLock(file, token) {
20212
20195
  if (!await localLockHasToken(file, token)) return;
20213
20196
  const now = /* @__PURE__ */ new Date();
20214
- await fs15.utimes(file, now, now);
20197
+ await fs14.utimes(file, now, now);
20215
20198
  }
20216
20199
  async function removeOwnedLocalLock(file, token) {
20217
- if (await localLockHasToken(file, token)) await fs15.rm(file, { force: true });
20200
+ if (await localLockHasToken(file, token)) await fs14.rm(file, { force: true });
20218
20201
  }
20219
20202
  async function localLockHasToken(file, token) {
20220
20203
  try {
20221
- const value = JSON.parse(await fs15.readFile(file, "utf8"));
20204
+ const value = JSON.parse(await fs14.readFile(file, "utf8"));
20222
20205
  return value.token === token;
20223
20206
  } catch {
20224
20207
  return false;
@@ -20284,19 +20267,19 @@ async function readDocument(client, file, schema) {
20284
20267
  if (blob.size > MAX_CONTROL_BYTES) throw new Error(`${file} exceeds ${MAX_CONTROL_BYTES} bytes`);
20285
20268
  return schema.parse(JSON.parse(await blob.text()));
20286
20269
  }
20287
- function jsonBlob(path17, value) {
20288
- return { path: path17, content: new Blob([stringify(value)], { type: "application/json" }) };
20270
+ function jsonBlob(path16, value) {
20271
+ return { path: path16, content: new Blob([stringify(value)], { type: "application/json" }) };
20289
20272
  }
20290
20273
  function stringify(value) {
20291
20274
  return `${JSON.stringify(value, null, 2)}
20292
20275
  `;
20293
20276
  }
20294
20277
  async function atomicPrivateWrite(file, content) {
20295
- await fs15.mkdir(path16.dirname(file), { recursive: true, mode: 448 });
20278
+ await fs14.mkdir(path15.dirname(file), { recursive: true, mode: 448 });
20296
20279
  const temporary = `${file}.${process.pid}.tmp`;
20297
- await fs15.writeFile(temporary, content, { mode: 384, flag: "wx" });
20298
- await fs15.rename(temporary, file);
20299
- await fs15.chmod(file, 384);
20280
+ await fs14.writeFile(temporary, content, { mode: 384, flag: "wx" });
20281
+ await fs14.rename(temporary, file);
20282
+ await fs14.chmod(file, 384);
20300
20283
  }
20301
20284
 
20302
20285
  // src/mlclaw/telegram.ts
@@ -20336,116 +20319,13 @@ function delay(ms) {
20336
20319
 
20337
20320
  // src/mlclaw/hf-broker-credential.ts
20338
20321
  import { createHash as createHash3 } from "node:crypto";
20339
-
20340
- // src/mlclaw/hf-broker-credential-requirements.json
20341
- var hf_broker_credential_requirements_default = {
20342
- version: 1,
20343
- profile_id: "hf-broker-complete-v1",
20344
- token_form_url: "https://huggingface.co/settings/tokens/new",
20345
- token_type: "fineGrained",
20346
- requires_gated_repositories: true,
20347
- personal_permissions: [
20348
- "collection.read",
20349
- "collection.write",
20350
- "discussion.write",
20351
- "inference.endpoints.infer.write",
20352
- "inference.endpoints.write",
20353
- "inference.serverless.write",
20354
- "job.write",
20355
- "repo.access.read",
20356
- "repo.content.read",
20357
- "repo.write",
20358
- "sql-console.embed.write",
20359
- "user.billing.read",
20360
- "user.mcp.read",
20361
- "user.notifications.read",
20362
- "user.notifications.write",
20363
- "user.papers.write",
20364
- "user.preferences.write",
20365
- "user.settings.notifications.write",
20366
- "user.social.likes.write",
20367
- "user.webhooks.read",
20368
- "user.webhooks.write"
20369
- ],
20370
- global_permissions: [
20371
- "discussion.write",
20372
- "post.write"
20373
- ],
20374
- organization_permissions: [
20375
- "collection.read",
20376
- "collection.write",
20377
- "discussion.write",
20378
- "inference.endpoints.infer.write",
20379
- "inference.endpoints.write",
20380
- "inference.serverless.write",
20381
- "job.write",
20382
- "org.auditLog.write",
20383
- "org.billing.read",
20384
- "org.members.read",
20385
- "org.members.write",
20386
- "org.networkSecurity.read",
20387
- "org.networkSecurity.write",
20388
- "org.read",
20389
- "org.repos.read",
20390
- "org.serviceAccounts.read",
20391
- "org.serviceAccounts.write",
20392
- "org.write",
20393
- "repo.access.read",
20394
- "repo.content.read",
20395
- "repo.write",
20396
- "resourceGroup.write",
20397
- "sql-console.embed.write"
20398
- ]
20399
- };
20400
-
20401
- // src/mlclaw/hf-broker-credential.ts
20402
- var permissionListSchema = external_exports.array(external_exports.string().min(1)).min(1).superRefine((permissions, context) => {
20403
- if (permissions.some((permission) => permission !== permission.trim())) {
20404
- context.addIssue({ code: external_exports.ZodIssueCode.custom, message: "permissions must not contain outer whitespace" });
20405
- }
20406
- if (new Set(permissions).size !== permissions.length) {
20407
- context.addIssue({ code: external_exports.ZodIssueCode.custom, message: "permissions must be unique" });
20408
- }
20409
- if (permissions.some((permission, index) => index > 0 && permission < permissions[index - 1])) {
20410
- context.addIssue({ code: external_exports.ZodIssueCode.custom, message: "permissions must be sorted" });
20411
- }
20412
- });
20413
- var profileSchema = external_exports.object({
20414
- version: external_exports.literal(1),
20415
- profile_id: external_exports.literal("hf-broker-complete-v1"),
20416
- token_form_url: external_exports.literal("https://huggingface.co/settings/tokens/new"),
20417
- token_type: external_exports.literal("fineGrained"),
20418
- requires_gated_repositories: external_exports.literal(true),
20419
- personal_permissions: permissionListSchema,
20420
- global_permissions: permissionListSchema,
20421
- organization_permissions: permissionListSchema
20422
- }).strict();
20423
- var BROKER_CREDENTIAL_PROFILE = Object.freeze(profileSchema.parse(hf_broker_credential_requirements_default));
20424
- var HF_TOKEN_CREATE_URL = BROKER_CREDENTIAL_PROFILE.token_form_url;
20425
- var BROKER_PERSONAL_PERMISSIONS = BROKER_CREDENTIAL_PROFILE.personal_permissions;
20426
- var BROKER_GLOBAL_PERMISSIONS = BROKER_CREDENTIAL_PROFILE.global_permissions;
20427
- var BROKER_ORGANIZATION_PERMISSIONS = BROKER_CREDENTIAL_PROFILE.organization_permissions;
20428
- function buildBrokerTokenUrl(owner, accountName) {
20429
- const url = new URL(HF_TOKEN_CREATE_URL);
20430
- url.searchParams.set("tokenType", BROKER_CREDENTIAL_PROFILE.token_type);
20431
- for (const permission of BROKER_PERSONAL_PERMISSIONS) {
20432
- url.searchParams.append("ownUserPermissions", permission);
20433
- }
20434
- for (const permission of BROKER_GLOBAL_PERMISSIONS) {
20435
- url.searchParams.append("globalPermissions", permission);
20436
- }
20437
- url.searchParams.set("canReadGatedRepos", String(BROKER_CREDENTIAL_PROFILE.requires_gated_repositories));
20438
- if (owner !== accountName) {
20439
- url.searchParams.append("orgs", owner);
20440
- for (const permission of BROKER_ORGANIZATION_PERMISSIONS) {
20441
- url.searchParams.append("orgPermissions", permission);
20442
- }
20443
- }
20444
- return url.toString();
20445
- }
20446
- function assessBrokerCredential(identity, owner) {
20322
+ var HF_TOKEN_CREATE_URL = "https://huggingface.co/settings/tokens/new?tokenType=fineGrained";
20323
+ function buildBrokerTokenUrl() {
20324
+ return HF_TOKEN_CREATE_URL;
20325
+ }
20326
+ function assessBrokerCredential(identity) {
20447
20327
  const accessToken = identity.auth?.accessToken;
20448
- if (accessToken?.role !== BROKER_CREDENTIAL_PROFILE.token_type) {
20328
+ if (accessToken?.role !== "fineGrained") {
20449
20329
  return {
20450
20330
  status: "unsupported",
20451
20331
  reason: "HF Broker requires a dedicated fine-grained Hugging Face token"
@@ -20457,40 +20337,16 @@ function assessBrokerCredential(identity, owner) {
20457
20337
  reason: "Hugging Face omitted this fine-grained token's permission details"
20458
20338
  };
20459
20339
  }
20460
- const personalAvailable = new Set(scopedPermissions(accessToken.fineGrained.scoped, "user", identity.name));
20461
- const globalAvailable = new Set(accessToken.fineGrained.global);
20462
- const missing = BROKER_PERSONAL_PERMISSIONS.filter((permission) => !personalAvailable.has(permission));
20463
- missing.push(
20464
- ...BROKER_GLOBAL_PERMISSIONS.filter((permission) => !globalAvailable.has(permission)).map(
20465
- (permission) => `global:${permission}`
20466
- )
20467
- );
20468
- if (!accessToken.fineGrained.canReadGatedRepos) {
20469
- missing.push("canReadGatedRepos");
20470
- }
20471
- if (owner !== identity.name) {
20472
- const organizationAvailable = new Set(scopedPermissions(accessToken.fineGrained.scoped, "org", owner));
20473
- missing.push(
20474
- ...BROKER_ORGANIZATION_PERMISSIONS.filter((permission) => !organizationAvailable.has(permission)).map(
20475
- (permission) => `org:${permission}`
20476
- )
20477
- );
20478
- }
20479
- missing.sort();
20480
- return missing.length === 0 ? { status: "sufficient" } : { status: "insufficient", missing };
20340
+ return { status: "sufficient" };
20481
20341
  }
20482
20342
  function brokerCredentialMetadata(token, identity, verifiedAt) {
20483
20343
  return {
20484
- profileId: BROKER_CREDENTIAL_PROFILE.profile_id,
20344
+ credentialKind: "fine_grained_user_token",
20485
20345
  account: identity.name,
20486
20346
  fingerprintSha256: createHash3("sha256").update(token).digest("hex"),
20487
20347
  verifiedAt: verifiedAt.toISOString()
20488
20348
  };
20489
20349
  }
20490
- function scopedPermissions(scopes, type, name) {
20491
- if (!Array.isArray(scopes)) return [];
20492
- return scopes.filter((scope) => scope.entity.type === type && (!scope.entity.name || scope.entity.name === name)).flatMap((scope) => scope.permissions);
20493
- }
20494
20350
 
20495
20351
  // src/mlclaw/tailscale.ts
20496
20352
  import { execFile as execFile3 } from "node:child_process";
@@ -20751,7 +20607,7 @@ function createProgram(runtimeOverrides = {}) {
20751
20607
  program2.name("mlclaw").description("Deploy OpenClaw to a Hugging Face Space and private bucket").showHelpAfterError().exitOverride((err) => {
20752
20608
  throw err;
20753
20609
  });
20754
- program2.command("bootstrap", { isDefault: true }).alias("configure").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").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(
20610
+ program2.command("bootstrap", { isDefault: true }).alias("configure").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").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", "Expose the Space source as well as the authenticated app", false).addOption(new Option("--gateway-token <token>").hideHelp()).option("--router-token <token>", "Hugging Face Router inference token for Space gateway model calls").option(
20755
20611
  "--router-token-file <path>",
20756
20612
  "File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token"
20757
20613
  ).option("--broker-hf-token-file <path>", "File containing MLCLAW_BROKER_HF_TOKEN=... or a raw Hugging Face token").option("--docker-context <name>", "Docker context for local gateway mode").option("--container-runtime <auto|docker|podman>", "Local container runtime", "auto").option("--local-port <port>", "Loopback port for a local gateway", parseLocalPort).option("--tailscale <off|direct|serve>", "Tailnet access mode", parseTailscaleMode).option("--tailscale-port <port>", "Tailnet listener or Serve HTTPS port", parseLocalPort).option(
@@ -20802,7 +20658,7 @@ function createProgram(runtimeOverrides = {}) {
20802
20658
  gateway.command("logs").argument("<agent>", "Agent name").option("--tail <lines>", "Number of log lines", parseInteger, 200).action(async (agent, opts) => {
20803
20659
  await gatewayLogs(agent, opts, runtime);
20804
20660
  });
20805
- gateway.command("migrate").argument("<agent>", "Agent name").requiredOption("--to <local|space>", "Target gateway location").option("--hardware <flavor>", "Hugging Face Space hardware flavor").option("--sleep-time <seconds>", "Space sleep timeout in seconds; -1 means never sleep", parseInteger).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).option("--router-token <token>", "Hugging Face Router inference token for Space gateway model calls").option(
20661
+ gateway.command("migrate").argument("<agent>", "Agent name").requiredOption("--to <local|space>", "Target gateway location").option("--hardware <flavor>", "Hugging Face Space hardware flavor").option("--sleep-time <seconds>", "Space sleep timeout in seconds; -1 means never sleep", parseInteger).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", "Expose the Space source as well as the authenticated app", false).option("--router-token <token>", "Hugging Face Router inference token for Space gateway model calls").option(
20806
20662
  "--router-token-file <path>",
20807
20663
  "File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token"
20808
20664
  ).option("--docker-context <name>", "Docker context for local gateway startup when migrating to local").option("--container-runtime <auto|docker|podman>", "Local container runtime", "auto").option("--local-port <port>", "Loopback port for the local gateway", parseLocalPort).option("--tailscale <off|direct|serve>", "Tailnet access mode", parseTailscaleMode).option("--tailscale-port <port>", "Tailnet listener or Serve HTTPS port", parseLocalPort).option("--no-pull", "Do not docker pull before starting a local gateway").option("--takeover", "Start even if another live runtime lease is present", false).option("--yes", "Confirm paid hardware prompts for automation", false).action(async (agent, opts) => {
@@ -21353,7 +21209,7 @@ async function reconcileManifest(params) {
21353
21209
  if (currentDesired && currentDesired.deploymentId !== requestedManifest.deploymentId) {
21354
21210
  throw new Error(`bucket ${requestedManifest.bucket} desired state belongs to another deployment`);
21355
21211
  }
21356
- const visibility = params.visibility ?? requestedManifest.spaceVisibility ?? "private";
21212
+ const visibility = params.visibility ?? requestedManifest.spaceVisibility ?? "protected";
21357
21213
  const candidate = deploymentDesiredState(requestedManifest, visibility);
21358
21214
  const sameDesired = currentDesired && JSON.stringify({ ...currentDesired, generation: 0, updatedAt: "" }) === JSON.stringify({ ...candidate, generation: 0, updatedAt: "" });
21359
21215
  if (currentDesired && currentDesired.generation > requestedManifest.desiredGeneration && !sameDesired) {
@@ -21481,7 +21337,6 @@ async function resolveBootstrapPlan(params) {
21481
21337
  const existingSecrets = await readSecretEnv(runtime.configRoot, agentName).catch(() => ({}));
21482
21338
  const brokerCredential = await resolveBrokerHfToken({
21483
21339
  opts,
21484
- owner,
21485
21340
  hfIdentity,
21486
21341
  ...providedBrokerHfToken ? { preferredToken: providedBrokerHfToken } : {},
21487
21342
  existingSecrets,
@@ -21543,7 +21398,7 @@ async function resolveBootstrapPlan(params) {
21543
21398
  spacePlan = {
21544
21399
  space: names.space,
21545
21400
  exists,
21546
- visibility: opts.publicSpace ? "public" : existingManifest?.spaceVisibility ?? currentVisibility ?? "private",
21401
+ visibility: opts.publicSpace ? "public" : "protected",
21547
21402
  ...currentVisibility ? { currentVisibility } : {}
21548
21403
  };
21549
21404
  }
@@ -21824,7 +21679,7 @@ async function createOrAdoptSpace(params) {
21824
21679
  }
21825
21680
  params.runtime.stdout.log(`Creating ${params.spacePlan.visibility} Space ${params.spacePlan.space}`);
21826
21681
  await params.hub.createDockerSpace(params.spacePlan.space, {
21827
- private: params.spacePlan.visibility === "private",
21682
+ visibility: params.spacePlan.visibility,
21828
21683
  ...params.hardware ? { hardware: params.hardware } : {},
21829
21684
  ...typeof params.sleepTime === "number" ? { sleepTimeSeconds: params.sleepTime } : {}
21830
21685
  });
@@ -22225,7 +22080,7 @@ async function deployLocalBootstrap(plan, opts, runtime, desiredChanged = true,
22225
22080
  await writeSecretEnv(runtime.configRoot, plan.agentName, previousSecrets);
22226
22081
  } else {
22227
22082
  await assertLease();
22228
- await fs16.rm(secretEnvPath(runtime.configRoot, plan.agentName), { force: true });
22083
+ await fs15.rm(secretEnvPath(runtime.configRoot, plan.agentName), { force: true });
22229
22084
  }
22230
22085
  if (previousContainer?.running && previousManifest) {
22231
22086
  await startLocalGateway({ manifest: previousManifest, runtime, pull: false, refresh: true, assertLease });
@@ -22254,7 +22109,7 @@ async function deployLocalBootstrap(plan, opts, runtime, desiredChanged = true,
22254
22109
  }
22255
22110
  if (!previousManifest) {
22256
22111
  await assertLease();
22257
- await fs16.rm(manifestPath(runtime.configRoot, plan.agentName), { force: true });
22112
+ await fs15.rm(manifestPath(runtime.configRoot, plan.agentName), { force: true });
22258
22113
  }
22259
22114
  } catch (rollbackError) {
22260
22115
  throw new AggregateError([error, rollbackError], "local bootstrap and rollback both failed");
@@ -22301,11 +22156,11 @@ async function deploySpaceGateway(params) {
22301
22156
  const assertLease = params.assertLease ?? (async () => void 0);
22302
22157
  if (!params.spacePrepared) {
22303
22158
  runtime.stdout.log(
22304
- params.spaceExists ? `Updating existing Space ${manifest.space}` : `Creating ${params.publicSpace ? "public" : "private"} Space ${manifest.space}`
22159
+ params.spaceExists ? `Updating existing Space ${manifest.space}` : `Creating ${params.visibility ?? "protected"} Space ${manifest.space}`
22305
22160
  );
22306
22161
  await assertLease();
22307
22162
  await hub.createDockerSpace(manifest.space, {
22308
- private: !params.publicSpace,
22163
+ visibility: params.visibility ?? "protected",
22309
22164
  ...params.hardware && !params.spaceExists ? { hardware: params.hardware } : {},
22310
22165
  ...typeof params.sleepTime === "number" ? { sleepTimeSeconds: params.sleepTime } : {}
22311
22166
  });
@@ -22739,7 +22594,7 @@ async function gatewayMigrate(agent, opts, runtime) {
22739
22594
  });
22740
22595
  updated = {
22741
22596
  ...updated,
22742
- spaceVisibility: opts.publicSpace ? "public" : current.spaceVisibility ?? "private",
22597
+ spaceVisibility: opts.publicSpace ? "public" : "protected",
22743
22598
  ...paidHardware.kind === "explicit" ? { spaceHardware: paidHardware.hardware } : {},
22744
22599
  ...typeof paidHardware.sleepTime === "number" ? { spaceSleepTime: paidHardware.sleepTime } : {}
22745
22600
  };
@@ -22770,7 +22625,7 @@ async function gatewayMigrate(agent, opts, runtime) {
22770
22625
  manifest: updated,
22771
22626
  secrets: deploymentSecrets2,
22772
22627
  allowedUsers: me2.name,
22773
- publicSpace: updated.spaceVisibility === "public",
22628
+ visibility: updated.spaceVisibility === "public" ? "public" : "protected",
22774
22629
  spaceExists,
22775
22630
  assertLease,
22776
22631
  ...paidHardware.kind === "explicit" ? { hardware: paidHardware.hardware } : {},
@@ -23609,6 +23464,15 @@ async function doctor(repoId, opts, hub, runtime) {
23609
23464
  }
23610
23465
  return;
23611
23466
  }
23467
+ const visibility = await hub.getSpaceVisibility(repoId);
23468
+ if (visibility !== "protected") {
23469
+ if (fix) {
23470
+ await hub.updateSpaceVisibility(repoId, "protected");
23471
+ fixed.push("set protected Space visibility");
23472
+ } else {
23473
+ issues.push(`Space visibility is ${visibility}; hosted gateways require protected visibility`);
23474
+ }
23475
+ }
23612
23476
  const bucket = variables.get("OPENCLAW_HF_STATE_BUCKET")?.value ?? opts.bucket;
23613
23477
  let signedInUser;
23614
23478
  const currentUsername = async () => {
@@ -23995,7 +23859,7 @@ async function readOptionalTelegramToken(opts, runtime) {
23995
23859
  return direct;
23996
23860
  }
23997
23861
  if (opts.telegramTokenFile) {
23998
- const raw = await fs16.readFile(opts.telegramTokenFile, "utf8");
23862
+ const raw = await fs15.readFile(opts.telegramTokenFile, "utf8");
23999
23863
  const match = raw.match(/(?:^|\n)\s*TELEGRAM_BOT_TOKEN\s*=\s*['"]?([^'"\n]+)['"]?/);
24000
23864
  return (match?.[1] ?? raw.trim()).trim();
24001
23865
  }
@@ -24017,7 +23881,7 @@ async function readOptionalRouterTokenFile(file) {
24017
23881
  if (!file) {
24018
23882
  return void 0;
24019
23883
  }
24020
- const raw = await fs16.readFile(file, "utf8");
23884
+ const raw = await fs15.readFile(file, "utf8");
24021
23885
  const parsed = parseSecretEnv(raw);
24022
23886
  return nonEmpty(parsed.MLCLAW_ROUTER_TOKEN) ?? nonEmpty(parsed.HF_ROUTER_TOKEN) ?? nonEmpty(raw);
24023
23887
  }
@@ -24028,7 +23892,7 @@ async function credentialsStatus(requestedAgent, runtime) {
24028
23892
  if (!metadata) throw new Error("verified HF Broker credential metadata is missing");
24029
23893
  runtime.stdout.log(`Agent: ${manifest.agent}`);
24030
23894
  runtime.stdout.log(`Status: healthy`);
24031
- runtime.stdout.log(`Profile: ${metadata.profileId}`);
23895
+ runtime.stdout.log(`Credential kind: ${metadata.credentialKind}`);
24032
23896
  runtime.stdout.log(`Account: ${metadata.account}`);
24033
23897
  runtime.stdout.log(`Fingerprint: ${metadata.fingerprintSha256.slice(0, 12)}`);
24034
23898
  runtime.stdout.log(`Verified: ${metadata.verifiedAt}`);
@@ -24042,7 +23906,7 @@ async function verifiedStoredBrokerCredential(manifest, runtime) {
24042
23906
  `HF Broker credential metadata is missing; run \`mlclaw credentials repair ${manifest.agent}\` to complete the cutover`
24043
23907
  );
24044
23908
  }
24045
- const verified = await verifyBrokerHfToken(token, manifest.owner, manifest.brokerCredential.account, runtime);
23909
+ const verified = await verifyBrokerHfToken(token, manifest.brokerCredential.account, runtime);
24046
23910
  const observed = brokerCredentialMetadata(token, verified.identity, runtime.now());
24047
23911
  if (observed.fingerprintSha256 !== manifest.brokerCredential.fingerprintSha256) {
24048
23912
  throw new Error(
@@ -24062,14 +23926,14 @@ async function credentialsRepair(requestedAgent, opts, runtime) {
24062
23926
  const suppliedToken = fileToken ?? nonEmpty(runtime.env.MLCLAW_BROKER_HF_TOKEN);
24063
23927
  let replacement;
24064
23928
  if (suppliedToken) {
24065
- replacement = await verifyBrokerHfToken(suppliedToken, manifest.owner, account, runtime);
23929
+ replacement = await verifyBrokerHfToken(suppliedToken, account, runtime);
24066
23930
  } else {
24067
23931
  if (!runtime.prompt.isInteractive()) {
24068
23932
  throw new Error(
24069
23933
  "credential repair requires --broker-hf-token-file, MLCLAW_BROKER_HF_TOKEN, or an interactive terminal"
24070
23934
  );
24071
23935
  }
24072
- replacement = await promptForBrokerHfToken(manifest.owner, account, runtime);
23936
+ replacement = await promptForBrokerHfToken(account, runtime);
24073
23937
  }
24074
23938
  const updatedManifest = {
24075
23939
  ...manifest,
@@ -24240,7 +24104,7 @@ async function resolveBrokerHfToken(params) {
24240
24104
  const configuredToken = fileToken ?? environmentToken ?? nonEmpty(params.preferredToken) ?? nonEmpty(params.existingSecrets.MLCLAW_BROKER_HF_TOKEN);
24241
24105
  if (configuredToken) {
24242
24106
  try {
24243
- return await verifyBrokerHfToken(configuredToken, params.owner, params.hfIdentity.name, params.runtime);
24107
+ return await verifyBrokerHfToken(configuredToken, params.hfIdentity.name, params.runtime);
24244
24108
  } catch (error) {
24245
24109
  if (fileToken || environmentToken || params.preferredToken) throw error;
24246
24110
  if (params.runtime.prompt.isInteractive()) {
@@ -24260,19 +24124,19 @@ async function resolveBrokerHfToken(params) {
24260
24124
  "a dedicated HF Broker credential is required; set MLCLAW_BROKER_HF_TOKEN, pass --broker-hf-token-file, or run bootstrap interactively"
24261
24125
  );
24262
24126
  }
24263
- return await promptForBrokerHfToken(params.owner, params.hfIdentity.name, params.runtime);
24127
+ return await promptForBrokerHfToken(params.hfIdentity.name, params.runtime);
24264
24128
  }
24265
- async function promptForBrokerHfToken(owner, account, runtime) {
24129
+ async function promptForBrokerHfToken(account, runtime) {
24266
24130
  runtime.prompt.note(
24267
- "ML Claw will open a Hugging Face token form with BrokerKit's permissions preselected. Create a dedicated token and paste it here. Your current HF CLI login will not be changed.",
24131
+ "ML Claw will open a Hugging Face fine-grained token form. Choose the permissions and resources this broker may use, create a dedicated token, and paste it here. Your current HF CLI login will not be changed.",
24268
24132
  "HF Broker credential"
24269
24133
  );
24270
- const url = buildBrokerTokenUrl(owner, account);
24134
+ const url = buildBrokerTokenUrl();
24271
24135
  const opened = await runtime.hfCli.openUrl(url);
24272
24136
  runtime.prompt.note(
24273
24137
  `${opened ? "The token form was opened in your browser." : "Open this token form in your browser."}
24274
24138
 
24275
- Name and create the token, then copy it. The URL contains permission names only; it contains no credential. The exact URL is printed below.`,
24139
+ Choose the permissions and resources, name and create the token, then copy it. The URL contains no credential. The exact URL is printed below.`,
24276
24140
  "Create the broker token"
24277
24141
  );
24278
24142
  runtime.stdout.log(url);
@@ -24282,7 +24146,7 @@ Name and create the token, then copy it. The URL contains permission names only;
24282
24146
  "Hugging Face broker token"
24283
24147
  );
24284
24148
  try {
24285
- const verified = await verifyBrokerHfToken(replacement, owner, account, runtime);
24149
+ const verified = await verifyBrokerHfToken(replacement, account, runtime);
24286
24150
  runtime.prompt.note(
24287
24151
  "The dedicated broker token was verified. It will be stored only in ML Claw's trusted broker configuration.",
24288
24152
  "HF Broker credential ready"
@@ -24296,12 +24160,12 @@ Name and create the token, then copy it. The URL contains permission names only;
24296
24160
  }
24297
24161
  }
24298
24162
  }
24299
- async function verifyBrokerHfToken(token, owner, expectedAccount, runtime) {
24163
+ async function verifyBrokerHfToken(token, expectedAccount, runtime) {
24300
24164
  const identity = await runtime.hubFactory(token).whoami();
24301
24165
  if (identity.name !== expectedAccount) {
24302
24166
  throw new Error(`broker token belongs to ${identity.name}, not ${expectedAccount}`);
24303
24167
  }
24304
- const assessment = assessBrokerCredential(identity, owner);
24168
+ const assessment = assessBrokerCredential(identity);
24305
24169
  if (assessment.status !== "sufficient") {
24306
24170
  throw new Error(brokerCredentialAssessmentDetail(assessment));
24307
24171
  }
@@ -24309,17 +24173,14 @@ async function verifyBrokerHfToken(token, owner, expectedAccount, runtime) {
24309
24173
  }
24310
24174
  async function readOptionalBrokerHfTokenFile(file) {
24311
24175
  if (!file) return void 0;
24312
- const raw = await fs16.readFile(file, "utf8");
24176
+ const raw = await fs15.readFile(file, "utf8");
24313
24177
  const parsed = parseSecretEnv(raw);
24314
24178
  const token = nonEmpty(parsed.MLCLAW_BROKER_HF_TOKEN) ?? nonEmpty(raw);
24315
24179
  if (!token) throw new Error("HF Broker token file is empty");
24316
24180
  return token;
24317
24181
  }
24318
24182
  function brokerCredentialAssessmentDetail(assessment) {
24319
- if (assessment.status === "unsupported") return assessment.reason;
24320
- const shown = assessment.missing.slice(0, 8);
24321
- const remaining = assessment.missing.length - shown.length;
24322
- return `The HF Broker credential is missing ${assessment.missing.length} required permission${assessment.missing.length === 1 ? "" : "s"}: ${shown.join(", ")}${remaining > 0 ? `, and ${remaining} more` : ""}`;
24183
+ return assessment.reason;
24323
24184
  }
24324
24185
  function errorMessage(error) {
24325
24186
  return error instanceof Error ? error.message : String(error);