mlclaw 0.4.6 → 0.4.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
@@ -1,8 +1,8 @@
1
1
  ARG OPENCLAW_VERSION=2026.7.1
2
2
  ARG OPENCLAW_BASE_IMAGE=ghcr.io/openclaw/openclaw:${OPENCLAW_VERSION}
3
- ARG BROKERKIT_PLUGIN_VERSION=0.3.2
3
+ ARG BROKERKIT_PLUGIN_VERSION=0.3.3
4
4
  ARG BROKERKIT_VERSION=hf-broker/v0.4.0
5
- ARG MLCLAW_RUNTIME_IMAGE=ghcr.io/huggingface/mlclaw:0.4.6-openclaw-2026.7.1
5
+ ARG MLCLAW_RUNTIME_IMAGE=ghcr.io/huggingface/mlclaw:0.4.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
@@ -5,8 +5,9 @@
5
5
  # ML Claw
6
6
 
7
7
  ML Claw deploys an OpenClaw agent on Hugging Face with durable state in a
8
- private Storage Bucket. The default deployment is a private Hugging Face Space
9
- with a browser gateway protected by Hugging Face OAuth.
8
+ private Storage Bucket. The default deployment is a protected Hugging Face
9
+ Space: its source stays private, its app URL is reachable, and the browser
10
+ gateway is protected by ML Claw's Hugging Face OAuth session.
10
11
 
