@clawos-dev/clawd 0.2.102 → 0.2.103

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.
Files changed (2) hide show
  1. package/dist/cli.cjs +69 -20
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -5367,6 +5367,20 @@ var init_received_capability = __esm({
5367
5367
  });
5368
5368
 
5369
5369
  // ../protocol/src/extension.ts
5370
+ function isAllowedHostedUrl(raw) {
5371
+ let u;
5372
+ try {
5373
+ u = new URL(raw);
5374
+ } catch {
5375
+ return false;
5376
+ }
5377
+ if (u.protocol === "https:") return true;
5378
+ if (u.protocol === "http:" && LOCALHOST_HOSTS.has(u.hostname)) return true;
5379
+ return false;
5380
+ }
5381
+ function manifestMode(m2) {
5382
+ return m2.entry?.url ? "hosted" : "local";
5383
+ }
5370
5384
  function ownerNamespace(ownerPrincipalId) {
5371
5385
  let h = 2166136261;
5372
5386
  for (let i = 0; i < ownerPrincipalId.length; i++) {
@@ -5408,7 +5422,7 @@ function parseOrThrow(v2) {
5408
5422
  const [a, b2, c] = v2.split(".").map((p2) => parseInt(p2, 10));
5409
5423
  return [a, b2, c];
5410
5424
  }
5411
- var EXT_ID_REGEX, ExtensionStateSchema, ExtensionManifestSchema, ExtensionRecordSchema, PublishedSnapshotSchema, ChannelRefSchema, SourceRefSchema, PublishedExtensionRecordSchema, PublishCheckSchema, PublishStatusResultSchema;
5425
+ var EXT_ID_REGEX, ExtensionStateSchema, LOCALHOST_HOSTS, ExtensionManifestSchema, ExtensionTargetSchema, ExtensionRecordSchema, PublishedSnapshotSchema, ChannelRefSchema, SourceRefSchema, PublishedExtensionRecordSchema, PublishCheckSchema, PublishStatusResultSchema;
5412
5426
  var init_extension = __esm({
5413
5427
  "../protocol/src/extension.ts"() {
5414
5428
  "use strict";
@@ -5421,18 +5435,38 @@ var init_extension = __esm({
5421
5435
  "crashed",
5422
5436
  "invalid"
5423
5437
  ]);
5438
+ LOCALHOST_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
5424
5439
  ExtensionManifestSchema = external_exports.object({
5425
5440
  id: external_exports.string().regex(EXT_ID_REGEX),
5426
5441
  name: external_exports.string().min(1),
5427
5442
  version: external_exports.string().min(1),
5428
5443
  apiVersion: external_exports.literal("1"),
5444
+ runtime: external_exports.object({ startCommand: external_exports.string().min(1) }).passthrough().optional(),
5429
5445
  entry: external_exports.object({
5430
- ui: external_exports.string().min(1).optional()
5431
- }).strict().optional(),
5432
- runtime: external_exports.object({
5433
- startCommand: external_exports.string().min(1)
5434
- }).passthrough()
5435
- }).passthrough();
5446
+ url: external_exports.string().url().refine(isAllowedHostedUrl, {
5447
+ message: "INVALID_URL_SCHEME: only https or http://localhost is allowed"
5448
+ })
5449
+ }).strict().optional()
5450
+ }).passthrough().superRefine((m2, ctx) => {
5451
+ const hasRuntime = !!m2.runtime;
5452
+ const hasUrl = !!m2.entry?.url;
5453
+ if (hasRuntime && hasUrl) {
5454
+ ctx.addIssue({
5455
+ code: external_exports.ZodIssueCode.custom,
5456
+ message: "INVALID_MANIFEST: entry.url and runtime cannot coexist"
5457
+ });
5458
+ }
5459
+ if (!hasRuntime && !hasUrl) {
5460
+ ctx.addIssue({
5461
+ code: external_exports.ZodIssueCode.custom,
5462
+ message: "INVALID_MANIFEST: must have either entry.url or runtime"
5463
+ });
5464
+ }
5465
+ });
5466
+ ExtensionTargetSchema = external_exports.discriminatedUnion("kind", [
5467
+ external_exports.object({ kind: external_exports.literal("local"), port: external_exports.number().int().min(1).max(65535) }),
5468
+ external_exports.object({ kind: external_exports.literal("hosted"), url: external_exports.string().url() })
5469
+ ]);
5436
5470
  ExtensionRecordSchema = external_exports.discriminatedUnion("state", [
5437
5471
  external_exports.object({
5438
5472
  extId: external_exports.string(),
@@ -5448,7 +5482,7 @@ var init_extension = __esm({
5448
5482
  extId: external_exports.string(),
5449
5483
  manifest: ExtensionManifestSchema,
5450
5484
  state: external_exports.literal("running"),
5451
- port: external_exports.number().int().min(1).max(65535)
5485
+ target: ExtensionTargetSchema
5452
5486
  }),
5453
5487
  external_exports.object({
5454
5488
  extId: external_exports.string(),
@@ -37791,12 +37825,6 @@ async function importZip(buf, root) {
37791
37825
  } catch (e) {
37792
37826
  throw new ImportError("INVALID_MANIFEST", `manifest.json: ${e.message}`);
37793
37827
  }
37794
- if (manifestJson && typeof manifestJson === "object" && "entry" in manifestJson && manifestJson.entry?.url !== void 0) {
37795
- throw new ImportError(
37796
- "REMOTE_NOT_SUPPORTED",
37797
- "entry.url (remote mode) is not supported in v1"
37798
- );
37799
- }
37800
37828
  const result = ExtensionManifestSchema.safeParse(manifestJson);
37801
37829
  if (!result.success) {
37802
37830
  throw new ImportError(
@@ -37805,6 +37833,16 @@ async function importZip(buf, root) {
37805
37833
  );
37806
37834
  }
37807
37835
  const manifest = result.data;
37836
+ if (manifestMode(manifest) === "hosted") {
37837
+ const filenames = Object.keys(zip.files).filter((n) => !zip.files[n].dir);
37838
+ const extras = filenames.filter((n) => n !== "manifest.json");
37839
+ if (extras.length > 0) {
37840
+ throw new ImportError(
37841
+ "HOSTED_ZIP_EXTRA_FILES",
37842
+ `hosted extension may only contain manifest.json (extra: ${extras.join(", ")})`
37843
+ );
37844
+ }
37845
+ }
37808
37846
  const destDir = import_node_path19.default.join(root, manifest.id);
37809
37847
  let destExists = false;
37810
37848
  try {
@@ -40963,10 +41001,17 @@ function pickExtId(frame) {
40963
41001
  }
40964
41002
  function composeState(rec, running, crashed, getPort) {
40965
41003
  if (rec.state === "invalid") return rec;
41004
+ if (manifestMode(rec.manifest) === "hosted") {
41005
+ return {
41006
+ ...rec,
41007
+ state: "running",
41008
+ target: { kind: "hosted", url: rec.manifest.entry.url }
41009
+ };
41010
+ }
40966
41011
  if (running.has(rec.extId)) {
40967
41012
  const port = getPort(rec.extId);
40968
41013
  if (port == null) return rec;
40969
- return { ...rec, state: "running", port };
41014
+ return { ...rec, state: "running", target: { kind: "local", port } };
40970
41015
  }
40971
41016
  if (crashed.has(rec.extId)) return { ...rec, state: "crashed" };
40972
41017
  return rec;
@@ -40988,8 +41033,8 @@ function buildExtensionHandlers(deps) {
40988
41033
  const open = async (frame, _client, ctx) => {
40989
41034
  assertOwner(ctx);
40990
41035
  const extId = pickExtId(frame);
40991
- const { port } = await deps.runtime.open(extId);
40992
- return { response: { port } };
41036
+ const target = await deps.runtime.open(extId);
41037
+ return { response: target };
40993
41038
  };
40994
41039
  const close = async (frame, _client, ctx) => {
40995
41040
  assertOwner(ctx);
@@ -41539,16 +41584,20 @@ var Runtime = class {
41539
41584
  }
41540
41585
  async open(extId) {
41541
41586
  const existing = this.handles.get(extId);
41542
- if (existing) return { port: existing.port };
41587
+ if (existing) return { kind: "local", port: existing.port };
41543
41588
  const records = await loadAll(this.root);
41544
41589
  const rec = records.find((r) => r.extId === extId);
41545
41590
  if (!rec) throw new RuntimeError("NOT_FOUND", `extension ${extId} not installed`);
41546
41591
  if (rec.state === "invalid")
41547
41592
  throw new RuntimeError("INVALID_MANIFEST", rec.invalidReason);
41593
+ if (manifestMode(rec.manifest) === "hosted") {
41594
+ return { kind: "hosted", url: rec.manifest.entry.url };
41595
+ }
41548
41596
  const port = await this.allocator.allocate().catch(() => {
41549
41597
  throw new RuntimeError("PORT_EXHAUSTED", "no free port in configured range");
41550
41598
  });
41551
- const cmd = rec.manifest.runtime.startCommand.replace(
41599
+ const startCommand = rec.manifest.runtime.startCommand;
41600
+ const cmd = startCommand.replace(
41552
41601
  /\$CLAWOS_EXT_PORT/g,
41553
41602
  String(port)
41554
41603
  );
@@ -41586,7 +41635,7 @@ var Runtime = class {
41586
41635
  try {
41587
41636
  await this.waitForHealthz(port, () => earlyExit, handle);
41588
41637
  this.crashed.delete(extId);
41589
- return { port };
41638
+ return { kind: "local", port };
41590
41639
  } catch (e) {
41591
41640
  if (this.handles.get(extId) === handle) {
41592
41641
  this.handles.delete(extId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.102",
3
+ "version": "0.2.103",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",