superbee 0.4.3-pre.1 → 0.4.3-pre.3

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/superbee.mjs CHANGED
@@ -44,7 +44,7 @@ var __toESM = (mod, isNodeMode, target3) => (target3 = mod != null ? __create(__
44
44
  var define_SUPERBEE_BUILD_IDENTITY_default;
45
45
  var init_define_SUPERBEE_BUILD_IDENTITY = __esm({
46
46
  "<define:__SUPERBEE_BUILD_IDENTITY__>"() {
47
- define_SUPERBEE_BUILD_IDENTITY_default = { schema: "superbee.build-identity.v1", package: { name: "superbee", version: "0.4.3-pre.1" }, source: { commit: "0c5c7f2b2437d3e33a4aa707f13704e9896482a6", dirty: false }, artifact: { channel: "npm-package" }, compatibility_contracts: { skill: 1, hook: 1, mcp: 1 } };
47
+ define_SUPERBEE_BUILD_IDENTITY_default = { schema: "superbee.build-identity.v1", package: { name: "superbee", version: "0.4.3-pre.3" }, source: { commit: "11561dfb62d36f61149e2655e8bebeb08c4e7c9f", dirty: false }, artifact: { channel: "npm-package" }, compatibility_contracts: { skill: 1, hook: 1, mcp: 1 } };
48
48
  }
49
49
  });
50
50
 
@@ -4943,6 +4943,12 @@ async function probeSegment(port, candidate, rel, segment) {
4943
4943
  function hasExact(listing, segment) {
4944
4944
  return listing.some((entry) => entry.name === segment);
4945
4945
  }
4946
+ function freshListings(port) {
4947
+ return async (dir) => {
4948
+ const listing = await port.entries(dir);
4949
+ return listing === null ? null : { has: (name) => hasExact(listing, name) };
4950
+ };
4951
+ }
4946
4952
  async function walkExact(port, rootResolved, segments, rel) {
4947
4953
  let parent = rootResolved;
4948
4954
  for (let index2 = 0; index2 < segments.length; index2++) {
@@ -4973,14 +4979,14 @@ async function recordWalk(port, rootResolved, segments, rel) {
4973
4979
  }
4974
4980
  return recorded;
4975
4981
  }
4976
- async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle) {
4982
+ async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle, listings = freshListings(port)) {
4977
4983
  let parent = rootResolved;
4978
4984
  for (let index2 = 0; index2 < segments.length; index2++) {
4979
4985
  const segment = segments[index2];
4980
4986
  const candidate = path2.join(parent, segment);
4981
- const listing = await port.entries(parent);
4987
+ const listing = await listings(parent);
4982
4988
  if (listing === null) return "absent";
4983
- const listed2 = hasExact(listing, segment);
4989
+ const listed2 = listing.has(segment);
4984
4990
  if (handle !== null && index2 === segments.length - 1) {
4985
4991
  const verdict = classifyLeaf({ listed: listed2, probe: await probeSegment(port, candidate, rel, segment), handle });
4986
4992
  if (verdict === "aliased") throw new FilesystemIdentityAliasError(rel, segment);
@@ -5000,13 +5006,15 @@ function countRestart(restarts, rel) {
5000
5006
  return restarts + 1;
5001
5007
  }
5002
5008
  async function observeExact(port, root, rel, read) {
5009
+ return observeWith(port, path2.resolve(root), rel, read, freshListings(port));
5010
+ }
5011
+ async function observeWith(port, rootResolved, rel, read, listings, onExact) {
5003
5012
  const segments = relSegments(rel);
5004
- const rootResolved = path2.resolve(root);
5005
5013
  const target3 = path2.join(rootResolved, ...segments);
5006
5014
  for (let restarts = 0; ; ) {
5007
5015
  const recorded = await recordWalk(port, rootResolved, segments, rel);
5008
5016
  if (recorded === null) return { state: "absent" };
5009
- const verified2 = await confirmedWalk(port, rootResolved, segments, rel, recorded, null);
5017
+ const verified2 = await confirmedWalk(port, rootResolved, segments, rel, recorded, null, listings);
5010
5018
  if (verified2 === "absent") return { state: "absent" };
5011
5019
  if (verified2 === "restart") {
5012
5020
  restarts = countRestart(restarts, rel);
@@ -5028,11 +5036,14 @@ async function observeExact(port, root, rel, read) {
5028
5036
  try {
5029
5037
  value = await read(opened.handle, target3);
5030
5038
  if (value === null) return { state: "absent" };
5031
- verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened);
5039
+ verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened, listings);
5032
5040
  } finally {
5033
5041
  await port.close(opened.handle);
5034
5042
  }
5035
- if (verdict === "exact") return { state: "exact", value };
5043
+ if (verdict === "exact") {
5044
+ onExact?.(recorded, { dev: opened.dev, ino: opened.ino });
5045
+ return { state: "exact", value };
5046
+ }
5036
5047
  if (verdict === "absent") return { state: "absent" };
5037
5048
  restarts = countRestart(restarts, rel);
5038
5049
  }
@@ -5051,6 +5062,99 @@ async function probeExact(port, root, rel) {
5051
5062
  restarts = countRestart(restarts, rel);
5052
5063
  }
5053
5064
  }
5065
+ function witnessKey(witness) {
5066
+ return `${witness.dev}:${witness.ino}:${witness.mtimeNs}:${witness.ctimeNs}`;
5067
+ }
5068
+ function openObservationPass(port, root, now = Date.now) {
5069
+ const rootResolved = path2.resolve(root);
5070
+ const kept = /* @__PURE__ */ new Map();
5071
+ const reusedVerdicts = [];
5072
+ const fresh = freshListings(port);
5073
+ const witnessOf = port.directoryWitness?.bind(port);
5074
+ const settled = (witness) => {
5075
+ const nowNs = BigInt(Math.floor(now())) * 1000000n;
5076
+ const latest = witness.mtimeNs > witness.ctimeNs ? witness.mtimeNs : witness.ctimeNs;
5077
+ return nowNs - latest >= SETTLED_AFTER_NS;
5078
+ };
5079
+ const listingsFor = () => {
5080
+ let reused = false;
5081
+ if (witnessOf === void 0) return { source: fresh, reused: () => false };
5082
+ const source = async (dir) => {
5083
+ const keep = kept.get(dir);
5084
+ if (keep !== void 0) {
5085
+ const current = await witnessOf(dir);
5086
+ if (current !== null && witnessKey(current) === keep.witness) {
5087
+ reused = true;
5088
+ return keep.names;
5089
+ }
5090
+ kept.delete(dir);
5091
+ }
5092
+ const before = await witnessOf(dir);
5093
+ const listing = await port.entries(dir);
5094
+ if (listing === null) return null;
5095
+ const names = new Set(listing.map((entry) => entry.name));
5096
+ const after = await witnessOf(dir);
5097
+ if (before !== null && after !== null && witnessKey(before) === witnessKey(after) && settled(after)) {
5098
+ kept.set(dir, { witness: witnessKey(after), names });
5099
+ }
5100
+ return names;
5101
+ };
5102
+ return { source, reused: () => reused };
5103
+ };
5104
+ return {
5105
+ async observe(rel, read) {
5106
+ const listings = listingsFor();
5107
+ let exact;
5108
+ let observed;
5109
+ try {
5110
+ observed = await observeWith(port, rootResolved, rel, read, listings.source, (recorded, handle) => {
5111
+ exact = { rel, segments: relSegments(rel), recorded, handle };
5112
+ });
5113
+ } catch (error51) {
5114
+ if (!listings.reused()) throw error51;
5115
+ return observeExact(port, rootResolved, rel, read);
5116
+ }
5117
+ if (!listings.reused()) return observed;
5118
+ if (observed.state === "absent") return observeExact(port, rootResolved, rel, read);
5119
+ if (exact !== void 0) reusedVerdicts.push(exact);
5120
+ return observed;
5121
+ },
5122
+ async finish() {
5123
+ const retry = /* @__PURE__ */ new Set();
5124
+ const endListings = /* @__PURE__ */ new Map();
5125
+ const listedAtEnd = async (dir) => {
5126
+ if (!endListings.has(dir)) {
5127
+ const listing = await port.entries(dir);
5128
+ endListings.set(dir, listing === null ? null : new Set(listing.map((entry) => entry.name)));
5129
+ }
5130
+ return endListings.get(dir);
5131
+ };
5132
+ try {
5133
+ for (const verdict of reusedVerdicts) {
5134
+ if (!await holdsAtEnd(port, rootResolved, verdict, listedAtEnd)) retry.add(verdict.rel);
5135
+ }
5136
+ } finally {
5137
+ kept.clear();
5138
+ reusedVerdicts.length = 0;
5139
+ }
5140
+ return [...retry];
5141
+ }
5142
+ };
5143
+ }
5144
+ async function holdsAtEnd(port, rootResolved, verdict, listedAtEnd) {
5145
+ let parent = rootResolved;
5146
+ for (let index2 = 0; index2 < verdict.segments.length; index2++) {
5147
+ const segment = verdict.segments[index2];
5148
+ const listing = await listedAtEnd(parent);
5149
+ if (listing === null || !listing.has(segment)) return false;
5150
+ const candidate = path2.join(parent, segment);
5151
+ const probed = await port.probe(candidate);
5152
+ const expected = index2 === verdict.segments.length - 1 ? verdict.handle : verdict.recorded[index2];
5153
+ if (probed === null || probed.kind === "symlink" || !sameWitness(probed, expected)) return false;
5154
+ parent = candidate;
5155
+ }
5156
+ return true;
5157
+ }
5054
5158
  function unsupportedLinkRoots(port) {
5055
5159
  let roots = linkUnsupportedRoots.get(port);
5056
5160
  if (!roots) {
@@ -5201,8 +5305,28 @@ function kindOf(stats) {
5201
5305
  if (stats.isFile()) return "file";
5202
5306
  return "other";
5203
5307
  }
5308
+ function directoryWitnessTrusted(platform, filesystemType) {
5309
+ if (platform !== "linux") return true;
5310
+ return filesystemType !== null && LOCAL_LINUX_FILESYSTEMS.has(filesystemType);
5311
+ }
5312
+ function witnessTrust() {
5313
+ const devices = /* @__PURE__ */ new Map();
5314
+ return (dev, dir) => {
5315
+ if (process.platform !== "linux") return Promise.resolve(true);
5316
+ let trusted = devices.get(dev);
5317
+ if (trusted === void 0) {
5318
+ trusted = fs2.statfs(dir).then(
5319
+ (info) => directoryWitnessTrusted("linux", Number(info.type)),
5320
+ () => false
5321
+ );
5322
+ devices.set(dev, trusted);
5323
+ }
5324
+ return trusted;
5325
+ };
5326
+ }
5204
5327
  function createNodeFilesystemIdentityPort(hostPolicy) {
5205
5328
  const policy = captureFilesystemHostPolicy(hostPolicy);
5329
+ const witnessTrustedOn = witnessTrust();
5206
5330
  return Object.freeze({
5207
5331
  isTransientOpenError: policy.isTransientOpenError,
5208
5332
  isReplacementConflict: policy.isReplacementConflict,
@@ -5225,6 +5349,17 @@ function createNodeFilesystemIdentityPort(hostPolicy) {
5225
5349
  throw err;
5226
5350
  }
5227
5351
  },
5352
+ async directoryWitness(dir) {
5353
+ let stats;
5354
+ try {
5355
+ stats = await fs2.stat(dir, { bigint: true });
5356
+ } catch (err) {
5357
+ if (isAbsentPathError(err)) return null;
5358
+ throw err;
5359
+ }
5360
+ if (!await witnessTrustedOn(stats.dev, dir)) return null;
5361
+ return { dev: stats.dev, ino: stats.ino, mtimeNs: stats.mtimeNs, ctimeNs: stats.ctimeNs };
5362
+ },
5228
5363
  async open(target3) {
5229
5364
  const handle = await fs2.open(target3, "r");
5230
5365
  try {
@@ -5279,7 +5414,7 @@ function createNodeFilesystemIdentityPort(hostPolicy) {
5279
5414
  }
5280
5415
  });
5281
5416
  }
5282
- var FilesystemSymlinkEntryError, FilesystemShapeMismatchError, ABSENT_PATH_CODES, MAX_RESTARTS, linkUnsupportedRoots, queues, ABSENT_FILE_CODES;
5417
+ var FilesystemSymlinkEntryError, FilesystemShapeMismatchError, ABSENT_PATH_CODES, MAX_RESTARTS, SETTLED_AFTER_NS, linkUnsupportedRoots, queues, ABSENT_FILE_CODES, LOCAL_LINUX_FILESYSTEMS;
5283
5418
  var init_filesystem_identity = __esm({
5284
5419
  "../core/src/filesystem-identity.ts"() {
5285
5420
  "use strict";
@@ -5310,9 +5445,38 @@ var init_filesystem_identity = __esm({
5310
5445
  };
5311
5446
  ABSENT_PATH_CODES = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]);
5312
5447
  MAX_RESTARTS = 3;
5448
+ SETTLED_AFTER_NS = 3000000000n;
5313
5449
  linkUnsupportedRoots = /* @__PURE__ */ new WeakMap();
5314
5450
  queues = /* @__PURE__ */ new Map();
5315
5451
  ABSENT_FILE_CODES = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR", "EISDIR"]);
5452
+ LOCAL_LINUX_FILESYSTEMS = /* @__PURE__ */ new Set([
5453
+ 61267,
5454
+ // ext2/3/4
5455
+ 1481003842,
5456
+ // xfs
5457
+ 2435016766,
5458
+ // btrfs
5459
+ 16914836,
5460
+ // tmpfs
5461
+ 2240043254,
5462
+ // ramfs
5463
+ 2035054128,
5464
+ // overlayfs
5465
+ 801189825,
5466
+ // zfs
5467
+ 4076150800,
5468
+ // f2fs
5469
+ 3393526350,
5470
+ // bcachefs
5471
+ 19780,
5472
+ // vfat
5473
+ 538032816,
5474
+ // exfat
5475
+ 1936094318,
5476
+ // ntfs3
5477
+ 18475
5478
+ // hfsplus
5479
+ ]);
5316
5480
  }
5317
5481
  });
5318
5482
 
@@ -5627,10 +5791,11 @@ var init_backend = __esm({
5627
5791
  return void 0;
5628
5792
  }
5629
5793
  }
5630
- async #readWithEdition(id, edition) {
5794
+ async #readWithEdition(id, edition, pass) {
5631
5795
  assertSafeConceptId(id);
5632
5796
  const rel = pathFromConceptId(id);
5633
- const observed = await observeExact(this.#port, this.#root, rel, (handle) => readBytes(this.#port, handle));
5797
+ const read = (handle) => readBytes(this.#port, handle);
5798
+ const observed = pass ? await pass.observe(rel, read) : await observeExact(this.#port, this.#root, rel, read);
5634
5799
  if (observed.state === "absent") throw notFound(this.#root, rel);
5635
5800
  const raw = observed.value.toString("utf8");
5636
5801
  const { frontmatter, body } = parseMarkdown(raw, rel, { okfVersion: await edition() });
@@ -5645,7 +5810,12 @@ var init_backend = __esm({
5645
5810
  }
5646
5811
  let editionPromise;
5647
5812
  const edition = () => editionPromise ??= this.#readEdition();
5648
- for (const id of ids) out.push(await this.#readWithEdition(id, edition));
5813
+ const pass = openObservationPass(this.#port, this.#root);
5814
+ for (const id of ids) out.push(await this.#readWithEdition(id, edition, pass));
5815
+ const retry = new Set(await pass.finish());
5816
+ for (let index2 = 0; index2 < ids.length; index2++) {
5817
+ if (retry.has(pathFromConceptId(ids[index2]))) out[index2] = await this.#readWithEdition(ids[index2], edition);
5818
+ }
5649
5819
  return out;
5650
5820
  }
5651
5821
  async write(id, doc2, options = {}) {
@@ -22560,7 +22730,13 @@ async function discoverIssuer(fetchImpl, issuer) {
22560
22730
  throw lastError instanceof CliError ? lastError : new CliError("RUNTIME", `could not read issuer metadata for ${issuer}`);
22561
22731
  }
22562
22732
  async function discoverHosted(fetchImpl, target3) {
22563
- const prm = await fetchJson(fetchImpl, target3.metadataUrl, "protected-resource metadata");
22733
+ let prm;
22734
+ try {
22735
+ prm = await fetchJson(fetchImpl, target3.metadataUrl, "protected-resource metadata");
22736
+ } catch (error51) {
22737
+ if (error51 instanceof CliError && error51.details?.status === 404) throw missingMetadataError(target3);
22738
+ throw error51;
22739
+ }
22564
22740
  const resource = optionalString(prm.resource);
22565
22741
  if (resource === void 0) {
22566
22742
  throw new CliError("RUNTIME", `protected-resource metadata at ${target3.metadataUrl} has no resource`);
@@ -22604,13 +22780,93 @@ function resolveClientId(sources) {
22604
22780
  details
22605
22781
  });
22606
22782
  }
22607
- var DEFAULT_RESOURCE_PATH, PUBLISHED_CLIENT_ID_FIELD, BUILT_IN_CLIENT_IDS, REQUESTED_SCOPE, HTTP_TIMEOUT_MS, CLIENT_ID, MAX_METADATA_BYTES;
22783
+ function parentDomain(hostname5) {
22784
+ if (hostname5.startsWith("[") || IPV4.test(hostname5)) return null;
22785
+ const labels = hostname5.split(".");
22786
+ if (labels.length < 3 || labels.some((label) => label === "")) return null;
22787
+ return labels.slice(1).join(".");
22788
+ }
22789
+ function mayBeWorkspaceOrigin(target3) {
22790
+ const url2 = new URL(target3.origin);
22791
+ return url2.protocol === "https:" && url2.port === "" && target3.audience === `${target3.origin}${DEFAULT_RESOURCE_PATH}` && parentDomain(url2.hostname) !== null;
22792
+ }
22793
+ function trustedPointerTarget(origin, resource) {
22794
+ if (typeof resource !== "string" || resource.length > MAX_POINTER_RESOURCE_LENGTH || resource.includes("@")) return null;
22795
+ let from;
22796
+ let to;
22797
+ try {
22798
+ from = new URL(origin);
22799
+ to = new URL(resource);
22800
+ } catch {
22801
+ return null;
22802
+ }
22803
+ if (from.protocol !== "https:" || to.protocol !== "https:") return null;
22804
+ if (to.username || to.password || to.port !== "" || from.port !== "" || to.search || to.hash) return null;
22805
+ if (to.hostname === from.hostname) return null;
22806
+ const parent = parentDomain(from.hostname);
22807
+ if (parent === null || to.hostname !== `mcp.${parent}`) return null;
22808
+ try {
22809
+ return resolveHostedTarget(resource);
22810
+ } catch {
22811
+ return null;
22812
+ }
22813
+ }
22814
+ function missingMetadataError(target3) {
22815
+ const hostname5 = new URL(target3.origin).hostname;
22816
+ const parent = parentDomain(hostname5);
22817
+ const label = hostname5.split(".")[0];
22818
+ const suggestion = parent !== null && label !== "mcp" && isWorkspaceSlug(label) ? { host: `https://mcp.${parent}`, workspace: label } : null;
22819
+ return new CliError("RUNTIME", `protected-resource metadata at ${target3.metadataUrl} returned HTTP 404`, {
22820
+ details: {
22821
+ status: 404,
22822
+ reason: "no_protected_resource_metadata",
22823
+ host: target3.origin,
22824
+ ...suggestion ? { suggested_host: suggestion.host, suggested_workspace: suggestion.workspace } : {}
22825
+ },
22826
+ help: suggestion ? `${target3.origin} may be a workspace address rather than the sign-in host; if so, re-run with --host ${commandToken(suggestion.host)} --workspace ${commandToken(suggestion.workspace)} (--workspace only where the command takes it)` : `${target3.origin} publishes no Superbee sign-in metadata; check the URL, or ask the host's operator which Superbee host to use`
22827
+ });
22828
+ }
22829
+ async function readWorkspacePointer(fetchImpl, target3) {
22830
+ let pointer;
22831
+ try {
22832
+ pointer = await fetchJson(fetchImpl, `${target3.origin}${WORKSPACE_POINTER_PATH}`, "workspace pointer");
22833
+ } catch {
22834
+ return null;
22835
+ }
22836
+ if (pointer.schema_version !== 1 || !isWorkspaceSlug(pointer.workspace_slug)) return null;
22837
+ if (pointer.workspace_slug !== new URL(target3.origin).hostname.split(".")[0]) return null;
22838
+ const gateway = trustedPointerTarget(target3.origin, pointer.resource);
22839
+ if (gateway === null) return null;
22840
+ return { target: gateway, workspaceSlug: pointer.workspace_slug, requestedOrigin: target3.origin };
22841
+ }
22842
+ async function followWorkspaceOrigin(fetchImpl, target3) {
22843
+ if (!mayBeWorkspaceOrigin(target3)) return null;
22844
+ let status2;
22845
+ try {
22846
+ const response = await fetchImpl(target3.metadataUrl, {
22847
+ headers: { accept: "application/json" },
22848
+ redirect: "error",
22849
+ signal: AbortSignal.timeout(HTTP_TIMEOUT_MS)
22850
+ });
22851
+ status2 = response.status;
22852
+ await response.body?.cancel().catch(() => void 0);
22853
+ } catch {
22854
+ return null;
22855
+ }
22856
+ if (status2 !== 404) return null;
22857
+ const followed = await readWorkspacePointer(fetchImpl, target3);
22858
+ if (followed === null) throw missingMetadataError(target3);
22859
+ return followed;
22860
+ }
22861
+ var DEFAULT_RESOURCE_PATH, PUBLISHED_CLIENT_ID_FIELD, BUILT_IN_CLIENT_IDS, REQUESTED_SCOPE, HTTP_TIMEOUT_MS, CLIENT_ID, MAX_METADATA_BYTES, WORKSPACE_POINTER_PATH, IPV4, MAX_POINTER_RESOURCE_LENGTH;
22608
22862
  var init_discovery = __esm({
22609
22863
  "../cli/src/hosted-auth/discovery.ts"() {
22610
22864
  "use strict";
22611
22865
  init_define_SUPERBEE_BUILD_IDENTITY();
22612
22866
  init_define_SUPERBEE_UPDATE_POLICY();
22613
22867
  init_errors4();
22868
+ init_command_text();
22869
+ init_reference();
22614
22870
  DEFAULT_RESOURCE_PATH = "/mcp";
22615
22871
  PUBLISHED_CLIENT_ID_FIELD = "superbee_cli_client_id";
22616
22872
  BUILT_IN_CLIENT_IDS = Object.freeze({});
@@ -22618,6 +22874,9 @@ var init_discovery = __esm({
22618
22874
  HTTP_TIMEOUT_MS = 1e4;
22619
22875
  CLIENT_ID = /^[\x21-\x7e]{1,256}$/;
22620
22876
  MAX_METADATA_BYTES = 256 * 1024;
22877
+ WORKSPACE_POINTER_PATH = "/.well-known/superbee-workspace";
22878
+ IPV4 = /^\d{1,3}(?:\.\d{1,3}){3}$/;
22879
+ MAX_POINTER_RESOURCE_LENGTH = 2048;
22621
22880
  }
22622
22881
  });
22623
22882
 
@@ -22840,8 +23099,11 @@ __export(session_exports, {
22840
23099
  readPending: () => readPending,
22841
23100
  readSession: () => readSession,
22842
23101
  requireHostedBundleHost: () => requireHostedBundleHost,
23102
+ resolveHostChoice: () => resolveHostChoice,
23103
+ resolveHostChoiceOrNull: () => resolveHostChoiceOrNull,
22843
23104
  resolveHostSelection: () => resolveHostSelection,
22844
23105
  resolveHostSelectionOrNull: () => resolveHostSelectionOrNull,
23106
+ resolveNamedHost: () => resolveNamedHost,
22845
23107
  sessionAccount: () => sessionAccount,
22846
23108
  sessionDirFor: () => sessionDirFor,
22847
23109
  storeForNewSession: () => storeForNewSession,
@@ -22852,6 +23114,8 @@ __export(session_exports, {
22852
23114
  waitForHostedSignIn: () => waitForHostedSignIn,
22853
23115
  waitingSignIns: () => waitingSignIns,
22854
23116
  withSessionLock: () => withSessionLock,
23117
+ workspaceForNamedHost: () => workspaceForNamedHost,
23118
+ workspaceOriginView: () => workspaceOriginView,
22855
23119
  writeDefaultHost: () => writeDefaultHost
22856
23120
  });
22857
23121
  import { mkdir as mkdir2, readdir as readdir3, realpath as realpath2, stat as stat3, unlink as unlink5 } from "node:fs/promises";
@@ -22955,10 +23219,31 @@ function notSignedInError(env = {}) {
22955
23219
  { details: { status: "not_signed_in", reason: "no_host", sign_in_command: command }, help: command }
22956
23220
  );
22957
23221
  }
22958
- async function requireHostedBundleHost(flag, home2, env = {}) {
22959
- const chosen = await hostedBundleHost(flag, home2);
22960
- if (!chosen) throw notSignedInError(env);
22961
- return resolveHostedTarget(chosen);
23222
+ async function requireHostedBundleHost(flag, deps) {
23223
+ if (flag && deps.fetch !== null) return resolveNamedHost(flag, { home: deps.home, fetch: deps.fetch });
23224
+ const chosen = await hostedBundleHost(flag, deps.home);
23225
+ if (!chosen) throw notSignedInError(deps.env);
23226
+ return { target: resolveHostedTarget(chosen), workspaceSlug: null, requestedOrigin: null };
23227
+ }
23228
+ async function resolveNamedHost(host, deps) {
23229
+ const target3 = resolveHostedTarget(host);
23230
+ const plain = { target: target3, workspaceSlug: null, requestedOrigin: null };
23231
+ if (await readSession(deps.home, target3) || await readPending(deps.home, target3)) return plain;
23232
+ const followed = await followWorkspaceOrigin(deps.fetch, target3);
23233
+ if (!followed) return plain;
23234
+ return { target: followed.target, workspaceSlug: followed.workspaceSlug, requestedOrigin: followed.requestedOrigin };
23235
+ }
23236
+ function workspaceOriginView(named) {
23237
+ if (named.requestedOrigin === null || named.workspaceSlug === null) return {};
23238
+ return { host_from: "workspace-origin", requested_host: named.requestedOrigin, workspace_slug: named.workspaceSlug };
23239
+ }
23240
+ function workspaceForNamedHost(named, flag) {
23241
+ if (named.workspaceSlug === null) return flag;
23242
+ if (flag === void 0 || flag === named.workspaceSlug) return named.workspaceSlug;
23243
+ throw new CliError("USAGE", `--host ${commandToken(named.requestedOrigin ?? "")} is the address of workspace '${named.workspaceSlug}', but --workspace names '${flag}'`, {
23244
+ details: { reason: "workspace_conflict", host_workspace: named.workspaceSlug, workspace: flag },
23245
+ help: `drop --workspace to use '${named.workspaceSlug}', or pass the other workspace's own address (or its slug) instead`
23246
+ });
22962
23247
  }
22963
23248
  async function storedSessionHosts(home2) {
22964
23249
  const root = hostedAuthRoot(home2);
@@ -23007,6 +23292,8 @@ function hostSourceText(source) {
23007
23292
  switch (source) {
23008
23293
  case "flag":
23009
23294
  return "--host";
23295
+ case "workspace-origin":
23296
+ return "the gateway the workspace address in --host points to";
23010
23297
  case "last-sign-in":
23011
23298
  return "your last sign-in, the only host with a session";
23012
23299
  case "only-session":
@@ -23015,11 +23302,14 @@ function hostSourceText(source) {
23015
23302
  return "your last sign-in; no session for it now";
23016
23303
  }
23017
23304
  }
23018
- async function hostedWriteHost(flag, home2, retry) {
23305
+ async function hostedWriteHost(flag, home2, retry, fetchImpl) {
23019
23306
  if (flag !== void 0) {
23020
23307
  if (flag.trim() === "") throw new CliError("USAGE", "--host is empty: name the hosted Superbee URL", { help: retry("<url>") });
23021
- return { target: resolveHostedTarget(flag), source: "flag" };
23308
+ if (fetchImpl === null) return { target: resolveHostedTarget(flag), source: "flag", workspaceSlug: null, requestedOrigin: null };
23309
+ const named = await resolveNamedHost(flag, { home: home2, fetch: fetchImpl });
23310
+ return { ...named, source: named.requestedOrigin !== null ? "workspace-origin" : "flag" };
23022
23311
  }
23312
+ const unnamed = { workspaceSlug: null, requestedOrigin: null };
23023
23313
  const remembered = await readDefaultHost(home2);
23024
23314
  const stored = await storedSessionHosts(home2);
23025
23315
  const candidates = new Set(stored);
@@ -23043,22 +23333,30 @@ async function hostedWriteHost(flag, home2, retry) {
23043
23333
  help: `re-run with --host set to the host you mean (one of: ${hosts.join(", ")}); the last sign-in is not used when sessions are held for more than one host or it has none`
23044
23334
  });
23045
23335
  }
23046
- if (rememberedHost) return { target: resolveHostedTarget(rememberedHost), source: stored.length === 0 ? "last-sign-in-signed-out" : "last-sign-in" };
23047
- if (stored.length === 1) return { target: resolveHostedTarget(stored[0]), source: "only-session" };
23336
+ if (rememberedHost) return { target: resolveHostedTarget(rememberedHost), source: stored.length === 0 ? "last-sign-in-signed-out" : "last-sign-in", ...unnamed };
23337
+ if (stored.length === 1) return { target: resolveHostedTarget(stored[0]), source: "only-session", ...unnamed };
23048
23338
  return null;
23049
23339
  }
23340
+ async function resolveHostChoiceOrNull(flag, deps) {
23341
+ const named = flag ?? (deps.env[HOST_ENV] || void 0);
23342
+ if (named !== void 0) return resolveNamedHost(named, deps);
23343
+ const remembered = await readDefaultHost(deps.home);
23344
+ return remembered ? { target: resolveHostedTarget(remembered), workspaceSlug: null, requestedOrigin: null } : null;
23345
+ }
23050
23346
  async function resolveHostSelectionOrNull(flag, deps) {
23051
- const chosen = flag ?? (deps.env[HOST_ENV] || void 0) ?? await readDefaultHost(deps.home) ?? void 0;
23052
- return chosen ? resolveHostedTarget(chosen) : null;
23347
+ return (await resolveHostChoiceOrNull(flag, deps))?.target ?? null;
23053
23348
  }
23054
- async function resolveHostSelection(flag, deps) {
23055
- const target3 = await resolveHostSelectionOrNull(flag, deps);
23056
- if (!target3) {
23349
+ async function resolveHostChoice(flag, deps) {
23350
+ const choice = await resolveHostChoiceOrNull(flag, deps);
23351
+ if (!choice) {
23057
23352
  throw new CliError("USAGE", "no hosted Superbee host selected", {
23058
23353
  help: `pass --host <url> (for example ${String(firstSignInCommand())}) or set ${HOST_ENV}`
23059
23354
  });
23060
23355
  }
23061
- return target3;
23356
+ return choice;
23357
+ }
23358
+ async function resolveHostSelection(flag, deps) {
23359
+ return (await resolveHostChoice(flag, deps)).target;
23062
23360
  }
23063
23361
  function directoryForAccount(home2) {
23064
23362
  return (account) => sessionDirFor(home2, account);
@@ -26304,8 +26602,10 @@ function jsonPure(value) {
26304
26602
  if (typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) return Object.values(value).every(jsonPure);
26305
26603
  return false;
26306
26604
  }
26307
- function wholeDocumentRequest(bundleId, intent, okfVersion) {
26605
+ function wholeDocumentRequest(bundleId, intent, okfVersion, options = {}) {
26308
26606
  const operation = operationOf(intent);
26607
+ const importing = options.mode === "import";
26608
+ if (importing && operation !== "create") throw new WholeDocumentInputError(`'${intent.target}' is a ${operation}, and only a create may carry imported provenance`, "unsupported_operation");
26309
26609
  if (operation === "delete") return { kind: "delete", operationId: OPERATION_IDS.delete, payload: { bundleId, documentId: intent.target, expectedVersion: intent.base } };
26310
26610
  let parsed2;
26311
26611
  try {
@@ -26314,11 +26614,17 @@ function wholeDocumentRequest(bundleId, intent, okfVersion) {
26314
26614
  throw new WholeDocumentInputError(`'${intent.target}' does not parse: ${error51.message}`);
26315
26615
  }
26316
26616
  const frontmatter = {};
26617
+ const carried = [];
26618
+ const dropped = [];
26317
26619
  for (const [key2, value] of Object.entries(parsed2.frontmatter)) {
26318
26620
  if (!HOSTED_MANAGED_FIELDS.has(key2)) frontmatter[key2] = value;
26621
+ else if (importing && IMPORT_CARRIED_FIELDS.includes(key2)) {
26622
+ frontmatter[key2] = value;
26623
+ carried.push(key2);
26624
+ } else if (importing) dropped.push(key2);
26319
26625
  }
26320
26626
  if (!jsonPure(frontmatter)) throw new WholeDocumentInputError(`'${intent.target}' has frontmatter that is not plain JSON`);
26321
- const keys = Object.keys(frontmatter);
26627
+ const keys = Object.keys(frontmatter).filter((key2) => !HOSTED_MANAGED_FIELDS.has(key2));
26322
26628
  if (keys.length > FRONTMATTER_KEY_LIMIT) throw new WholeDocumentInputError(`'${intent.target}' has ${keys.length} frontmatter fields; at most ${FRONTMATTER_KEY_LIMIT} are accepted`);
26323
26629
  if (typeof frontmatter.type !== "string" || frontmatter.type.trim() === "") throw new WholeDocumentInputError(`'${intent.target}' has no type`);
26324
26630
  if (keys.some((key2) => UNSAFE_KEYS.has(key2))) throw new WholeDocumentInputError(`'${intent.target}' names a reserved object key in its frontmatter`);
@@ -26327,7 +26633,8 @@ function wholeDocumentRequest(bundleId, intent, okfVersion) {
26327
26633
  kind: "create",
26328
26634
  operationId: OPERATION_IDS.create,
26329
26635
  payload: { bundleId, documentId: intent.target, expectAbsent: true, frontmatter, body: parsed2.body },
26330
- ...intent.recreates !== void 0 ? { recreates: intent.recreates } : {}
26636
+ ...intent.recreates !== void 0 ? { recreates: intent.recreates } : {},
26637
+ ...importing ? { provenance: { carried, dropped } } : {}
26331
26638
  } : { kind: "replace", operationId: OPERATION_IDS.replace, payload: { ...common, expectedVersion: intent.base } };
26332
26639
  }
26333
26640
  function createWholeDocumentTransport(options) {
@@ -26497,7 +26804,7 @@ function createWholeDocumentTransport(options) {
26497
26804
  }
26498
26805
  };
26499
26806
  }
26500
- var HOSTED_MANAGED_FIELDS, FRONTMATTER_KEY_LIMIT, UNSAFE_KEYS, WHOLE_DOCUMENT_SETTLEMENT, WHOLE_DOCUMENT_BOUNDS, CURRENT_HOST_DOCUMENT_INPUT_BYTES, SYNC_WRITE_ROUTES, OPERATION_IDS, WHOLE_DOCUMENT_INTENT_KINDS, WholeDocumentInputError, UNKNOWN3, encoder2;
26807
+ var HOSTED_MANAGED_FIELDS, IMPORT_CARRIED_FIELDS, IMPORT_DROPPED_FIELDS, FRONTMATTER_KEY_LIMIT, UNSAFE_KEYS, WHOLE_DOCUMENT_SETTLEMENT, WHOLE_DOCUMENT_BOUNDS, CURRENT_HOST_DOCUMENT_INPUT_BYTES, SYNC_WRITE_ROUTES, OPERATION_IDS, WHOLE_DOCUMENT_INTENT_KINDS, WholeDocumentInputError, UNKNOWN3, encoder2;
26501
26808
  var init_whole_document_transport = __esm({
26502
26809
  "../core/src/hosted-transport/whole-document-transport.ts"() {
26503
26810
  "use strict";
@@ -26510,6 +26817,8 @@ var init_whole_document_transport = __esm({
26510
26817
  init_version_transport();
26511
26818
  init_read_adapter();
26512
26819
  HOSTED_MANAGED_FIELDS = /* @__PURE__ */ new Set(["actor", "superbee_updated_by", "generated", "verified", "timestamp", "okf_version"]);
26820
+ IMPORT_CARRIED_FIELDS = Object.freeze(["generated", "timestamp", "actor", "okf_version"]);
26821
+ IMPORT_DROPPED_FIELDS = Object.freeze([...HOSTED_MANAGED_FIELDS].filter((field) => !IMPORT_CARRIED_FIELDS.includes(field)));
26513
26822
  FRONTMATTER_KEY_LIMIT = 32;
26514
26823
  UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
26515
26824
  WHOLE_DOCUMENT_SETTLEMENT = "recorded-only";
@@ -129253,11 +129562,13 @@ async function bundleRetire(argv2, partial2 = {}) {
129253
129562
  if (!typed) {
129254
129563
  throw new CliError("USAGE", `'${positionals[0]}' is not a hosted bundle id or <workspace>/<bundle-id>`, { help: `${cliInvocation()} bundle retire --help` });
129255
129564
  }
129256
- const target3 = await requireHostedBundleHost(values.host, deps.auth.home, deps.auth.env);
129565
+ const named = await requireHostedBundleHost(values.host, deps.auth);
129566
+ const target3 = named.target;
129567
+ const workspace = workspaceForNamedHost(named, values.workspace);
129257
129568
  const host = commandToken(hostArgument(target3));
129258
- const command = (reference2) => commandFragment`${cliInvocation()} bundle retire ${commandToken(reference2)} --host ${host}${values.workspace !== void 0 ? commandFragment` --workspace ${commandToken(values.workspace)}` : commandFragment``}`;
129569
+ const command = (reference2) => commandFragment`${cliInvocation()} bundle retire ${commandToken(reference2)} --host ${host}${workspace !== void 0 ? commandFragment` --workspace ${commandToken(workspace)}` : commandFragment``}`;
129259
129570
  const resume2 = commandFragment`${command(hostedBundleReferenceText(typed))}${values.json ? commandFragment` --json` : commandFragment``}`;
129260
- const account = await connectHostedAccount(target3, { ...values.workspace !== void 0 ? { workspace: values.workspace } : {}, resume: resume2 }, { auth: deps.auth, ...deps.fetch ? { fetch: deps.fetch } : {} });
129571
+ const account = await connectHostedAccount(target3, { ...workspace !== void 0 ? { workspace } : {}, resume: resume2 }, { auth: deps.auth, ...deps.fetch ? { fetch: deps.fetch } : {} });
129261
129572
  const resolved = resolveBundleReference(typed, account, target3, command).reference;
129262
129573
  const client = resolved.slug === null ? account.client : account.client.within(resolved.slug);
129263
129574
  const reference = hostedBundleReferenceText(resolved);
@@ -129627,7 +129938,7 @@ async function catalogInner(argv2, deps) {
129627
129938
  }
129628
129939
  async function listHosted(values, deps, home2, stdout) {
129629
129940
  const auth = deps.auth ?? defaultHostedAuthDeps(home2);
129630
- const target3 = await requireHostedBundleHost(values.host, auth.home, auth.env);
129941
+ const { target: target3 } = await requireHostedBundleHost(values.host, auth);
129631
129942
  const host = hostArgument(target3);
129632
129943
  const resume2 = commandFragment`${cliInvocation()} catalog list --hosted --host ${commandToken(host)}${values.json ? commandFragment` --json` : commandFragment``}`;
129633
129944
  const { client, identity } = await connectHostedAccount(
@@ -130868,9 +131179,9 @@ async function setupHosted(argv2, partial2 = {}) {
130868
131179
  return;
130869
131180
  }
130870
131181
  const mode = resolveMode(values);
130871
- let target3;
131182
+ let choice;
130872
131183
  try {
130873
- target3 = await resolveHostSelection(values.url, auth);
131184
+ choice = await resolveHostChoice(values.url, auth);
130874
131185
  } catch (error51) {
130875
131186
  if (error51 instanceof CliError && error51.code === "USAGE" && values.url === void 0) {
130876
131187
  throw new CliError("USAGE", "no hosted Superbee URL: pass --url", { help: `${cliInvocation()} setup hosted --url <hosted-url>` });
@@ -130880,17 +131191,20 @@ async function setupHosted(argv2, partial2 = {}) {
130880
131191
  }
130881
131192
  throw error51;
130882
131193
  }
131194
+ const target3 = choice.target;
131195
+ const requested = workspaceForNamedHost(choice, values.workspace);
130883
131196
  const host = hostArgument(target3);
130884
- const resume2 = commandFragment`${cliInvocation()} setup hosted --url ${commandToken(host)}${values.workspace !== void 0 ? commandFragment` --workspace ${commandToken(values.workspace)}` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`;
131197
+ const resume2 = commandFragment`${cliInvocation()} setup hosted --url ${commandToken(host)}${requested !== void 0 ? commandFragment` --workspace ${commandToken(requested)}` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`;
130885
131198
  const { identity, workspace: chosen } = await connectHostedAccount(
130886
131199
  target3,
130887
- { workspace: values.workspace, resume: resume2, otherWorkspace: `${cliInvocation()} setup hosted --url ${commandToken(host)} --workspace <id>` },
131200
+ { workspace: requested, resume: resume2, otherWorkspace: `${cliInvocation()} setup hosted --url ${commandToken(host)} --workspace <id>` },
130888
131201
  { auth, ...partial2.fetch ? { fetch: partial2.fetch } : {} }
130889
131202
  );
130890
131203
  await writeDefaultHost(auth.home, host);
130891
131204
  const workspaces = identity.tenantIds;
130892
131205
  const base = {
130893
131206
  host: target3.origin,
131207
+ ...workspaceOriginView(choice),
130894
131208
  signed_in: true,
130895
131209
  principal: identity.principalId,
130896
131210
  workspaces
@@ -131953,7 +132267,8 @@ async function login(argv2, partial2 = {}) {
131953
132267
  const port = parsePort(values.port);
131954
132268
  const clientIdFlag = values["client-id"] || void 0;
131955
132269
  const auth = { ...deps.auth, env: { ...deps.auth.env, [ACCESS_TOKEN_ENV]: void 0 } };
131956
- const target3 = await resolveHostSelection(values.host, auth);
132270
+ const choice = await resolveHostChoice(values.host, auth);
132271
+ const target3 = choice.target;
131957
132272
  const signIn = { ...clientIdFlag ? { clientIdFlag } : {} };
131958
132273
  let token;
131959
132274
  if (values.loopback && await readSession(auth.home, target3)) {
@@ -131993,6 +132308,7 @@ ${url2}
131993
132308
  status: token.source === "sign-in" ? "signed_in" : "already_signed_in",
131994
132309
  host: target3.origin,
131995
132310
  audience: target3.audience,
132311
+ ...workspaceOriginView(choice),
131996
132312
  ...session ? sessionView(session) : {},
131997
132313
  ...deps.auth.env[ACCESS_TOKEN_ENV] ? { env_override: `${ACCESS_TOKEN_ENV} is set and takes precedence for hosted commands` } : {},
131998
132314
  help: [`${cliInvocation()} whoami --host ${commandToken(hostArgument(target3))}`]
@@ -132198,8 +132514,11 @@ and it completes sign-in. --wait polls instead, for at most --timeout seconds
132198
132514
  --loopback signs in through a browser redirect to 127.0.0.1 (PKCE), waits at most --timeout
132199
132515
  seconds, then falls back to device sign-in. The link is printed on stderr.
132200
132516
 
132201
- The host is --host, then ${HOST_ENV}, then the host of the last sign-in. The issuer comes from the
132202
- host's protected-resource metadata. The CLI client id comes from --client-id, then
132517
+ The host is --host, then ${HOST_ENV}, then the host of the last sign-in. A workspace address
132518
+ (<workspace>.<domain>) with no metadata of its own is followed, through its
132519
+ /.well-known/superbee-workspace pointer, to the gateway it names under the same domain; the
132520
+ session is kept for that gateway (reported as host_from: workspace-origin). The issuer comes from
132521
+ the host's protected-resource metadata. The CLI client id comes from --client-id, then
132203
132522
  ${CLIENT_ID_ENV}, then the host's metadata. The refresh token is kept in the OS credential store
132204
132523
  (macOS Keychain, Linux Secret Service); ${CREDENTIAL_STORE_ENV}=file opts in to a 0600 file
132205
132524
  instead. ${ACCESS_TOKEN_ENV} (for CI) is used as given by hosted commands and is never stored.
@@ -132219,10 +132538,12 @@ Options:
132219
132538
  Usage:
132220
132539
  superbee whoami [--host <url>] [--json]
132221
132540
 
132222
- Local and read-only: reports the host, issuer, client, the signed-in subject from the token's
132541
+ Read-only: reports the host, issuer, client, the signed-in subject from the token's
132223
132542
  claims (not yet confirmed by the gateway), scopes, token expiry, where the refresh token is kept,
132224
132543
  and any sign-in waiting on the person. Never prints a token. Not signed in is a successful result,
132225
132544
  including on a first run with no host selected yet (it names the sign-in command).
132545
+ It reads local state only, except that a host with no stored session that turns out to be a
132546
+ workspace's browser address is resolved to its gateway first (its metadata and pointer requests).
132226
132547
 
132227
132548
  Options:
132228
132549
  --host <url> Hosted Superbee URL (default: ${HOST_ENV}, then the last sign-in)
@@ -132915,18 +133236,18 @@ async function release(folderArg, deps, mode) {
132915
133236
  )
132916
133237
  );
132917
133238
  }
132918
- async function checkoutHost(flag, folder, typed, values, home2, env) {
133239
+ async function checkoutHost(flag, folder, typed, values, home2, env, fetchImpl) {
132919
133240
  if (flag === void 0) {
132920
133241
  const real = await realpath11(folder).catch(() => null);
132921
133242
  const bound = real ? await bindingForPath(home2, real).catch(() => null) : null;
132922
- if (bound) return checkoutTarget(bound);
133243
+ if (bound) return { target: checkoutTarget(bound), workspace: values.workspace, origin: {} };
132923
133244
  }
132924
133245
  const retry = (host) => String(
132925
133246
  commandFragment`${cliInvocation()} checkout ${commandToken(hostedBundleReferenceText(typed))} --host ${commandToken(host)} --dir ${commandToken(folder)}${values.workspace !== void 0 ? commandFragment` --workspace ${commandToken(values.workspace)}` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`
132926
133247
  );
132927
- const chosen = await hostedWriteHost(flag, home2, retry);
133248
+ const chosen = await hostedWriteHost(flag, home2, retry, fetchImpl);
132928
133249
  if (!chosen) throw notSignedInError(env);
132929
- return chosen.target;
133250
+ return { target: chosen.target, workspace: workspaceForNamedHost(chosen, values.workspace), origin: workspaceOriginView(chosen) };
132930
133251
  }
132931
133252
  async function checkout(argv2, partial2 = {}) {
132932
133253
  const deps = checkoutDeps(partial2);
@@ -132975,16 +133296,16 @@ async function checkout(argv2, partial2 = {}) {
132975
133296
  const bundleId = typed.bundleId;
132976
133297
  const folder = path53.resolve(deps.cwd, values.dir ?? bundleId);
132977
133298
  assertBundleOutsidePrivateState(folder, deps.auth.home);
132978
- const target3 = await checkoutHost(values.host, folder, typed, values, deps.auth.home, deps.auth.env);
133299
+ const { target: target3, workspace: workspaceFlag2, origin: hostOrigin } = await checkoutHost(values.host, folder, typed, values, deps.auth.home, deps.auth.env, deps.auth.fetch);
132979
133300
  const prefix = syncRoutePrefix(target3);
132980
- const resume2 = commandFragment`${cliInvocation()} checkout ${commandToken(hostedBundleReferenceText(typed))} --host ${commandToken(hostArgument(target3))} --dir ${commandToken(folder)}${values.workspace !== void 0 ? commandFragment` --workspace ${commandToken(values.workspace)}` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`;
133301
+ const resume2 = commandFragment`${cliInvocation()} checkout ${commandToken(hostedBundleReferenceText(typed))} --host ${commandToken(hostArgument(target3))} --dir ${commandToken(folder)}${workspaceFlag2 !== void 0 ? commandFragment` --workspace ${commandToken(workspaceFlag2)}` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`;
132981
133302
  const found = await entryKind(folder);
132982
133303
  if (found === "other") {
132983
133304
  throw new CliError("ALREADY_EXISTS", `${folder} exists and is not a folder`, { help: "pass --dir <new folder>" });
132984
133305
  }
132985
133306
  if (found === "dir") {
132986
133307
  const existing = await bindingForPath(deps.auth.home, await realpath11(folder));
132987
- const sameWorkspace = values.workspace === void 0 || values.workspace === existing?.workspace_slug || values.workspace === existing?.workspace;
133308
+ const sameWorkspace = workspaceFlag2 === void 0 || workspaceFlag2 === existing?.workspace_slug || workspaceFlag2 === existing?.workspace;
132988
133309
  const asked = typed.slug === null && sameWorkspace ? { slug: existing?.workspace_slug ?? null, bundleId } : typed;
132989
133310
  if (existing && bindsBundle(existing, target3, asked)) {
132990
133311
  deps.stdout(render({ checkout: "unchanged", ...bindingView(existing), help: nextSteps(existing.path) }, mode));
@@ -132998,7 +133319,7 @@ async function checkout(argv2, partial2 = {}) {
132998
133319
  });
132999
133320
  }
133000
133321
  await assertStandaloneFolder(folder);
133001
- const { identity, reader, listed: listed2, workspace, reference, definitionWrites, documentInputBytes } = await connectHostedBundle(typed, target3, values.workspace, deps, resume2);
133322
+ const { identity, reader, listed: listed2, workspace, reference, definitionWrites, documentInputBytes } = await connectHostedBundle(typed, target3, workspaceFlag2, deps, resume2);
133002
133323
  const canonical2 = await canonicalFolder(folder);
133003
133324
  let createdFolder = false;
133004
133325
  const placed = /* @__PURE__ */ new Map();
@@ -133104,6 +133425,7 @@ async function checkout(argv2, partial2 = {}) {
133104
133425
  {
133105
133426
  checkout: "created",
133106
133427
  ...bindingView(result3.binding),
133428
+ ...hostOrigin,
133107
133429
  catalog: cataloged,
133108
133430
  documents: result3.documents,
133109
133431
  root_index: result3.root,
@@ -134000,11 +134322,12 @@ async function exportCommand(argv2, partial2 = {}) {
134000
134322
  }
134001
134323
  let source;
134002
134324
  if (reference) {
134325
+ const named2 = await requireHostedBundleHost(values.host, deps.auth);
134003
134326
  source = {
134004
- target: await requireHostedBundleHost(values.host, deps.auth.home, deps.auth.env),
134327
+ target: named2.target,
134005
134328
  bundleId: reference.bundleId,
134006
134329
  slug: reference.slug,
134007
- workspace: values.workspace ?? null,
134330
+ workspace: workspaceForNamedHost(named2, values.workspace) ?? null,
134008
134331
  binding: null
134009
134332
  };
134010
134333
  } else {
@@ -134430,7 +134753,10 @@ function gitVersions(board, id, rel, current, okfVersion, now, documentInputByte
134430
134753
  label: `imported:git/${sha}`,
134431
134754
  author: cleanAuthor(author ?? ""),
134432
134755
  authoredAt: new Date(when).toISOString(),
134433
- frontmatter: parsed2.frontmatter,
134756
+ // An imported version never asserts verification or host attribution, as a current document does not.
134757
+ frontmatter: Object.fromEntries(
134758
+ Object.entries(parsed2.frontmatter).filter(([key2]) => !IMPORT_DROPPED_FIELDS.includes(key2))
134759
+ ),
134434
134760
  body: parsed2.body ?? ""
134435
134761
  });
134436
134762
  }
@@ -134493,6 +134819,10 @@ async function planPublish(folder, options) {
134493
134819
  const blockers = [];
134494
134820
  const extras = {};
134495
134821
  const documentFiles = [];
134822
+ const provenance2 = {
134823
+ carried: Object.fromEntries(IMPORT_CARRIED_FIELDS.map((field) => [field, 0])),
134824
+ dropped: Object.fromEntries(IMPORT_DROPPED_FIELDS.map((field) => [field, 0]))
134825
+ };
134496
134826
  const entries = await walkAll(folder);
134497
134827
  let rootIndex = null;
134498
134828
  try {
@@ -134564,7 +134894,7 @@ async function planPublish(folder, options) {
134564
134894
  }
134565
134895
  let request3;
134566
134896
  try {
134567
- request3 = wholeDocumentRequest("publish", { kind: "document.write", target: id, base: null, content: utf83(bytes) }, okfVersion);
134897
+ request3 = wholeDocumentRequest("publish", { kind: "document.write", target: id, base: null, content: utf83(bytes) }, okfVersion, { mode: "import" });
134568
134898
  } catch (error51) {
134569
134899
  if (error51 instanceof WholeDocumentInputError) {
134570
134900
  blockers.push({ path: entry.rel, reason: "not_sendable", message: error51.message });
@@ -134572,7 +134902,13 @@ async function planPublish(folder, options) {
134572
134902
  }
134573
134903
  throw error51;
134574
134904
  }
134575
- if (request3.kind === "delete") throw new Error(`'${id}' became a delete request`);
134905
+ if (request3.kind !== "create") throw new Error(`'${id}' became a ${request3.kind} request`);
134906
+ if (Buffer.byteLength(JSON.stringify(request3.payload.frontmatter)) > FRONTMATTER_JSON_BYTES) {
134907
+ blockers.push({ path: entry.rel, reason: "too_large", message: `'${id}' has more than the ${FRONTMATTER_JSON_BYTES / 1024} KiB of frontmatter the host stores, counting ${request3.provenance.carried.join(", ")}` });
134908
+ continue;
134909
+ }
134910
+ for (const field of request3.provenance.carried) provenance2.carried[field] = (provenance2.carried[field] ?? 0) + 1;
134911
+ for (const field of request3.provenance.dropped) provenance2.dropped[field] = (provenance2.dropped[field] ?? 0) + 1;
134576
134912
  documents.push({ id, frontmatter: request3.payload.frontmatter, body: request3.payload.body ?? "" });
134577
134913
  documentFiles.push({ id, rel: entry.rel, text: utf83(bytes) });
134578
134914
  }
@@ -134619,7 +134955,7 @@ async function planPublish(folder, options) {
134619
134955
  const draft = { documents, reserved, blobs: blobs2, history };
134620
134956
  const sendPath = publishPath(draft);
134621
134957
  if (sendPath.mode === "staged") blockers.push(...stagedBlockers(draft));
134622
- return { documents, reserved, blobs: blobs2, history, path: sendPath, skipped, blockers, historyPlan, extras };
134958
+ return { documents, reserved, blobs: blobs2, history, path: sendPath, skipped, blockers, historyPlan, extras, provenance: provenance2 };
134623
134959
  }
134624
134960
  function publishPath(plan) {
134625
134961
  const bounds = PUBLISH_BOUNDS;
@@ -135159,7 +135495,15 @@ function summary(plan) {
135159
135495
  reserved_files: plan.reserved.length,
135160
135496
  other_files: plan.blobs.length,
135161
135497
  sent: plan.path.mode === "one-shot" ? "one request" : `staged: ${plan.path.why}; a list of everything, parts of about 1 MiB, each file, then commits until created (resumable)`,
135162
- history: { mode: plan.historyPlan.mode, versions: plan.historyPlan.versions, ...plan.historyPlan.skipped > 0 ? { skipped: plan.historyPlan.skipped } : {}, note: plan.historyPlan.note }
135498
+ history: { mode: plan.historyPlan.mode, versions: plan.historyPlan.versions, ...plan.historyPlan.skipped > 0 ? { skipped: plan.historyPlan.skipped } : {}, note: plan.historyPlan.note },
135499
+ provenance: provenanceOf(plan)
135500
+ };
135501
+ }
135502
+ function provenanceOf(plan) {
135503
+ return {
135504
+ carried: plan.provenance.carried,
135505
+ dropped: plan.provenance.dropped,
135506
+ note: "provenance travels as each file states it (a claim, not a verification); verification events and the last-editor attribution stay in the folder, and the host attributes the creation to you"
135163
135507
  };
135164
135508
  }
135165
135509
  function createRefusal(code3, message, context) {
@@ -135351,15 +135695,17 @@ async function publish(argv2, partial2 = {}) {
135351
135695
  });
135352
135696
  }
135353
135697
  const withHistory = values["with-history"] === true;
135354
- const yesCommandFor = (host) => commandFragment`${cliInvocation()} publish --to hosted${values.dir !== void 0 ? commandFragment` --dir ${commandToken(canonical2)}` : commandFragment``}${host !== null ? commandFragment` --host ${commandToken(host)}` : commandFragment``}${values.workspace !== void 0 ? commandFragment` --workspace ${commandToken(values.workspace)}` : commandFragment``} --bundle-id ${commandToken(bundleId)}${values.name !== void 0 ? commandFragment` --name ${commandToken(name)}` : commandFragment``}${withHistory ? commandFragment` --with-history` : commandFragment``} --yes${values.json ? commandFragment` --json` : commandFragment``}`;
135698
+ let workspaceFlag2 = values.workspace;
135699
+ const yesCommandFor = (host) => commandFragment`${cliInvocation()} publish --to hosted${values.dir !== void 0 ? commandFragment` --dir ${commandToken(canonical2)}` : commandFragment``}${host !== null ? commandFragment` --host ${commandToken(host)}` : commandFragment``}${workspaceFlag2 !== void 0 ? commandFragment` --workspace ${commandToken(workspaceFlag2)}` : commandFragment``} --bundle-id ${commandToken(bundleId)}${values.name !== void 0 ? commandFragment` --name ${commandToken(name)}` : commandFragment``}${withHistory ? commandFragment` --with-history` : commandFragment``} --yes${values.json ? commandFragment` --json` : commandFragment``}`;
135355
135700
  let chosen = null;
135356
135701
  let ambiguous = null;
135357
135702
  try {
135358
- chosen = await hostedWriteHost(values.host, home2, (host) => String(yesCommandFor(host)));
135703
+ chosen = await hostedWriteHost(values.host, home2, (host) => String(yesCommandFor(host)), values.yes ? deps.auth.fetch : null);
135359
135704
  } catch (error51) {
135360
135705
  if (values.yes || !(error51 instanceof CliError) || error51.details?.reason !== "ambiguous_host") throw error51;
135361
135706
  ambiguous = error51;
135362
135707
  }
135708
+ if (chosen) workspaceFlag2 = workspaceForNamedHost(chosen, values.workspace);
135363
135709
  const target3 = chosen?.target ?? null;
135364
135710
  const planFor = (documentInputBytes) => planPublish(canonical2, withHistory ? { history: true, ...board ? { board } : {}, now: deps.auth.now(), documentInputBytes } : { history: false, documentInputBytes });
135365
135711
  let plan = await planFor(CURRENT_HOST_DOCUMENT_INPUT_BYTES);
@@ -135430,7 +135776,7 @@ async function publish(argv2, partial2 = {}) {
135430
135776
  const otherWorkspace = `${cliInvocation()} publish --to hosted --host ${commandToken(bindingHostArgument(target3))} --workspace <id> --bundle-id ${commandToken(bundleId)} --yes`;
135431
135777
  const { client, identity, workspace } = await connectHostedAccount(
135432
135778
  target3,
135433
- { workspace: values.workspace, resume: yesCommand, otherWorkspace, deadlineMs: CREATE_DEADLINE_MS },
135779
+ { workspace: workspaceFlag2, resume: yesCommand, otherWorkspace, deadlineMs: CREATE_DEADLINE_MS },
135434
135780
  { auth: deps.auth, ...deps.fetch ? { fetch: deps.fetch } : {} }
135435
135781
  );
135436
135782
  if (workspace === null) {
@@ -135466,7 +135812,8 @@ async function publish(argv2, partial2 = {}) {
135466
135812
  documents: created.documents ?? plan.documents.length,
135467
135813
  reserved_files: created.reserved ?? plan.reserved.length,
135468
135814
  other_files: created.blobs ?? plan.blobs.length,
135469
- history: created.history ?? { imported: plan.history.length, verified: false }
135815
+ history: created.history ?? { imported: plan.history.length, verified: false },
135816
+ provenance: { carried: plan.provenance.carried, dropped: plan.provenance.dropped }
135470
135817
  },
135471
135818
  folder: canonical2,
135472
135819
  home: facts.home,
@@ -135560,7 +135907,8 @@ async function publish(argv2, partial2 = {}) {
135560
135907
  documents: created.documents ?? plan.documents.length,
135561
135908
  reserved_files: created.reserved ?? plan.reserved.length,
135562
135909
  other_files: created.blobs ?? plan.blobs.length,
135563
- history: created.history ?? { imported: plan.history.length, verified: false }
135910
+ history: created.history ?? { imported: plan.history.length, verified: false },
135911
+ provenance: { carried: plan.provenance.carried, dropped: plan.provenance.dropped }
135564
135912
  },
135565
135913
  folder: canonical2,
135566
135914
  home: "hosted",
@@ -135629,6 +135977,10 @@ Without --yes, previews only, with no network: what travels (documents, reserved
135629
135977
  files), what stays (dot-files, links), how it is sent, every bound the host enforces, the history
135630
135978
  plan, and what will happen to the folder.
135631
135979
 
135980
+ Each document's provenance (generated, timestamp, actor, okf_version) travels as its file states
135981
+ it, a claim rather than a verification; verified and superbee_updated_by never travel. The
135982
+ preview and the receipt count both, per field.
135983
+
135632
135984
  A bundle within one request's bounds (at most 1,000 documents, 100 other files of 1 MB each,
135633
135985
  1,000 earlier versions, 1,500 objects in all, 3 MiB) is sent in one request. A larger one is sent
135634
135986
  staged: a list of everything, then parts of about 1 MiB, then each file, then commits until the
@@ -135739,10 +136091,12 @@ async function accessList(argv2, deps) {
135739
136091
  return;
135740
136092
  }
135741
136093
  const typed = typedReference(positionals[0]);
135742
- const target3 = await requireHostedBundleHost(values.host, deps.auth.home, deps.auth.env);
136094
+ const named = await requireHostedBundleHost(values.host, deps.auth);
136095
+ const target3 = named.target;
136096
+ const workspace = workspaceForNamedHost(named, values.workspace);
135743
136097
  const command = (reference) => commandFragment`${cliInvocation()} access list ${commandToken(reference)}${hostFlag(target3)}`;
135744
- const resume2 = commandFragment`${command(hostedBundleReferenceText(typed))}${workspaceFlag(values.workspace)}${values.json ? commandFragment` --json` : commandFragment``}`;
135745
- const reached = await reach(typed, target3, values.workspace, resume2, deps, command);
136098
+ const resume2 = commandFragment`${command(hostedBundleReferenceText(typed))}${workspaceFlag(workspace)}${values.json ? commandFragment` --json` : commandFragment``}`;
136099
+ const reached = await reach(typed, target3, workspace, resume2, deps, command);
135746
136100
  const answer2 = await postRoute({ client: reached.client, resume: resume2, reference: reached.reference }, "access-list", { bundleId: reached.bundleId });
135747
136101
  if (!answer2.ok) throw accessRefusal(answer2.code, answer2.message, { reference: reached.reference, host: target3, again: resume2 });
135748
136102
  const data = answer2.data;
@@ -135815,8 +136169,10 @@ async function accessChange(action, argv2, deps) {
135815
136169
  throw usage2(wanted === void 0 ? "grant needs --level read or --level write" : `'${wanted}' is not a level: read or write`);
135816
136170
  }
135817
136171
  const mode = resolveMode(values);
135818
- const target3 = await requireHostedBundleHost(values.host, deps.auth.home, deps.auth.env);
135819
- const command = (reference) => commandFragment`${cliInvocation()} access ${commandToken(action)} ${commandToken(reference)} ${commandToken(person)}${action === "grant" ? commandFragment` --level ${commandToken(wanted)}` : commandFragment``}${hostFlag(target3)}${workspaceFlag(values.workspace)} --yes`;
136172
+ const named = await requireHostedBundleHost(values.host, { ...deps.auth, fetch: values.yes ? deps.auth.fetch : null });
136173
+ const target3 = named.target;
136174
+ const workspace = workspaceForNamedHost(named, values.workspace);
136175
+ const command = (reference) => commandFragment`${cliInvocation()} access ${commandToken(action)} ${commandToken(reference)} ${commandToken(person)}${action === "grant" ? commandFragment` --level ${commandToken(wanted)}` : commandFragment``}${hostFlag(target3)}${workspaceFlag(workspace)} --yes`;
135820
136176
  const typedText = hostedBundleReferenceText(typed);
135821
136177
  const yesCommand = commandFragment`${command(typedText)}${values.json ? commandFragment` --json` : commandFragment``}`;
135822
136178
  if (!values.yes) {
@@ -135829,7 +136185,7 @@ async function accessChange(action, argv2, deps) {
135829
136185
  person,
135830
136186
  ...action === "grant" ? { level: wanted } : {},
135831
136187
  host: target3.origin,
135832
- ...values.workspace !== void 0 ? { workspace: values.workspace } : {},
136188
+ ...workspace !== void 0 ? { workspace } : {},
135833
136189
  will: action === "grant" ? `give ${person} ${wanted} access to '${typedText}' (or change their level to ${wanted}); they must already be a member of the workspace (invite them from the Members page in the Superbee app first)` : `take ${person}'s access to '${typedText}' away; they stay a member of the workspace`,
135834
136190
  needs: "a workspace admin, granting no more than your own level on the bundle",
135835
136191
  network: "none (preview)",
@@ -135840,7 +136196,7 @@ async function accessChange(action, argv2, deps) {
135840
136196
  );
135841
136197
  return;
135842
136198
  }
135843
- const reached = await reach(typed, target3, values.workspace, yesCommand, deps, (reference) => command(reference));
136199
+ const reached = await reach(typed, target3, workspace, yesCommand, deps, (reference) => command(reference));
135844
136200
  const route = action === "grant" ? "access-grant" : "access-revoke";
135845
136201
  const home2 = deps.auth.home;
135846
136202
  const requestId2 = await accessRequestId(home2, target3.origin, reached.reference, person, action === "grant" ? `grant:${wanted}` : "revoke", deps.auth.now());