11
12
  [ml-intern](https://github.com/huggingface/ml-intern) is Hugging Face's
12
13
  open-source ML engineer for reading papers, training models, and shipping
@@ -77,7 +78,7 @@ npx mlclaw@latest bootstrap --name mlclaw
77
78
 
78
79
  This creates:
79
80
 
80
- - a private Docker Space for the browser gateway when the account can host it;
81
+ - a protected Docker Space for the browser gateway when the account can host it;
81
82
  - a private Storage Bucket for OpenClaw state after the Space is accepted;
82
83
  - no explicit Space hardware request unless you pass `--hardware`;
83
84
  - a Docker Space that starts from the prebuilt `ghcr.io/huggingface/mlclaw` image;
@@ -106,7 +107,7 @@ Open the Space, sign in with your Hugging Face account, and use the OpenClaw
106
107
  browser gateway directly. The gateway includes a small ML Claw control link
107
108
  for settings, status, credentials, and sign out.
108
109
 
109
- Create a public Space only when you explicitly want a public demo or template:
110
+ Expose the Space source only when you explicitly want a public demo or template:
110
111
 
111
112
  ```bash
112
113
  npx mlclaw@latest bootstrap --name mlclaw --public-space
@@ -8937,7 +8937,7 @@ function templatePage(config2) {
8937
8937
  <img src="/assets/mlclaw.svg" alt="ML Claw" class="logo">
8938
8938
  <h1>ML Claw</h1>
8939
8939
  <p>Run the local bootstrapper to create a Hugging Face hosted OpenClaw agent for ML workflows.</p>
8940
- <p class="notice">Do not set this up by only clicking Duplicate. The bootstrapper creates the private Space, private Storage Bucket, OAuth settings, secrets, model configuration, and local manifest.</p>
8940
+ <p class="notice">Do not set this up by only clicking Duplicate. The bootstrapper creates the protected Space, private Storage Bucket, OAuth settings, secrets, model configuration, and local manifest.</p>
8941
8941
  <h2>With Node.js</h2>
8942
8942
  <pre><code>npx mlclaw@latest bootstrap --name mlclaw</code></pre>
8943
8943
  <h2>macOS or Linux without Node.js</h2>
@@ -10348,7 +10348,6 @@ function safeErrorClass(error) {
10348
10348
  }
10349
10349
  function delegatedHeaders(c) {
10350
10350
  c.header("access-control-allow-origin", "null");
10351
- c.header("access-control-allow-credentials", "true");
10352
10351
  c.header("cache-control", "no-store");
10353
10352
  c.header("vary", "origin");
10354
10353
  c.header("x-content-type-options", "nosniff");
package/dist/mlclaw.mjs CHANGED
@@ -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`, {
@@ -15375,7 +15386,7 @@ import fs12 from "node:fs";
15375
15386
  import path13 from "node:path";
15376
15387
  import { fileURLToPath as fileURLToPath2 } from "node:url";
15377
15388
  var DEFAULT_OPENCLAW_VERSION = "2026.7.1";
15378
- var DEFAULT_BROKERKIT_PLUGIN_VERSION = "0.3.2";
15389
+ var DEFAULT_BROKERKIT_PLUGIN_VERSION = "0.3.3";
15379
15390
  var DEFAULT_BROKERKIT_VERSION = "hf-broker/v0.4.0";
15380
15391
  var DEFAULT_RUNTIME_IMAGE_REPOSITORY = "ghcr.io/huggingface/mlclaw";
15381
15392
  var PACKAGE_METADATA = readPackageMetadata();
@@ -19848,7 +19859,7 @@ var manifestFields = {
19848
19859
  }).strict().optional(),
19849
19860
  credentialKeySha256: external_exports.string().regex(/^[a-f0-9]{64}$/).optional(),
19850
19861
  tailscaleMode: external_exports.enum(["off", "direct", "serve"]).optional(),
19851
- spaceVisibility: external_exports.enum(["private", "public"]).optional(),
19862
+ spaceVisibility: external_exports.enum(["private", "protected", "public"]).optional(),
19852
19863
  spaceHardware: external_exports.string().min(1).max(128).optional(),
19853
19864
  spaceSleepTime: external_exports.number().int().min(-1).optional(),
19854
19865
  recoveredWithoutCredentialKey: external_exports.boolean().optional(),
@@ -20013,7 +20024,7 @@ var desiredStateSchema = external_exports.object({
20013
20024
  runtimeImage: external_exports.string().min(1).max(1024),
20014
20025
  space: external_exports.object({
20015
20026
  repo: external_exports.string().min(3).max(256),
20016
- visibility: external_exports.enum(["private", "public"]),
20027
+ visibility: external_exports.enum(["private", "protected", "public"]),
20017
20028
  hardware: external_exports.string().min(1).max(128).optional(),
20018
20029
  sleepTime: external_exports.number().int().min(-1).optional()
20019
20030
  }).strict()
@@ -20067,7 +20078,7 @@ function deploymentIdentity(manifest, statePrefix = "openclaw-state") {
20067
20078
  createdAt: manifest.createdAt
20068
20079
  });
20069
20080
  }
20070
- function deploymentDesiredState(manifest, visibility = manifest.spaceVisibility ?? "private") {
20081
+ function deploymentDesiredState(manifest, visibility = manifest.spaceVisibility ?? "protected") {
20071
20082
  return desiredStateSchema.parse({
20072
20083
  schemaVersion: 1,
20073
20084
  deploymentId: manifest.deploymentId,
@@ -20751,7 +20762,7 @@ function createProgram(runtimeOverrides = {}) {
20751
20762
  program2.name("mlclaw").description("Deploy OpenClaw to a Hugging Face Space and private bucket").showHelpAfterError().exitOverride((err) => {
20752
20763
  throw err;
20753
20764
  });
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(
20765
+ 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
20766
  "--router-token-file <path>",
20756
20767
  "File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token"
20757
20768
  ).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 +20813,7 @@ function createProgram(runtimeOverrides = {}) {
20802
20813
  gateway.command("logs").argument("<agent>", "Agent name").option("--tail <lines>", "Number of log lines", parseInteger, 200).action(async (agent, opts) => {
20803
20814
  await gatewayLogs(agent, opts, runtime);
20804
20815
  });
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(
20816
+ 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
20817
  "--router-token-file <path>",
20807
20818
  "File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token"
20808
20819
  ).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 +21364,7 @@ async function reconcileManifest(params) {
21353
21364
  if (currentDesired && currentDesired.deploymentId !== requestedManifest.deploymentId) {
21354
21365
  throw new Error(`bucket ${requestedManifest.bucket} desired state belongs to another deployment`);
21355
21366
  }
21356
- const visibility = params.visibility ?? requestedManifest.spaceVisibility ?? "private";
21367
+ const visibility = params.visibility ?? requestedManifest.spaceVisibility ?? "protected";
21357
21368
  const candidate = deploymentDesiredState(requestedManifest, visibility);
21358
21369
  const sameDesired = currentDesired && JSON.stringify({ ...currentDesired, generation: 0, updatedAt: "" }) === JSON.stringify({ ...candidate, generation: 0, updatedAt: "" });
21359
21370
  if (currentDesired && currentDesired.generation > requestedManifest.desiredGeneration && !sameDesired) {
@@ -21543,7 +21554,7 @@ async function resolveBootstrapPlan(params) {
21543
21554
  spacePlan = {
21544
21555
  space: names.space,
21545
21556
  exists,
21546
- visibility: opts.publicSpace ? "public" : existingManifest?.spaceVisibility ?? currentVisibility ?? "private",
21557
+ visibility: opts.publicSpace ? "public" : "protected",
21547
21558
  ...currentVisibility ? { currentVisibility } : {}
21548
21559
  };
21549
21560
  }
@@ -21824,7 +21835,7 @@ async function createOrAdoptSpace(params) {
21824
21835
  }
21825
21836
  params.runtime.stdout.log(`Creating ${params.spacePlan.visibility} Space ${params.spacePlan.space}`);
21826
21837
  await params.hub.createDockerSpace(params.spacePlan.space, {
21827
- private: params.spacePlan.visibility === "private",
21838
+ visibility: params.spacePlan.visibility,
21828
21839
  ...params.hardware ? { hardware: params.hardware } : {},
21829
21840
  ...typeof params.sleepTime === "number" ? { sleepTimeSeconds: params.sleepTime } : {}
21830
21841
  });
@@ -22301,11 +22312,11 @@ async function deploySpaceGateway(params) {
22301
22312
  const assertLease = params.assertLease ?? (async () => void 0);
22302
22313
  if (!params.spacePrepared) {
22303
22314
  runtime.stdout.log(
22304
- params.spaceExists ? `Updating existing Space ${manifest.space}` : `Creating ${params.publicSpace ? "public" : "private"} Space ${manifest.space}`
22315
+ params.spaceExists ? `Updating existing Space ${manifest.space}` : `Creating ${params.visibility ?? "protected"} Space ${manifest.space}`
22305
22316
  );
22306
22317
  await assertLease();
22307
22318
  await hub.createDockerSpace(manifest.space, {
22308
- private: !params.publicSpace,
22319
+ visibility: params.visibility ?? "protected",
22309
22320
  ...params.hardware && !params.spaceExists ? { hardware: params.hardware } : {},
22310
22321
  ...typeof params.sleepTime === "number" ? { sleepTimeSeconds: params.sleepTime } : {}
22311
22322
  });
@@ -22739,7 +22750,7 @@ async function gatewayMigrate(agent, opts, runtime) {
22739
22750
  });
22740
22751
  updated = {
22741
22752
  ...updated,
22742
- spaceVisibility: opts.publicSpace ? "public" : current.spaceVisibility ?? "private",
22753
+ spaceVisibility: opts.publicSpace ? "public" : "protected",
22743
22754
  ...paidHardware.kind === "explicit" ? { spaceHardware: paidHardware.hardware } : {},
22744
22755
  ...typeof paidHardware.sleepTime === "number" ? { spaceSleepTime: paidHardware.sleepTime } : {}
22745
22756
  };
@@ -22770,7 +22781,7 @@ async function gatewayMigrate(agent, opts, runtime) {
22770
22781
  manifest: updated,
22771
22782
  secrets: deploymentSecrets2,
22772
22783
  allowedUsers: me2.name,
22773
- publicSpace: updated.spaceVisibility === "public",
22784
+ visibility: updated.spaceVisibility === "public" ? "public" : "protected",
22774
22785
  spaceExists,
22775
22786
  assertLease,
22776
22787
  ...paidHardware.kind === "explicit" ? { hardware: paidHardware.hardware } : {},
@@ -23609,6 +23620,15 @@ async function doctor(repoId, opts, hub, runtime) {
23609
23620
  }
23610
23621
  return;
23611
23622
  }
23623
+ const visibility = await hub.getSpaceVisibility(repoId);
23624
+ if (visibility !== "protected") {
23625
+ if (fix) {
23626
+ await hub.updateSpaceVisibility(repoId, "protected");
23627
+ fixed.push("set protected Space visibility");
23628
+ } else {
23629
+ issues.push(`Space visibility is ${visibility}; hosted gateways require protected visibility`);
23630
+ }
23631
+ }
23612
23632
  const bucket = variables.get("OPENCLAW_HF_STATE_BUCKET")?.value ?? opts.bucket;
23613
23633
  let signedInUser;
23614
23634
  const currentUsername = async () => {
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "mlclaw",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "license": "MIT",
5
5
  "config": {
6
6
  "openclawVersion": "2026.7.1",
7
7
  "brokerkitVersion": "hf-broker/v0.4.0",
8
- "brokerkitPluginVersion": "0.3.2",
8
+ "brokerkitPluginVersion": "0.3.3",
9
9
  "runtimeImageRepository": "ghcr.io/huggingface/mlclaw"
10
10
  },
11
11
  "repository": {