superbee 0.4.3-pre.6 → 0.4.3-pre.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/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.6" }, source: { commit: "e4dbff30e3806cbcb70d658e41f3a29d46d069c8", 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.8" }, source: { commit: "9d37b0a82d04092a95ebb2fd95d9faf93964d384", dirty: false }, artifact: { channel: "npm-package" }, compatibility_contracts: { skill: 1, hook: 1, mcp: 1 } };
48
48
  }
49
49
  });
50
50
 
@@ -27545,7 +27545,7 @@ var init_whole_document_transport = __esm({
27545
27545
  init_version_transport();
27546
27546
  init_read_adapter();
27547
27547
  HOSTED_MANAGED_FIELDS = /* @__PURE__ */ new Set(["actor", "superbee_updated_by", "generated", "verified", "timestamp", "okf_version"]);
27548
- IMPORT_CARRIED_FIELDS = Object.freeze(["generated", "timestamp", "actor", "okf_version"]);
27548
+ IMPORT_CARRIED_FIELDS = Object.freeze(["generated", "timestamp", "actor", "okf_version", "superbee_updated_by", "verified"]);
27549
27549
  IMPORT_DROPPED_FIELDS = Object.freeze([...HOSTED_MANAGED_FIELDS].filter((field) => !IMPORT_CARRIED_FIELDS.includes(field)));
27550
27550
  FRONTMATTER_KEY_LIMIT = 32;
27551
27551
  UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
@@ -28287,12 +28287,37 @@ async function deleteLocal(local, id, options = {}) {
28287
28287
  }
28288
28288
  }
28289
28289
  async function retireQuietly(backend, mode, target3) {
28290
+ let failed = false, failure3;
28290
28291
  try {
28291
28292
  await retireAcknowledgedBody(backend, mode, target3);
28292
28293
  } catch (error51) {
28293
- const name = error51?.name;
28294
- if (!(error51 instanceof JournalGuardConflict) && !(typeof name === "string" && TRANSIENT_STORAGE_ERRORS.has(name))) throw error51;
28294
+ failed = true;
28295
+ failure3 = error51;
28295
28296
  }
28297
+ try {
28298
+ if (!failed || failure3 instanceof JournalGuardConflict) retirementFailures.get(backend)?.delete(target3);
28299
+ else recordRetirementFailure(backend, target3, failure3);
28300
+ } catch {
28301
+ }
28302
+ }
28303
+ function recordRetirementFailure(backend, target3, error51) {
28304
+ let failures = retirementFailures.get(backend);
28305
+ if (!failures) retirementFailures.set(backend, failures = /* @__PURE__ */ new Map());
28306
+ const previous3 = failures.get(target3);
28307
+ const described = describeRetirementError(error51);
28308
+ failures.set(target3, { target: target3, failures: (previous3?.failures ?? 0) + 1, error: described, since: previous3?.since ?? (/* @__PURE__ */ new Date()).toISOString() });
28309
+ }
28310
+ function describeRetirementError(error51) {
28311
+ let name = "Error", message = "";
28312
+ try {
28313
+ const candidate = error51;
28314
+ if (candidate !== null && typeof candidate === "object") {
28315
+ if (typeof candidate.name === "string" && candidate.name) name = candidate.name;
28316
+ if (typeof candidate.message === "string") message = candidate.message;
28317
+ } else message = String(error51);
28318
+ } catch {
28319
+ }
28320
+ return { name: name.slice(0, 64), message: message.slice(0, RETIREMENT_MESSAGE_CHARS) };
28296
28321
  }
28297
28322
  function conflictResolutionKey(id) {
28298
28323
  return `conflict-resolution:${id}`;
@@ -29055,7 +29080,7 @@ async function reclaimInFlight(local) {
29055
29080
  }
29056
29081
  return reclaimed;
29057
29082
  }
29058
- var BOOTSTRAP_KEY, SYNC_KEY, PULL_KEY, ACKNOWLEDGED_KEY, EMPTY_REGISTRY, UNSETTLED_STATES, DEFAULT_BATCH_SIZE, DEFAULT_CONCURRENCY, MIN_BOUNDED_DELETIONS, COMPOSE_ATTEMPTS, TRANSIENT_STORAGE_ERRORS, ConflictReviewStaleError, BUSY_REFUSAL_CODES, PULL_MARK_ATTEMPTS;
29083
+ var BOOTSTRAP_KEY, SYNC_KEY, PULL_KEY, ACKNOWLEDGED_KEY, EMPTY_REGISTRY, UNSETTLED_STATES, DEFAULT_BATCH_SIZE, DEFAULT_CONCURRENCY, MIN_BOUNDED_DELETIONS, COMPOSE_ATTEMPTS, RETIREMENT_MESSAGE_CHARS, retirementFailures, ConflictReviewStaleError, BUSY_REFUSAL_CODES, PULL_MARK_ATTEMPTS;
29059
29084
  var init_local_bundle = __esm({
29060
29085
  "../browser-local/src/local-bundle.ts"() {
29061
29086
  "use strict";
@@ -29084,7 +29109,8 @@ var init_local_bundle = __esm({
29084
29109
  DEFAULT_CONCURRENCY = 8;
29085
29110
  MIN_BOUNDED_DELETIONS = 8;
29086
29111
  COMPOSE_ATTEMPTS = 3;
29087
- TRANSIENT_STORAGE_ERRORS = /* @__PURE__ */ new Set(["AbortError", "InvalidStateError", "TransactionInactiveError", "UnknownError"]);
29112
+ RETIREMENT_MESSAGE_CHARS = 512;
29113
+ retirementFailures = /* @__PURE__ */ new WeakMap();
29088
29114
  ConflictReviewStaleError = class extends Error {
29089
29115
  constructor() {
29090
29116
  super("The conflict changed since review. Inspect it again before choosing a resolution.");
@@ -88299,17 +88325,16 @@ function monotonicEvolutionBlockers(current, desired, blockers) {
88299
88325
  );
88300
88326
  }
88301
88327
  }
88302
- const currentDeclared = /* @__PURE__ */ new Set([...current.fields.required, ...current.fields.optional]);
88303
88328
  const desiredDeclared = /* @__PURE__ */ new Set([...desired.fields.required, ...desired.fields.optional]);
88304
88329
  for (const [field, desiredValues] of Object.entries(desired.fields.values)) {
88305
88330
  const currentValues = current.fields.values[field];
88306
88331
  if (!currentValues) {
88307
- if (desiredDeclared.has(field) && !currentDeclared.has(field)) continue;
88332
+ if (desiredDeclared.has(field)) continue;
88308
88333
  evolutionBlocker(
88309
88334
  blockers,
88310
88335
  "RECIPE_EVOLUTION_NON_MONOTONIC",
88311
88336
  desired.id,
88312
- `automatic evolution cannot add an enum restriction to '${field}' for '${desired.governs}'; only a field newly declared by the same plan may gain one`,
88337
+ `automatic evolution cannot add an enum restriction to '${field}' for '${desired.governs}'; declare '${field}' in fields.required or fields.optional first`,
88313
88338
  field
88314
88339
  );
88315
88340
  continue;
@@ -88368,6 +88393,20 @@ function monotonicEvolutionBlockers(current, desired, blockers) {
88368
88393
  );
88369
88394
  }
88370
88395
  }
88396
+ function addedFieldRestrictions(current, desired) {
88397
+ const types = /* @__PURE__ */ new Map();
88398
+ for (const [field, type] of Object.entries(desired.fields.types ?? {})) {
88399
+ if (!Object.hasOwn(current.fields.types ?? {}, field)) types.set(field, type);
88400
+ }
88401
+ const currentDeclared = /* @__PURE__ */ new Set([...current.fields.required, ...current.fields.optional]);
88402
+ const values = /* @__PURE__ */ new Map();
88403
+ for (const [field, allowed] of Object.entries(desired.fields.values)) {
88404
+ if (!Object.hasOwn(current.fields.values, field) && currentDeclared.has(field)) {
88405
+ values.set(field, allowed.map((value) => String(value)));
88406
+ }
88407
+ }
88408
+ return { types, values };
88409
+ }
88371
88410
  function addedLinkTypes(current, desired) {
88372
88411
  const currentLinks = current.links ?? {};
88373
88412
  return Object.keys(desired.links ?? {}).filter((linkType) => !Object.hasOwn(currentLinks, linkType));
@@ -88423,6 +88462,7 @@ async function prepareRecipeEvolution(bundle, sourceRecipe) {
88423
88462
  const proofs = [];
88424
88463
  const desiredKinds = /* @__PURE__ */ new Map();
88425
88464
  const addedLinkTexts = /* @__PURE__ */ new Set();
88465
+ const addedRestrictions = /* @__PURE__ */ new Map();
88426
88466
  const skippedConventions = [];
88427
88467
  const installedConventions = await query2(bundle, { prefix: CONVENTIONS_PREFIX, type: "Convention" }, {
88428
88468
  onSkip: (skipped) => skippedConventions.push(skipped)
@@ -88567,6 +88607,7 @@ async function prepareRecipeEvolution(bundle, sourceRecipe) {
88567
88607
  });
88568
88608
  if (!unchanged2 && existing.doc.frontmatter.type === "Convention" && parsedCurrent.ok && parsedCandidate.ok && parsedCurrent.kind.governs === parsedCandidate.kind.governs) {
88569
88609
  monotonicEvolutionBlockers(parsedCurrent.kind, parsedCandidate.kind, blockers);
88610
+ addedRestrictions.set(parsedCandidate.kind.governs, addedFieldRestrictions(parsedCurrent.kind, parsedCandidate.kind));
88570
88611
  for (const linkType of addedLinkTypes(parsedCurrent.kind, parsedCandidate.kind)) addedLinkTexts.add(linkType);
88571
88612
  }
88572
88613
  }
@@ -88651,6 +88692,8 @@ async function prepareRecipeEvolution(bundle, sourceRecipe) {
88651
88692
  );
88652
88693
  }
88653
88694
  for (const kind2 of changingKinds) {
88695
+ const added = addedRestrictions.get(kind2.governs);
88696
+ const violations = /* @__PURE__ */ new Map();
88654
88697
  for (const doc2 of docs) {
88655
88698
  if (String(doc2.frontmatter.type) !== kind2.governs) continue;
88656
88699
  instancesChecked += 1;
@@ -88659,16 +88702,39 @@ async function prepareRecipeEvolution(bundle, sourceRecipe) {
88659
88702
  id: doc2.id,
88660
88703
  current_version: contentVersion(doc2)
88661
88704
  });
88662
- for (const warning of projectKindValidationWarnings(okfVersion, kind2, validateAgainstKind(doc2, kind2))) {
88663
- evolutionBlocker(
88664
- blockers,
88665
- "RECIPE_EVOLUTION_INSTANCE_INVALID",
88666
- doc2.id,
88667
- warning.message,
88668
- warning.field
88669
- );
88705
+ const stored = validateAgainstKind(doc2, kind2);
88706
+ const projected = projectKindValidationWarnings(okfVersion, kind2, stored);
88707
+ for (const [index2, warning] of projected.entries()) {
88708
+ const field = stored[index2].field ?? "";
88709
+ const restriction = warning.code === "KIND_FIELD_TYPE" && added?.types.has(field) ? `fields.types.${field}` : (warning.code === "KIND_FIELD_VALUE" || warning.code === "KIND_FIELD_ARITY") && added?.values.has(field) ? `fields.values.${field}` : void 0;
88710
+ if (restriction === void 0) {
88711
+ evolutionBlocker(
88712
+ blockers,
88713
+ "RECIPE_EVOLUTION_INSTANCE_INVALID",
88714
+ doc2.id,
88715
+ warning.message,
88716
+ warning.field
88717
+ );
88718
+ continue;
88719
+ }
88720
+ const entry = violations.get(restriction) ?? { field, docs: /* @__PURE__ */ new Map() };
88721
+ if (!entry.docs.has(doc2.id)) entry.docs.set(doc2.id, warning.message);
88722
+ violations.set(restriction, entry);
88670
88723
  }
88671
88724
  }
88725
+ for (const [restriction, { field, docs: violating }] of violations) {
88726
+ const ids = [...violating.keys()].sort();
88727
+ const named = ids.slice(0, RESTRICTION_BLOCKER_DOC_CAP).join(", ");
88728
+ const more = ids.length > RESTRICTION_BLOCKER_DOC_CAP ? `, and ${ids.length - RESTRICTION_BLOCKER_DOC_CAP} more` : "";
88729
+ const declared = restriction.startsWith("fields.types.") ? `type '${added.types.get(field)}'` : `allowed values [${added.values.get(field).join(", ")}]`;
88730
+ evolutionBlocker(
88731
+ blockers,
88732
+ "RECIPE_EVOLUTION_RESTRICTION_VIOLATED",
88733
+ kind2.id,
88734
+ `adding ${declared} to '${field}' for '${kind2.governs}' would make ${ids.length} existing document(s) invalid: ${named}${more}; fix them first (e.g. ${ids[0]}: ${violating.get(ids[0])})`,
88735
+ restriction
88736
+ );
88737
+ }
88672
88738
  }
88673
88739
  if (addedLinkTexts.size > 0) {
88674
88740
  const proven = new Set(instanceProofs.map((proof) => proof.id));
@@ -88836,7 +88902,7 @@ async function applyRecipeEvolution(bundle, recipe2, expectedPlanToken, actor) {
88836
88902
  counts: { updated, unchanged: completed.length - updated }
88837
88903
  };
88838
88904
  }
88839
- var RECIPE_EVOLUTION_WRITE_REGISTRY, PRESERVED_ROOT_METADATA, BUNDLE_LOCAL_PLACEMENT;
88905
+ var RECIPE_EVOLUTION_WRITE_REGISTRY, PRESERVED_ROOT_METADATA, BUNDLE_LOCAL_PLACEMENT, RESTRICTION_BLOCKER_DOC_CAP;
88840
88906
  var init_recipe_evolution = __esm({
88841
88907
  "../cli/src/recipe-evolution.ts"() {
88842
88908
  "use strict";
@@ -88849,6 +88915,7 @@ var init_recipe_evolution = __esm({
88849
88915
  RECIPE_EVOLUTION_WRITE_REGISTRY = { kinds: /* @__PURE__ */ new Map(), warnings: [] };
88850
88916
  PRESERVED_ROOT_METADATA = /* @__PURE__ */ new Set(["timestamp", "actor", "generated", "verified", "superbee_updated_by"]);
88851
88917
  BUNDLE_LOCAL_PLACEMENT = /* @__PURE__ */ new Set(["order"]);
88918
+ RESTRICTION_BLOCKER_DOC_CAP = 10;
88852
88919
  }
88853
88920
  });
88854
88921
 
@@ -89036,7 +89103,9 @@ it compares definitions, permits additive declarations only, revalidates existin
89036
89103
  returns one exact apply command. Applying requires that plan's token, recomputes the preflight, and
89037
89104
  writes each changed convention with exact-version CAS. Concurrent non-target changes are detected
89038
89105
  by a postcondition check and reported with completed work. It never replaces existing values,
89039
- active View assets, or artifacts omitted from the source.
89106
+ active View assets, or artifacts omitted from the source. It may add a field type (fields.types) or
89107
+ an enum (fields.values) to a declared field only when every existing instance conforms; otherwise
89108
+ the plan names the violating documents. It never changes or removes a type or an enum.
89040
89109
 
89041
89110
  Options:
89042
89111
  --dir <path> Bundle directory (default: discovered from the cwd)
@@ -134329,9 +134398,806 @@ var init_publish_state = __esm({
134329
134398
  }
134330
134399
  });
134331
134400
 
134332
- // ../cli/src/commands/checkout-adopt.ts
134401
+ // ../cli/src/commands/export.ts
134402
+ import { randomBytes as randomBytes9 } from "node:crypto";
134403
+ import { homedir as homedir39 } from "node:os";
134404
+ import { link as link3, lstat as lstat8, mkdir as mkdir4, open as open4, readdir as readdir8, realpath as realpath11, rename as rename2, rm as rm2, unlink as unlink13 } from "node:fs/promises";
134333
134405
  import path54 from "node:path";
134334
- import { lstat as lstat8, realpath as realpath11 } from "node:fs/promises";
134406
+ import { parseArgs as parseArgs41 } from "node:util";
134407
+ function exportDeps(partial2) {
134408
+ return {
134409
+ stdout: partial2.stdout ?? ((text5) => void process.stdout.write(text5)),
134410
+ auth: partial2.auth ?? defaultHostedAuthDeps(homedir39()),
134411
+ cwd: partial2.cwd ?? process.cwd(),
134412
+ ...partial2.fetch ? { fetch: partial2.fetch } : {}
134413
+ };
134414
+ }
134415
+ async function entryKind(target3) {
134416
+ let info;
134417
+ try {
134418
+ info = await lstat8(target3);
134419
+ } catch (error51) {
134420
+ if (error51.code === "ENOENT") return "absent";
134421
+ throw error51;
134422
+ }
134423
+ if (!info.isDirectory()) return "other";
134424
+ return (await readdir8(target3)).length === 0 ? "empty-dir" : "dir";
134425
+ }
134426
+ function shown(paths) {
134427
+ return [...paths].sort().slice(0, SHOWN);
134428
+ }
134429
+ function refusalCode(body) {
134430
+ const error51 = body?.error;
134431
+ if (typeof error51 === "string") return error51;
134432
+ const code3 = error51?.code;
134433
+ return typeof code3 === "string" ? code3 : void 0;
134434
+ }
134435
+ async function namedClient(source, deps2, resume2) {
134436
+ const { target: target3 } = source;
134437
+ const account = await connectHostedAccount(target3, { ...source.workspace !== null ? { workspace: source.workspace } : {}, resume: resume2, deadlineMs: EXPORT_DEADLINE_MS }, deps2);
134438
+ const { reference } = resolveBundleReference(
134439
+ { slug: source.slug, bundleId: source.bundleId },
134440
+ account,
134441
+ target3,
134442
+ (named) => `${cliInvocation()} export ${commandToken(named)} --host ${commandToken(hostArgument(target3))} --to <folder>`
134443
+ );
134444
+ return { client: reference.slug === null ? account.client : account.client.within(reference.slug), slug: reference.slug };
134445
+ }
134446
+ async function fetchExport(source, deps2, resume2) {
134447
+ const named = source.binding ? null : await namedClient(source, deps2, resume2);
134448
+ const client = named ? named.client : (await connectCheckout(source.binding, { resume: resume2, deadlineMs: EXPORT_DEADLINE_MS }, deps2)).client;
134449
+ const slug = named ? named.slug : source.binding.workspace_slug ?? null;
134450
+ return fetchExportThrough({ client, slug, source, resume: resume2 });
134451
+ }
134452
+ async function fetchExportThrough(request3) {
134453
+ const { source } = request3;
134454
+ const { bundleId: bundleId2, target: target3 } = source;
134455
+ for (let attempt = 1; ; attempt += 1) {
134456
+ const chain = new ExportPageChain();
134457
+ let bytes = 0;
134458
+ let cursor;
134459
+ let moved = false;
134460
+ for (; ; ) {
134461
+ let page;
134462
+ for (let tries = 1; page === void 0; tries += 1) {
134463
+ const answer2 = await exportAnswer(request3, { bundleId: bundleId2, paged: true, ...cursor !== void 0 ? { cursor } : {} });
134464
+ if (answer2.refused === "invalid_input" && cursor === void 0 && attempt === 1) return verified(await readArchive(await wholeAnswer(request3), source, MAX_EXPORT_BYTES), source);
134465
+ if (answer2.refused === "concurrent_change") {
134466
+ moved = true;
134467
+ break;
134468
+ }
134469
+ try {
134470
+ if (answer2.refused !== void 0) throw await exportRefusal(request3, answer2.refused, answer2.status);
134471
+ page = verified(await readArchive(answer2.ok, source, MAX_EXPORT_BYTES - bytes), source, { paged: true });
134472
+ } catch (error51) {
134473
+ const again = error51 instanceof CliError && (error51.details?.reason === "export_incomplete" || answer2.refused === "backend_unavailable" && error51.code === "TRANSIENT");
134474
+ if (!again || tries >= 2) throw error51;
134475
+ await pause2(PAGE_RETRY_MS);
134476
+ }
134477
+ }
134478
+ if (moved) break;
134479
+ bytes += page.bytes;
134480
+ cursor = joining(source, () => chain.add(page));
134481
+ if (cursor === void 0) return joining(source, () => chain.joined());
134482
+ }
134483
+ if (attempt >= PAGED_EXPORT_ATTEMPTS) {
134484
+ throw new CliError("TRANSIENT", `'${bundleId2}' kept changing on ${target3.origin} while it was exported; nothing was written`, {
134485
+ details: { reason: "export_source_changed", bundle_id: bundleId2, host: target3.origin, retryable: true },
134486
+ help: "retry the same command once the bundle is not being edited"
134487
+ });
134488
+ }
134489
+ const base = PAGED_EXPORT_RESTART_MS[attempt - 1];
134490
+ await pause2(Math.round(base / 2 + Math.random() * base / 2));
134491
+ }
134492
+ }
134493
+ async function exportAnswer({ client, source, resume: resume2 }, input) {
134494
+ let answer2;
134495
+ try {
134496
+ answer2 = await client.carrier.stream(`${client.prefix}/export`, input, client.signal);
134497
+ } catch (error51) {
134498
+ throw hostedFailure(error51, source.target, resume2);
134499
+ }
134500
+ if (!answer2.ok) return { refused: refusalCode(answer2.body) ?? "RUNTIME", status: answer2.status };
134501
+ return { ok: answer2.body };
134502
+ }
134503
+ async function wholeAnswer(request3) {
134504
+ const answer2 = await exportAnswer(request3, { bundleId: request3.source.bundleId });
134505
+ if (answer2.refused !== void 0) throw await exportRefusal(request3, answer2.refused, answer2.status);
134506
+ return answer2.ok;
134507
+ }
134508
+ function exportTooLarge(source) {
134509
+ return new CliError("RUNTIME", `${source.target.origin} answered an export larger than ${MAX_EXPORT_BYTES} bytes`, {
134510
+ details: { reason: "export_too_large", host: source.target.origin, bundle_id: source.bundleId, retryable: false, next: "the person exports it with Export bundle in the Superbee app" },
134511
+ help: `${cliInvocation()} whoami --host ${commandToken(hostArgument(source.target))}`
134512
+ });
134513
+ }
134514
+ async function exportRefusal({ client, slug, source, resume: resume2 }, code3, status2) {
134515
+ const { target: target3, bundleId: bundleId2 } = source;
134516
+ if (code3 === "bundle_not_found") {
134517
+ if (source.binding) return await bundleAbsent(source.binding, client);
134518
+ const text5 = hostedBundleReferenceText({ slug, bundleId: bundleId2 });
134519
+ return new CliError("NOT_FOUND", `no hosted bundle '${text5}' is visible to you on ${target3.origin}`, {
134520
+ details: { bundle_id: bundleId2, ...slug !== null ? { reference: text5 } : {}, host: target3.origin },
134521
+ help: hostedListCommand(target3)
134522
+ });
134523
+ }
134524
+ if (code3 === "result_too_large") {
134525
+ return new CliError("FORBIDDEN", `hosted bundle '${bundleId2}' is larger than an export carries`, {
134526
+ details: { reason: "bundle_too_large", bundle_id: bundleId2, host: target3.origin, next: "the person exports it with Export bundle in the Superbee app" },
134527
+ help: `${cliInvocation()} whoami --host ${commandToken(hostArgument(target3))}`
134528
+ });
134529
+ }
134530
+ if (code3 === "validation_failed") {
134531
+ return new CliError("FORBIDDEN", `hosted bundle '${bundleId2}' holds a path an export cannot carry`, {
134532
+ details: { reason: "unexportable_path", bundle_id: bundleId2, host: target3.origin, next: "the person renames the document or file in the Superbee app, then the same command is retried" },
134533
+ help: `${cliInvocation()} whoami --host ${commandToken(hostArgument(target3))}`
134534
+ });
134535
+ }
134536
+ return hostedFailure(new RemoteError(`hosted export answered ${status2}`, code3, status2), target3, resume2);
134537
+ }
134538
+ async function readArchive(body, source, budget) {
134539
+ const { target: target3, bundleId: bundleId2 } = source;
134540
+ const reader = body.getReader();
134541
+ const chunks = [];
134542
+ let size = 0;
134543
+ try {
134544
+ for (; ; ) {
134545
+ const part = await reader.read();
134546
+ if (part.done) break;
134547
+ size += part.value.byteLength;
134548
+ if (size > budget) throw exportTooLarge(source);
134549
+ chunks.push(part.value);
134550
+ }
134551
+ } catch (error51) {
134552
+ if (error51 instanceof CliError) throw error51;
134553
+ throw new CliError("TRANSIENT", `the export of '${bundleId2}' from ${target3.origin} stopped part way; nothing was written`, {
134554
+ details: { reason: "export_incomplete", bundle_id: bundleId2, host: target3.origin, retryable: true },
134555
+ help: "retry the same command"
134556
+ });
134557
+ } finally {
134558
+ void reader.cancel().catch(() => {
134559
+ });
134560
+ }
134561
+ const archive = new Uint8Array(size);
134562
+ let offset = 0;
134563
+ for (const chunk of chunks) {
134564
+ archive.set(chunk, offset);
134565
+ offset += chunk.byteLength;
134566
+ }
134567
+ return archive;
134568
+ }
134569
+ function verified(archive, source, options = {}) {
134570
+ return refusingArchive(source, () => verifyExport(archive, source.bundleId, options));
134571
+ }
134572
+ function joining(source, join19) {
134573
+ return refusingArchive(source, join19);
134574
+ }
134575
+ function refusingArchive(source, verify) {
134576
+ try {
134577
+ return verify();
134578
+ } catch (error51) {
134579
+ if (!(error51 instanceof ExportArchiveError)) throw error51;
134580
+ if (error51.problem === "incomplete") {
134581
+ throw new CliError("TRANSIENT", `the export of '${source.bundleId}' was not completed by the host; nothing was written`, {
134582
+ details: { reason: "export_incomplete", bundle_id: source.bundleId, host: source.target.origin, retryable: true },
134583
+ help: "retry the same command"
134584
+ });
134585
+ }
134586
+ throw new CliError("RUNTIME", `${source.target.origin} answered an export this CLI refuses (${error51.message}); nothing was written`, {
134587
+ details: { reason: `export_${error51.problem}`, bundle_id: source.bundleId, host: source.target.origin, retryable: false },
134588
+ help: "upgrade Superbee (npm install -g superbee); if it persists, report this bundle and reason"
134589
+ });
134590
+ }
134591
+ }
134592
+ async function writeNewFile(file2, bytes) {
134593
+ const handle = await open4(file2, "wx", 420);
134594
+ try {
134595
+ await handle.writeFile(bytes);
134596
+ await handle.sync();
134597
+ } finally {
134598
+ await handle.close();
134599
+ }
134600
+ }
134601
+ async function writeEntries(root, entries) {
134602
+ for (const entry of entries) {
134603
+ const file2 = path54.join(root, ...entry.path.split("/"));
134604
+ await mkdir4(path54.dirname(file2), { recursive: true });
134605
+ await writeNewFile(file2, entry.bytes);
134606
+ }
134607
+ }
134608
+ function gitRun(dir, args) {
134609
+ let result3;
134610
+ try {
134611
+ result3 = runGit(dir, args);
134612
+ } catch (error51) {
134613
+ const missing2 = error51.code === "GIT_MISSING";
134614
+ throw new CliError(missing2 ? "GIT_MISSING" : "RUNTIME", `git could not run (${error51 instanceof Error ? error51.message : String(error51)})`, {
134615
+ details: { reason: missing2 ? "git_missing" : "git_unavailable" },
134616
+ help: "install git, or export without --git"
134617
+ });
134618
+ }
134619
+ if (result3.status !== 0) {
134620
+ throw new CliError("RUNTIME", `git ${args.find((arg) => !arg.startsWith("-") && !arg.includes("=")) ?? ""} failed: ${result3.stderr.trim().split("\n").at(-1) ?? ""}`, {
134621
+ details: { reason: "git_failed" },
134622
+ help: "fix the git error, then retry the same command"
134623
+ });
134624
+ }
134625
+ return result3.stdout.trim();
134626
+ }
134627
+ function commitExport(dir, message, options) {
134628
+ const quiet = ["-c", "core.hooksPath=/dev/null"];
134629
+ gitRun(dir, [...quiet, "init", "-q"]);
134630
+ gitRun(dir, ["symbolic-ref", "HEAD", `refs/heads/${BOARD_BRANCH}`]);
134631
+ const excluded = ["--", ".", `:(exclude)${IN_PLACE_STAGING}`, `:(exclude)${CHECKOUT_MARKER_DIR}`];
134632
+ gitRun(dir, ["add", "-A", ...options.force ? ["--force"] : [], ...excluded]);
134633
+ gitRun(dir, [...quiet, ...identityFlags(dir), "-c", "commit.gpgsign=false", "commit", "-q", "--no-verify", "--allow-empty", "-m", message]);
134634
+ const committed = { branch: BOARD_BRANCH, commit: gitRun(dir, ["rev-parse", "HEAD"]) };
134635
+ if (options.force) return committed;
134636
+ const ignored = gitRun(dir, ["ls-files", "--others", "--ignored", "--exclude-standard", ...excluded]).split("\n").filter(Boolean);
134637
+ return ignored.length === 0 ? committed : { ...committed, ignored: { count: ignored.length, paths: shown(ignored) } };
134638
+ }
134639
+ function commitMessage(source, exported) {
134640
+ return `Export ${source.bundleId} from ${source.target.origin} at revision ${exported.source.revision}
134641
+
134642
+ superbee export, ${exported.exportedAt}: ${exported.counts.documents} documents, ${exported.counts.reserved} reserved files, ${exported.counts.blobs} blobs. History is not included.
134643
+ `;
134644
+ }
134645
+ function stagingName(target3) {
134646
+ return path54.join(path54.dirname(target3), `.${path54.basename(target3)}.superbee-export-${process.pid}-${randomBytes9(6).toString("hex")}.partial`);
134647
+ }
134648
+ function processAlive(pid) {
134649
+ try {
134650
+ process.kill(pid, 0);
134651
+ return true;
134652
+ } catch (error51) {
134653
+ return error51.code === "EPERM";
134654
+ }
134655
+ }
134656
+ async function removeAbandonedStaging(target3) {
134657
+ const prefix = `.${path54.basename(target3)}.superbee-export-`;
134658
+ let removed = 0;
134659
+ let names;
134660
+ try {
134661
+ names = await readdir8(path54.dirname(target3));
134662
+ } catch {
134663
+ return 0;
134664
+ }
134665
+ for (const name of names) {
134666
+ if (!name.startsWith(prefix)) continue;
134667
+ const match = /^(\d+)-[0-9a-f]{12}\.partial$/.exec(name.slice(prefix.length));
134668
+ if (!match) continue;
134669
+ const age = await lstat8(path54.join(path54.dirname(target3), name)).then((info) => Date.now() - info.mtimeMs, () => 0);
134670
+ if (processAlive(Number(match[1])) && age < ABANDONED_AFTER_MS) continue;
134671
+ await rm2(path54.join(path54.dirname(target3), name), { recursive: true, force: true });
134672
+ removed += 1;
134673
+ }
134674
+ return removed;
134675
+ }
134676
+ async function assertStandalone(target3, home2) {
134677
+ const parent = path54.dirname(target3);
134678
+ const help2 = "pass --to <folder> outside any bundle, board or checkout";
134679
+ const checkout2 = await hostedCheckoutAt(parent, home2);
134680
+ if (checkout2) {
134681
+ throw new CliError("FORBIDDEN", `refusing to export inside the hosted checkout at ${checkout2.path}`, { details: { reason: "inside_checkout", enclosing: checkout2.path }, help: help2 });
134682
+ }
134683
+ const enclosing = await findBundleRoot(parent).catch(() => null);
134684
+ if (enclosing) {
134685
+ throw new CliError("FORBIDDEN", `refusing to export inside the local bundle at ${enclosing}`, { details: { reason: "inside_bundle", enclosing }, help: help2 });
134686
+ }
134687
+ const binding = await resolveProjectBinding(parent).catch(() => null);
134688
+ if (binding) {
134689
+ throw new CliError("FORBIDDEN", `refusing to export inside a project bound to a board (${binding.file})`, { details: { reason: "inside_bound_project", binding: binding.file }, help: help2 });
134690
+ }
134691
+ }
134692
+ async function exportToFolder(source, toArg, git2, deps2, mode, resume2) {
134693
+ const requested = path54.resolve(deps2.cwd, toArg);
134694
+ assertBundleOutsidePrivateState(requested, deps2.auth.home);
134695
+ const found = await entryKind(requested);
134696
+ if (found === "other") throw new CliError("ALREADY_EXISTS", `${requested} exists and is not a folder`, { details: { reason: "not_a_folder", folder: requested }, help: "pass --to <new folder>" });
134697
+ if (found === "dir") throw new CliError("ALREADY_EXISTS", `${requested} is not empty`, { details: { reason: "not_empty", folder: requested }, help: "pass --to <new or empty folder>" });
134698
+ await mkdir4(path54.dirname(requested), { recursive: true });
134699
+ const target3 = path54.join(await realpath11(path54.dirname(requested)), path54.basename(requested));
134700
+ assertBundleOutsidePrivateState(target3, deps2.auth.home);
134701
+ await assertStandalone(target3, deps2.auth.home);
134702
+ const exported = await fetchExport(source, deps2, resume2);
134703
+ const abandoned = await removeAbandonedStaging(target3);
134704
+ const staging = stagingName(target3);
134705
+ await mkdir4(staging);
134706
+ let gitResult = null;
134707
+ try {
134708
+ await writeEntries(staging, exported.entries);
134709
+ if (git2) gitResult = commitExport(staging, commitMessage(source, exported), { force: true });
134710
+ const now = await entryKind(target3);
134711
+ if (now === "dir" || now === "other") throw new CliError("ALREADY_EXISTS", `${target3} is no longer empty`, { details: { reason: "not_empty", folder: target3 }, help: "pass --to <new or empty folder>" });
134712
+ try {
134713
+ await rename2(staging, target3);
134714
+ } catch (error51) {
134715
+ const code3 = error51.code;
134716
+ if (code3 === "ENOTEMPTY" || code3 === "EEXIST" || code3 === "ENOTDIR") {
134717
+ throw new CliError("ALREADY_EXISTS", `${target3} is no longer empty`, { details: { reason: "not_empty", folder: target3 }, help: "pass --to <new or empty folder>" });
134718
+ }
134719
+ throw error51;
134720
+ }
134721
+ } catch (error51) {
134722
+ await rm2(staging, { recursive: true, force: true }).catch(() => {
134723
+ });
134724
+ throw error51;
134725
+ }
134726
+ const home2 = await bundleHomeAt(target3, { home: deps2.auth.home });
134727
+ deps2.stdout(
134728
+ render(
134729
+ {
134730
+ export: "created",
134731
+ folder: target3,
134732
+ home: home2.home,
134733
+ bundle_id: source.bundleId,
134734
+ host: source.target.origin,
134735
+ revision: exported.source.revision,
134736
+ exported_at: exported.exportedAt,
134737
+ okf_edition: exported.source.okfEdition,
134738
+ documents: exported.counts.documents,
134739
+ reserved: exported.counts.reserved,
134740
+ blobs: exported.counts.blobs,
134741
+ bytes: exported.bytes,
134742
+ root_index: exported.entries.some((entry) => entry.path === "index.md"),
134743
+ ...gitResult ? { git: gitResult } : {},
134744
+ ...abandoned > 0 ? { removed_abandoned_exports: abandoned } : {},
134745
+ hosted: HOSTED_UNCHANGED,
134746
+ history: NO_HISTORY,
134747
+ help: nextSteps(target3, gitResult !== null)
134748
+ },
134749
+ mode
134750
+ )
134751
+ );
134752
+ }
134753
+ function nextSteps(folder, git2) {
134754
+ const steps = [commandFragment`${cliInvocation()} status --dir ${commandToken(folder)}`];
134755
+ if (git2) steps.push(commandFragment`git -C ${commandToken(folder)} remote add origin <url> && ${cliInvocation()} sync --establish --dir ${commandToken(folder)}`);
134756
+ return steps;
134757
+ }
134758
+ function isJournal(value) {
134759
+ const record6 = value;
134760
+ return record6 !== null && typeof record6 === "object" && record6.schema === JOURNAL_SCHEMA && typeof record6.bundle_id === "string" && typeof record6.host === "string" && typeof record6.audience === "string" && Number.isSafeInteger(record6.revision) && typeof record6.exported_at === "string" && typeof record6.git === "boolean" && Array.isArray(record6.adds) && record6.adds.every((entry) => typeof entry === "string") && Number.isSafeInteger(record6.same) && Array.isArray(record6.kept_local) && record6.kept_local.every((entry) => typeof entry === "string") && Array.isArray(record6.deleted_locally) && record6.deleted_locally.every((entry) => typeof entry === "string") && Number.isSafeInteger(record6.unsent_kept);
134761
+ }
134762
+ async function stagingDir(folder) {
134763
+ const staging = path54.join(folder, IN_PLACE_STAGING);
134764
+ try {
134765
+ if (!(await lstat8(staging)).isDirectory()) return null;
134766
+ return await realpath11(staging) === path54.join(await realpath11(folder), IN_PLACE_STAGING) ? staging : null;
134767
+ } catch {
134768
+ return null;
134769
+ }
134770
+ }
134771
+ async function readJournal(folder) {
134772
+ const staging = await stagingDir(folder);
134773
+ if (!staging) return null;
134774
+ let journal;
134775
+ const read = readRegularFileNoFollowSync(path54.join(staging, JOURNAL));
134776
+ if (read.state !== "present" || read.bytes.byteLength > MAX_JOURNAL_BYTES) return null;
134777
+ try {
134778
+ const value = JSON.parse(read.bytes.toString("utf8"));
134779
+ if (!isJournal(value)) return null;
134780
+ journal = value;
134781
+ } catch {
134782
+ return null;
134783
+ }
134784
+ const marker = readCheckoutMarker(folder);
134785
+ if (!marker || marker.bundle_id !== journal.bundle_id || marker.host !== bindingHostArgument({ origin: journal.host, audience: journal.audience })) return null;
134786
+ return journal;
134787
+ }
134788
+ async function sameBytes(file2, bytes) {
134789
+ const read = readRegularFileNoFollowSync(file2);
134790
+ return read.state === "present" && Buffer.compare(read.bytes, Buffer.from(bytes)) === 0;
134791
+ }
134792
+ async function placementOf(folder, entry) {
134793
+ let info;
134794
+ try {
134795
+ info = await lstat8(path54.join(folder, ...entry.path.split("/")));
134796
+ } catch (error51) {
134797
+ const code3 = error51.code;
134798
+ if (code3 === "ENOENT") return "add";
134799
+ if (code3 === "ENOTDIR") return "kept";
134800
+ throw error51;
134801
+ }
134802
+ if (!info.isFile()) return "kept";
134803
+ return await sameBytes(path54.join(folder, ...entry.path.split("/")), entry.bytes) ? "same" : "kept";
134804
+ }
134805
+ async function placeStaged(folder, staging, relative2) {
134806
+ const final = path54.join(folder, ...relative2.split("/"));
134807
+ const staged = path54.join(staging, "files", ...relative2.split("/"));
134808
+ try {
134809
+ if ((await lstat8(staged)).isFile()) {
134810
+ const stagedParent = await realpath11(path54.dirname(staged));
134811
+ if (!stagedParent.startsWith(`${await realpath11(staging)}${path54.sep}`)) return "kept";
134812
+ } else return "kept";
134813
+ } catch (error51) {
134814
+ if (error51.code !== "ENOENT") return "kept";
134815
+ return await lstat8(final).then((info) => info.isFile(), () => false) ? "same" : "kept";
134816
+ }
134817
+ try {
134818
+ await mkdir4(path54.dirname(final), { recursive: true });
134819
+ const parent = await realpath11(path54.dirname(final));
134820
+ if (parent !== folder && !parent.startsWith(`${folder}${path54.sep}`)) return "kept";
134821
+ } catch {
134822
+ return "kept";
134823
+ }
134824
+ let outcome;
134825
+ try {
134826
+ await link3(staged, final);
134827
+ outcome = "added";
134828
+ } catch (error51) {
134829
+ const code3 = error51.code;
134830
+ if (code3 !== "EEXIST") throw error51;
134831
+ const stagedRead = readRegularFileNoFollowSync(staged);
134832
+ outcome = stagedRead.state === "present" && await sameBytes(final, stagedRead.bytes) ? "same" : "kept";
134833
+ }
134834
+ await unlink13(staged).catch(() => {
134835
+ });
134836
+ return outcome;
134837
+ }
134838
+ async function writeJournal(staging, journal) {
134839
+ const temp = path54.join(staging, `.${JOURNAL}.${randomBytes9(6).toString("hex")}.tmp`);
134840
+ await writeNewFile(temp, Buffer.from(`${JSON.stringify(journal)}
134841
+ `, "utf8"));
134842
+ await rename2(temp, path54.join(staging, JOURNAL));
134843
+ }
134844
+ async function finishInPlace(folder, journal) {
134845
+ const staging = await stagingDir(folder);
134846
+ if (!staging) throw new CliError("RUNTIME", `the in-place export's staging folder in ${folder} is gone`, { help: `${cliInvocation()} export --in-place --dir ${commandToken(folder)}` });
134847
+ const added = [];
134848
+ const kept = [...journal.kept_local];
134849
+ let same = journal.same;
134850
+ for (const relative2 of journal.adds) {
134851
+ classifyEntryPath(relative2);
134852
+ const outcome = await placeStaged(folder, staging, relative2);
134853
+ if (outcome === "added") added.push(relative2);
134854
+ else if (outcome === "same") same += 1;
134855
+ else kept.push(relative2);
134856
+ }
134857
+ let git2 = null;
134858
+ if (journal.git) {
134859
+ git2 = await ownCommit(folder) ?? commitExport(folder, `Export ${journal.bundle_id} from ${journal.host} at revision ${journal.revision}
134860
+
134861
+ superbee export --in-place, ${journal.exported_at}. History is not included.
134862
+ `, { force: false });
134863
+ }
134864
+ await rm2(path54.join(staging, "files"), { recursive: true, force: true });
134865
+ await unlink13(path54.join(staging, JOURNAL)).catch(() => {
134866
+ });
134867
+ await rm2(staging, { recursive: true, force: true });
134868
+ const marker = await removeCheckoutMarker(folder, { origin: journal.host, audience: journal.audience, bundle_id: journal.bundle_id }).catch(() => false) ? "removed" : "none";
134869
+ return { added, kept, same, git: git2, marker };
134870
+ }
134871
+ function inPlaceReceipt(folder, journal, finished, homeName, resumed) {
134872
+ return {
134873
+ export: "converted",
134874
+ folder,
134875
+ home: homeName,
134876
+ bundle_id: journal.bundle_id,
134877
+ host: journal.host,
134878
+ revision: journal.revision,
134879
+ exported_at: journal.exported_at,
134880
+ ...resumed ? { resumed: true } : {},
134881
+ binding: "removed (the folder is no longer a hosted checkout)",
134882
+ marker: finished.marker,
134883
+ added: finished.added.length,
134884
+ ...finished.added.length > 0 ? { added_paths: shown(finished.added) } : {},
134885
+ unchanged: finished.same,
134886
+ kept_local: finished.kept.length,
134887
+ ...finished.kept.length > 0 ? { kept_local_paths: shown(finished.kept), kept_local_note: "these files differ from the host's (or block its path); the folder's own were kept" } : {},
134888
+ ...journal.deleted_locally.length > 0 ? { deleted_locally: journal.deleted_locally.length, deleted_locally_paths: shown(journal.deleted_locally), deleted_locally_note: "deleted in this folder and not sent; the host's copies were not put back" } : {},
134889
+ ...journal.unsent_kept > 0 ? { unsent_kept: journal.unsent_kept, unsent_note: "changes sync had not sent stay in this folder only" } : {},
134890
+ ...finished.git ? { git: finished.git } : {},
134891
+ hosted: HOSTED_UNCHANGED,
134892
+ history: NO_HISTORY,
134893
+ help: nextSteps(folder, finished.git !== null)
134894
+ };
134895
+ }
134896
+ async function ownCommit(folder) {
134897
+ const head = runGit(folder, ["rev-parse", "--verify", "--quiet", "HEAD"]);
134898
+ const top = runGit(folder, ["rev-parse", "--show-toplevel"]);
134899
+ const own5 = top.status === 0 && await realpath11(top.stdout.trim()).catch(() => "") === await realpath11(folder).catch(() => folder);
134900
+ if (!own5 || head.status !== 0) return null;
134901
+ return { branch: runGit(folder, ["symbolic-ref", "-q", "--short", "HEAD"]).stdout.trim() || BOARD_BRANCH, commit: head.stdout.trim() };
134902
+ }
134903
+ async function assertNoRepository(folder) {
134904
+ if (await lstat8(path54.join(folder, ".git")).then(() => true, () => false)) {
134905
+ throw new CliError("ALREADY_EXISTS", `${folder} already holds a Git repository`, {
134906
+ details: { reason: "already_git", folder },
134907
+ help: `${cliInvocation()} export --in-place --dir ${commandToken(folder)}`
134908
+ });
134909
+ }
134910
+ }
134911
+ async function exportInPlace(dirArg, git2, keepUnsent, deps2, mode, resume2) {
134912
+ const requested = path54.resolve(deps2.cwd, dirArg ?? ".");
134913
+ assertBundleOutsidePrivateState(requested, deps2.auth.home);
134914
+ const binding = await hostedCheckoutFor(dirArg === void 0 ? [] : ["--dir", dirArg], deps2.auth.home, deps2.cwd);
134915
+ if (!binding) {
134916
+ const folder2 = await realpath11(requested).catch(() => requested);
134917
+ const journal = await readJournal(folder2);
134918
+ if (journal) {
134919
+ const finished = await finishInPlace(folder2, journal);
134920
+ const home4 = await bundleHomeAt(folder2, { home: deps2.auth.home });
134921
+ deps2.stdout(render(inPlaceReceipt(folder2, journal, finished, home4.home, true), mode));
134922
+ return;
134923
+ }
134924
+ if (await entryKind(folder2) === "absent") throw new CliError("NOT_FOUND", `${folder2} does not exist`, { help: `${cliInvocation()} export --in-place --dir <checkout folder>` });
134925
+ const marker = readCheckoutMarker(folder2);
134926
+ if (marker) {
134927
+ const existing = git2 ? await ownCommit(folder2) : null;
134928
+ if (git2 && !existing) await assertNoRepository(folder2);
134929
+ const staging = await stagingDir(folder2);
134930
+ if (staging && !await lstat8(path54.join(staging, JOURNAL)).then(() => true, () => false)) await rm2(staging, { recursive: true, force: true });
134931
+ await removeCheckoutMarker(folder2, { origin: marker.host, audience: `${marker.host}/mcp`, bundle_id: marker.bundle_id });
134932
+ const committed = existing ?? (git2 ? commitExport(folder2, `Export ${marker.bundle_id} (an unbound copy of a hosted checkout)
134933
+
134934
+ superbee export --in-place. Nothing was fetched from the host; history is not included.
134935
+ `, { force: false }) : null);
134936
+ const home4 = await bundleHomeAt(folder2, { home: deps2.auth.home });
134937
+ deps2.stdout(
134938
+ render(
134939
+ {
134940
+ export: "converted",
134941
+ folder: folder2,
134942
+ home: home4.home,
134943
+ bundle_id: marker.bundle_id,
134944
+ from: "an unbound copy of a hosted checkout",
134945
+ marker: "removed",
134946
+ fetched: false,
134947
+ note: `nothing was fetched: the files are kept as they are. To fill in what the copy lacks from the host first, adopt it (${cliInvocation()} checkout --adopt <folder> --host <url>), then export --in-place`,
134948
+ ...committed ? { git: committed } : {},
134949
+ hosted: HOSTED_UNCHANGED,
134950
+ history: NO_HISTORY,
134951
+ help: nextSteps(folder2, committed !== null)
134952
+ },
134953
+ mode
134954
+ )
134955
+ );
134956
+ return;
134957
+ }
134958
+ const home3 = await bundleHomeAt(folder2, { home: deps2.auth.home });
134959
+ deps2.stdout(render({ export: "unchanged", folder: folder2, home: home3.home, reason: "not a hosted checkout: nothing to convert" }, mode));
134960
+ return;
134961
+ }
134962
+ const folder = binding.path;
134963
+ if (git2) await assertNoRepository(folder);
134964
+ const status2 = await hostedStatus(binding, deps2.auth.home);
134965
+ if (status2.sync.state === "busy") {
134966
+ throw new CliError("CONFLICT", `another command holds the checkout lock for ${folder}`, { details: { reason: "checkout_busy", folder }, help: "wait for it to finish, then retry the same command" });
134967
+ }
134968
+ const unsentRefusal = (count5, sync3) => new CliError("CONFLICT", `the checkout of '${binding.bundle_id}' at ${folder} has ${count5} change(s) not on the host`, {
134969
+ details: {
134970
+ reason: "unsent_changes",
134971
+ folder,
134972
+ ...sync3,
134973
+ keep_them_here_only: commandFragment`${cliInvocation()} export --in-place --dir ${commandToken(folder)} --keep-unsent${git2 ? commandFragment` --git` : commandFragment``}`
134974
+ },
134975
+ help: commandFragment`${cliInvocation()} sync --dir ${commandToken(folder)}`
134976
+ });
134977
+ const early = Number(status2.sync.unsent ?? 0) + Number(status2.sync.conflicts ?? 0) + Number(status2.sync.held_files ?? 0) + Number(status2.sync.held_deletions ?? 0);
134978
+ if (early > 0 && !keepUnsent) throw unsentRefusal(early, status2.sync);
134979
+ const source = { target: resolveHostedTarget(binding.audience), bundleId: binding.bundle_id, slug: binding.workspace_slug ?? null, workspace: null, binding };
134980
+ const exported = await fetchExport(source, deps2, resume2);
134981
+ const result3 = await filesystemPushRoleLocks().request(checkoutLockName(folder), { ifAvailable: true }, async (lock) => {
134982
+ if (!lock) {
134983
+ throw new CliError("CONFLICT", `another command holds the checkout lock for ${folder}`, { details: { reason: "checkout_busy", folder }, help: "wait for it to finish, then retry the same command" });
134984
+ }
134985
+ const current = await bindingForPath(deps2.auth.home, folder);
134986
+ if (!current || current.checkout_id !== binding.checkout_id) {
134987
+ throw new CliError("CONFLICT", `the checkout at ${folder} changed while it was exported`, { details: { reason: "checkout_changed", folder }, help: "retry the same command" });
134988
+ }
134989
+ const store = await FileJournaledBackend.open({ directory: checkoutStoreDir(deps2.auth.home, binding.checkout_id), readOnly: true });
134990
+ let pending;
134991
+ try {
134992
+ const classified = await classifyCheckout(binding, deps2.auth.home, store);
134993
+ pending = /* @__PURE__ */ new Set([...classified.unsent, ...classified.conflicts, ...classified.held.keys(), ...classified.heldDeletions]);
134994
+ } finally {
134995
+ await store.close();
134996
+ }
134997
+ if (pending.size > 0 && !keepUnsent) throw unsentRefusal(pending.size, { unsent_ids: shown([...pending]) });
134998
+ const staging = path54.join(folder, IN_PLACE_STAGING);
134999
+ await rm2(staging, { recursive: true, force: true });
135000
+ await mkdir4(path54.join(staging, "files"), { recursive: true });
135001
+ const adds = [];
135002
+ const kept = [];
135003
+ const deletedLocally = [];
135004
+ let same = 0;
135005
+ for (const entry of exported.entries) {
135006
+ const id = entry.kind === "document" ? entry.path.slice(0, -3) : entry.path;
135007
+ const placement = await placementOf(folder, entry);
135008
+ if (placement === "add" && pending.has(id)) {
135009
+ deletedLocally.push(entry.path);
135010
+ continue;
135011
+ }
135012
+ if (placement === "same") same += 1;
135013
+ else if (placement === "kept") kept.push(entry.path);
135014
+ else {
135015
+ const file2 = path54.join(staging, "files", ...entry.path.split("/"));
135016
+ await mkdir4(path54.dirname(file2), { recursive: true });
135017
+ await writeNewFile(file2, entry.bytes);
135018
+ adds.push(entry.path);
135019
+ }
135020
+ }
135021
+ const journal = {
135022
+ schema: JOURNAL_SCHEMA,
135023
+ bundle_id: binding.bundle_id,
135024
+ host: binding.origin,
135025
+ audience: binding.audience,
135026
+ revision: exported.source.revision,
135027
+ exported_at: exported.exportedAt,
135028
+ git: git2,
135029
+ adds,
135030
+ same,
135031
+ kept_local: kept,
135032
+ deleted_locally: deletedLocally,
135033
+ unsent_kept: pending.size
135034
+ };
135035
+ await writeJournal(staging, journal);
135036
+ await releaseCheckout(deps2.auth.home, binding);
135037
+ return { journal, finished: await finishInPlace(folder, journal) };
135038
+ });
135039
+ const home2 = await bundleHomeAt(folder, { home: deps2.auth.home });
135040
+ deps2.stdout(render(inPlaceReceipt(folder, result3.journal, result3.finished, home2.home, false), mode));
135041
+ }
135042
+ async function exportCommand(argv2, partial2 = {}) {
135043
+ const deps2 = exportDeps(partial2);
135044
+ const { values, positionals } = parseLeafOrUsage(
135045
+ () => parseArgs41({
135046
+ args: argv2,
135047
+ options: {
135048
+ to: { type: "string" },
135049
+ "in-place": { type: "boolean" },
135050
+ dir: { type: "string" },
135051
+ host: { type: "string" },
135052
+ workspace: { type: "string" },
135053
+ git: { type: "boolean" },
135054
+ "keep-unsent": { type: "boolean" },
135055
+ json: { type: "boolean" },
135056
+ help: { type: "boolean", short: "h" }
135057
+ },
135058
+ allowPositionals: true
135059
+ }),
135060
+ CLI_LEAVES.export
135061
+ );
135062
+ if (values.help) {
135063
+ deps2.stdout(renderUsage(EXPORT_USAGE));
135064
+ return;
135065
+ }
135066
+ const mode = resolveMode(values);
135067
+ const usage3 = (message) => new CliError("USAGE", message, { help: `${cliInvocation()} export --help` });
135068
+ const named = positionals[0];
135069
+ const inPlace = values["in-place"] === true;
135070
+ if (inPlace === (values.to !== void 0)) throw usage3("pass exactly one of --to <folder> and --in-place");
135071
+ if (named !== void 0 && values.dir !== void 0) throw usage3("pass a bundle id or --dir <checkout>, not both");
135072
+ if (named === void 0 && (values.host !== void 0 || values.workspace !== void 0)) throw usage3("--host and --workspace go with a bundle id; a checkout uses its own");
135073
+ if (inPlace && named !== void 0) throw usage3("--in-place converts a checkout folder: pass --dir <checkout>, not a bundle id");
135074
+ if (!inPlace && values["keep-unsent"]) throw usage3("--keep-unsent goes with --in-place");
135075
+ const reference = named === void 0 ? void 0 : parseHostedBundleReference(named);
135076
+ if (named !== void 0 && !reference) throw usage3(`'${named}' is not a hosted bundle id or <workspace>/<bundle-id>`);
135077
+ const git2 = values.git === true;
135078
+ const resume2 = commandFragment`${cliInvocation()} export${named !== void 0 ? commandFragment` ${commandToken(named)}` : commandFragment``}${values.dir !== void 0 ? commandFragment` --dir ${commandToken(path54.resolve(deps2.cwd, values.dir))}` : commandFragment``}${values.to !== void 0 ? commandFragment` --to ${commandToken(path54.resolve(deps2.cwd, values.to))}` : commandFragment``}${inPlace ? commandFragment` --in-place` : commandFragment``}${values.host !== void 0 ? commandFragment` --host ${commandToken(values.host)}` : commandFragment``}${values.workspace !== void 0 ? commandFragment` --workspace ${commandToken(values.workspace)}` : commandFragment``}${git2 ? commandFragment` --git` : commandFragment``}${values["keep-unsent"] ? commandFragment` --keep-unsent` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`;
135079
+ if (values.dir !== void 0) assertBundleOutsidePrivateState(path54.resolve(deps2.cwd, values.dir), deps2.auth.home);
135080
+ if (inPlace) {
135081
+ await exportInPlace(values.dir, git2, values["keep-unsent"] === true, deps2, mode, resume2);
135082
+ return;
135083
+ }
135084
+ let source;
135085
+ if (reference) {
135086
+ const named2 = await requireHostedBundleHost(values.host, deps2.auth);
135087
+ source = {
135088
+ target: named2.target,
135089
+ bundleId: reference.bundleId,
135090
+ slug: reference.slug,
135091
+ workspace: workspaceForNamedHost(named2, values.workspace) ?? null,
135092
+ binding: null
135093
+ };
135094
+ } else {
135095
+ const binding = await hostedCheckoutFor(values.dir === void 0 ? [] : ["--dir", values.dir], deps2.auth.home, deps2.cwd);
135096
+ if (!binding) {
135097
+ throw new CliError("NOT_FOUND", `${path54.resolve(deps2.cwd, values.dir ?? ".")} is not a hosted checkout`, {
135098
+ details: { reason: "not_a_checkout" },
135099
+ help: `${cliInvocation()} export <bundle-id> --to ${commandToken(values.to)}`
135100
+ });
135101
+ }
135102
+ source = { target: resolveHostedTarget(binding.audience), bundleId: binding.bundle_id, slug: binding.workspace_slug ?? null, workspace: null, binding };
135103
+ }
135104
+ await exportToFolder(source, values.to, git2, deps2, mode, resume2);
135105
+ }
135106
+ var EXPORT_USAGE, EXPORT_DEADLINE_MS, SHOWN, JOURNAL, JOURNAL_SCHEMA, MAX_JOURNAL_BYTES, NO_HISTORY, HOSTED_UNCHANGED, PAGED_EXPORT_ATTEMPTS, PAGED_EXPORT_RESTART_MS, PAGE_RETRY_MS, pause2, ABANDONED_AFTER_MS;
135107
+ var init_export = __esm({
135108
+ "../cli/src/commands/export.ts"() {
135109
+ "use strict";
135110
+ init_define_SUPERBEE_BUILD_IDENTITY();
135111
+ init_define_SUPERBEE_UPDATE_POLICY();
135112
+ init_src();
135113
+ init_filesystem_push_role();
135114
+ init_src2();
135115
+ init_args();
135116
+ init_bundle2();
135117
+ init_bundle_home();
135118
+ init_command_spec();
135119
+ init_command_text();
135120
+ init_errors4();
135121
+ init_invocation();
135122
+ init_output2();
135123
+ init_private_state_bundle_boundary();
135124
+ init_nofollow_read();
135125
+ init_autopull2();
135126
+ init_session();
135127
+ init_discovery();
135128
+ init_binding();
135129
+ init_client();
135130
+ init_account();
135131
+ init_refusals();
135132
+ init_reference();
135133
+ init_sync2();
135134
+ init_status();
135135
+ init_file_journaled_backend();
135136
+ init_marker();
135137
+ init_export_archive();
135138
+ init_export_archive();
135139
+ EXPORT_USAGE = `superbee export \u2014 copy a hosted bundle out of hosted Superbee
135140
+
135141
+ Usage:
135142
+ superbee export <bundle-id> --to <folder> [--host <url>] [--workspace <id>] [--git] [--json]
135143
+ superbee export [--dir <checkout>] --to <folder> [--git] [--json]
135144
+ superbee export [--dir <checkout>] --in-place [--git] [--keep-unsent] [--json]
135145
+
135146
+ Fetches the hosted bundle's portable export: every document, reserved file (index.md, log.md)
135147
+ and blob at its latest confirmed revision, byte for byte as the host stores them. The archive is
135148
+ verified whole (every entry against the host's digest manifest) before any file is written.
135149
+ Signs in if needed (AUTH_REQUIRED, exit 4, carries the one link to relay and the command to
135150
+ re-run). The hosted bundle is never changed. History is not exported: the folder holds the
135151
+ current revision only.
135152
+
135153
+ --to <folder> writes a new local bundle there. The folder must be new or empty; it appears
135154
+ complete or not at all. With a bundle id the host is --host, else your last sign-in; with
135155
+ --dir (or run inside a checkout) the checkout's own host and bundle are used. A bundle id in more
135156
+ than one of your workspaces is named <workspace>/<bundle-id>, or with --workspace.
135157
+
135158
+ --in-place converts a hosted checkout into a plain local bundle: it adds the files the checkout
135159
+ lacks (blobs, reserved files, documents added on the host), never overwrites a file, then
135160
+ forgets the checkout's binding. It refuses a checkout with changes sync has not sent, conflicts
135161
+ or held files; run 'superbee sync' first, or pass --keep-unsent to keep them in this folder only.
135162
+ If it is interrupted, re-running the same command finishes it.
135163
+
135164
+ --git makes the result a Git board: a repository on branch '${BOARD_BRANCH}' whose first commit is the
135165
+ export. Share it with 'git remote add origin <url>' and 'superbee sync --establish'.
135166
+
135167
+ Options:
135168
+ --to <folder> New or empty folder to export into
135169
+ --in-place Convert the hosted checkout (--dir, else the current folder) into a local bundle
135170
+ --dir <checkout> The hosted checkout to export (default: the current folder)
135171
+ --host <url> Hosted Superbee URL, with a bundle id; default: your last sign-in
135172
+ --workspace <id> With a bundle id: your workspace that holds it, by id or slug
135173
+ --git Initialize a Git repository on branch '${BOARD_BRANCH}' and commit the export
135174
+ --keep-unsent With --in-place: convert even with unsent changes, conflicts or held files
135175
+ --json Emit compact JSON instead of TOON
135176
+ -h, --help Show this help
135177
+
135178
+ Examples:
135179
+ superbee export team.knowledge --to ~/work/team-knowledge --git
135180
+ superbee export --dir ~/work/team --to ~/work/team-copy
135181
+ superbee export --dir ~/work/team --in-place
135182
+ `;
135183
+ EXPORT_DEADLINE_MS = 6e4;
135184
+ SHOWN = 20;
135185
+ JOURNAL = IN_PLACE_JOURNAL;
135186
+ JOURNAL_SCHEMA = 1;
135187
+ MAX_JOURNAL_BYTES = 8 * 1024 * 1024;
135188
+ NO_HISTORY = "not exported: the folder holds the current revision only";
135189
+ HOSTED_UNCHANGED = "unchanged: the hosted bundle still exists and was not modified";
135190
+ PAGED_EXPORT_ATTEMPTS = 3;
135191
+ PAGED_EXPORT_RESTART_MS = [500, 1500];
135192
+ PAGE_RETRY_MS = 1e3;
135193
+ pause2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
135194
+ ABANDONED_AFTER_MS = 60 * 60 * 1e3;
135195
+ }
135196
+ });
135197
+
135198
+ // ../cli/src/commands/checkout-adopt.ts
135199
+ import path55 from "node:path";
135200
+ import { lstat as lstat9, realpath as realpath12 } from "node:fs/promises";
134335
135201
  function readLeaf(file2) {
134336
135202
  const read = readRegularFileNoFollowSync(file2);
134337
135203
  if (read.state === "missing") return null;
@@ -134354,11 +135220,11 @@ async function withCheckoutLock(folder, body) {
134354
135220
  });
134355
135221
  }
134356
135222
  async function adopt(folderArg, options, deps2, mode) {
134357
- const folder = path54.resolve(deps2.cwd, folderArg);
135223
+ const folder = path55.resolve(deps2.cwd, folderArg);
134358
135224
  let canonical2;
134359
135225
  try {
134360
- canonical2 = await realpath11(folder);
134361
- if (!(await lstat8(canonical2)).isDirectory()) throw new Error("not a folder");
135226
+ canonical2 = await realpath12(folder);
135227
+ if (!(await lstat9(canonical2)).isDirectory()) throw new Error("not a folder");
134362
135228
  } catch {
134363
135229
  throw new CliError("NOT_FOUND", `${folder} is not a folder`, { help: `${cliInvocation()} checkout --adopt <folder> --host <url>` });
134364
135230
  }
@@ -134373,7 +135239,7 @@ async function adopt(folderArg, options, deps2, mode) {
134373
135239
  }
134374
135240
  if (options.workspace !== void 0 && await rebindToWorkspace(canonical2, bound, options, deps2, mode)) return;
134375
135241
  const marker2 = await writeCheckoutMarker(canonical2, bound).catch(() => null);
134376
- deps2.stdout(render({ adopted: "unchanged", ...bindingView(bound), marker: marker2 ? "written" : "present", help: nextSteps(canonical2) }, mode));
135242
+ deps2.stdout(render({ adopted: "unchanged", ...bindingView(bound), marker: marker2 ? "written" : "present", help: nextSteps2(canonical2) }, mode));
134377
135243
  return;
134378
135244
  }
134379
135245
  const folderMarker = readCheckoutMarker(canonical2);
@@ -134413,7 +135279,7 @@ async function adopt(folderArg, options, deps2, mode) {
134413
135279
  ...marker2 ? { marker: "written" } : {},
134414
135280
  catalog: relocated ? { relocated: true, label: relocated.label, id: relocated.id } : { relocated: false, note: "no catalog entry named the old folder" },
134415
135281
  ...options.workspace !== void 0 ? { workspace_flag: "ignored: a moved checkout keeps the workspace it was bound with" } : {},
134416
- help: [...nextSteps(canonical2), `${cliInvocation()} sync --dir ${commandToken(canonical2)}`]
135282
+ help: [...nextSteps2(canonical2), `${cliInvocation()} sync --dir ${commandToken(canonical2)}`]
134417
135283
  },
134418
135284
  mode
134419
135285
  )
@@ -134465,7 +135331,7 @@ async function adopt(folderArg, options, deps2, mode) {
134465
135331
  const typed = { slug: marker.workspace_slug ?? null, bundleId: bundleId2 };
134466
135332
  await assertStandaloneFolder(canonical2);
134467
135333
  const resume2 = commandFragment`${cliInvocation()} checkout --adopt ${commandToken(canonical2)} --host ${commandToken(bindingHostArgument(target3))}${options.workspace !== void 0 ? commandFragment` --workspace ${commandToken(options.workspace)}` : commandFragment``}${options.json ? commandFragment` --json` : commandFragment``}`;
134468
- const connection = await connectHostedBundle(typed, target3, options.workspace, deps2, resume2);
135334
+ const connection = await connectHostedBundle(typed, target3, options.workspace, deps2, resume2, { deadlineMs: EXPORT_DEADLINE_MS });
134469
135335
  if (typed.slug === null && connection.reference.slug !== null) {
134470
135336
  const found = readBundleListing(await connection.client.bundles()).lookup({ slug: null, bundleId: bundleId2 });
134471
135337
  if (found.holders > 1) {
@@ -134477,8 +135343,12 @@ async function adopt(folderArg, options, deps2, mode) {
134477
135343
  }
134478
135344
  }
134479
135345
  const published = await readPublishedExtras(home2, canonical2);
134480
- const extras = published && published.host === target3.origin && published.bundle_id === bundleId2 ? published.extras : void 0;
134481
- const result3 = await bindFolderInPlace({ canonical: canonical2, target: target3, bundleId: bundleId2, connection, deps: deps2, resume: resume2, ...extras ? { extras } : {} });
135346
+ const host = await adoptedExtras(canonical2, exportRequestFor(connection, target3, bundleId2, resume2));
135347
+ const extras = {
135348
+ ...host.extras,
135349
+ ...published && published.host === target3.origin && published.bundle_id === bundleId2 ? published.extras : {}
135350
+ };
135351
+ const result3 = await bindWithExtras({ canonical: canonical2, target: target3, bundleId: bundleId2, connection, deps: deps2, resume: resume2, extras }, host);
134482
135352
  if (published) await clearPublishedExtras(home2, canonical2);
134483
135353
  const cataloged = await registerInCatalog(home2, result3.binding);
134484
135354
  const syncHelp = `${cliInvocation()} sync --dir ${commandToken(canonical2)}`;
@@ -134492,8 +135362,9 @@ async function adopt(folderArg, options, deps2, mode) {
134492
135362
  ...result3.conflicts.length > 0 ? { conflicts: listed(result3.conflicts) } : {},
134493
135363
  ...result3.localOnly.length > 0 ? { local_only: listed(result3.localOnly), local_only_note: "the next sync sends these as new documents, which re-creates any the host deleted since the copy was made; delete any you do not want first" } : {},
134494
135364
  root_index: result3.rootIndex,
135365
+ ...result3.otherFiles ? { other_files: result3.otherFiles, warning: "files other than documents were not checked against the host" } : {},
134495
135366
  ...result3.markerWritten ? { marker: "written" } : {},
134496
- help: result3.conflicts.length > 0 ? [`${cliInvocation()} sync --dir ${commandToken(canonical2)} --inspect --doc ${commandToken(result3.conflicts[0])}`, syncHelp] : [syncHelp, ...nextSteps(canonical2)]
135367
+ help: result3.conflicts.length > 0 ? [`${cliInvocation()} sync --dir ${commandToken(canonical2)} --inspect --doc ${commandToken(result3.conflicts[0])}`, syncHelp] : [syncHelp, ...nextSteps2(canonical2)]
134497
135368
  },
134498
135369
  mode
134499
135370
  )
@@ -134508,7 +135379,7 @@ async function rebindToWorkspace(canonical2, bound, options, deps2, mode) {
134508
135379
  }
134509
135380
  const target3 = resolveHostedTarget(options.host);
134510
135381
  const resume2 = commandFragment`${cliInvocation()} checkout --adopt ${commandToken(canonical2)} --host ${commandToken(bindingHostArgument(target3))} --workspace ${commandToken(options.workspace)}${options.json ? commandFragment` --json` : commandFragment``}`;
134511
- const connection = await connectHostedBundle({ slug: null, bundleId: bound.bundle_id }, target3, options.workspace, deps2, resume2);
135382
+ const connection = await connectHostedBundle({ slug: null, bundleId: bound.bundle_id }, target3, options.workspace, deps2, resume2, { deadlineMs: EXPORT_DEADLINE_MS });
134512
135383
  const slug = connection.reference.slug;
134513
135384
  if (slug === null || slug === (bound.workspace_slug ?? null)) return false;
134514
135385
  if (connection.identity.principalId !== bound.principal_id) {
@@ -134557,7 +135428,8 @@ async function rebindToWorkspace(canonical2, bound, options, deps2, mode) {
134557
135428
  await releaseCheckout(home2, bound);
134558
135429
  return pending;
134559
135430
  });
134560
- const result3 = await bindFolderInPlace({ canonical: canonical2, target: target3, bundleId: bound.bundle_id, connection, deps: deps2, resume: resume2 });
135431
+ const host = await adoptedExtras(canonical2, exportRequestFor(connection, target3, bound.bundle_id, resume2));
135432
+ const result3 = await bindWithExtras({ canonical: canonical2, target: target3, bundleId: bound.bundle_id, connection, deps: deps2, resume: resume2, extras: host.extras }, host);
134561
135433
  deps2.stdout(
134562
135434
  render(
134563
135435
  {
@@ -134571,7 +135443,7 @@ async function rebindToWorkspace(canonical2, bound, options, deps2, mode) {
134571
135443
  documents: { placed: result3.placed.length, matched: result3.matched.length, conflicts: result3.conflicts.length, local_only: result3.localOnly.length },
134572
135444
  ...result3.conflicts.length > 0 ? { conflicts: listed(result3.conflicts) } : {},
134573
135445
  ...result3.localOnly.length > 0 ? { local_only: listed(result3.localOnly) } : {},
134574
- help: [`${cliInvocation()} sync --dir ${commandToken(canonical2)}`, ...nextSteps(canonical2)]
135446
+ help: [`${cliInvocation()} sync --dir ${commandToken(canonical2)}`, ...nextSteps2(canonical2)]
134575
135447
  },
134576
135448
  mode
134577
135449
  )
@@ -134629,7 +135501,7 @@ async function bindFolderInPlace(input) {
134629
135501
  const hostIds = /* @__PURE__ */ new Set();
134630
135502
  for (const head of heads) {
134631
135503
  hostIds.add(head.id);
134632
- const file2 = path54.join(canonical2, pathFromConceptId(head.id));
135504
+ const file2 = path55.join(canonical2, pathFromConceptId(head.id));
134633
135505
  if (await parentUnsafe(canonical2, file2)) {
134634
135506
  conflicts.push(head.id);
134635
135507
  continue;
@@ -134663,12 +135535,12 @@ async function bindFolderInPlace(input) {
134663
135535
  if (index2) {
134664
135536
  const hostRoot2 = Buffer.from(index2.content, "utf8");
134665
135537
  root = digestOf(hostRoot2);
134666
- const current = readLeaf(path54.join(canonical2, ROOT_INDEX));
135538
+ const current = readLeaf(path55.join(canonical2, ROOT_INDEX));
134667
135539
  if (current === "unsafe") rootIndex = "kept (not a plain file; sync holds it)";
134668
135540
  else if (current === null) {
134669
- const placedRoot = (await placeNew(path54.join(canonical2, ROOT_INDEX), hostRoot2)).placed;
135541
+ const placedRoot = (await placeNew(path55.join(canonical2, ROOT_INDEX), hostRoot2)).placed;
134670
135542
  if (placedRoot) {
134671
- placedFiles.set(path54.join(canonical2, ROOT_INDEX), root);
135543
+ placedFiles.set(path55.join(canonical2, ROOT_INDEX), root);
134672
135544
  rootBase = index2.version;
134673
135545
  }
134674
135546
  rootIndex = placedRoot ? "placed" : "kept";
@@ -134703,6 +135575,25 @@ async function bindFolderInPlace(input) {
134703
135575
  }
134704
135576
  });
134705
135577
  }
135578
+ function exportRequestFor(connection, target3, bundleId2, resume2) {
135579
+ const { client, reference } = connection;
135580
+ return {
135581
+ client: reference.slug === null ? client : client.within(reference.slug),
135582
+ slug: reference.slug,
135583
+ source: { target: target3, bundleId: bundleId2, slug: reference.slug, workspace: null, binding: null },
135584
+ resume: resume2
135585
+ };
135586
+ }
135587
+ async function bindWithExtras(input, host) {
135588
+ try {
135589
+ const result3 = await bindFolderInPlace(input);
135590
+ return host.unplaced === null ? result3 : { ...result3, otherFiles: `not recorded: ${host.unplaced}; files other than documents here that differ from nothing on record read as edits until the next checkout` };
135591
+ } catch (error51) {
135592
+ await removePlaced(input.canonical, host.placed, false).catch(() => {
135593
+ });
135594
+ throw error51;
135595
+ }
135596
+ }
134706
135597
  var LISTED;
134707
135598
  var init_checkout_adopt = __esm({
134708
135599
  "../cli/src/commands/checkout-adopt.ts"() {
@@ -134730,24 +135621,25 @@ var init_checkout_adopt = __esm({
134730
135621
  init_sync_scan();
134731
135622
  init_checkout_store();
134732
135623
  init_checkout();
135624
+ init_export();
134733
135625
  LISTED = 20;
134734
135626
  }
134735
135627
  });
134736
135628
 
134737
135629
  // ../cli/src/commands/checkout.ts
134738
- import { homedir as homedir39 } from "node:os";
134739
- import { lstat as lstat9, mkdir as mkdir4, readFile as readFile5, readdir as readdir8, realpath as realpath12, rmdir as rmdir3, stat as stat8, unlink as unlink13 } from "node:fs/promises";
134740
- import path55 from "node:path";
134741
- import { parseArgs as parseArgs41 } from "node:util";
135630
+ import { homedir as homedir40 } from "node:os";
135631
+ import { lstat as lstat10, mkdir as mkdir5, readFile as readFile5, readdir as readdir9, realpath as realpath13, rmdir as rmdir3, stat as stat8, unlink as unlink14 } from "node:fs/promises";
135632
+ import path56 from "node:path";
135633
+ import { parseArgs as parseArgs42 } from "node:util";
134742
135634
  function checkoutDeps(partial2) {
134743
135635
  return {
134744
135636
  stdout: partial2.stdout ?? ((text5) => void process.stdout.write(text5)),
134745
- auth: partial2.auth ?? defaultHostedAuthDeps(homedir39()),
135637
+ auth: partial2.auth ?? defaultHostedAuthDeps(homedir40()),
134746
135638
  cwd: partial2.cwd ?? process.cwd(),
134747
135639
  ...partial2.fetch ? { fetch: partial2.fetch } : {}
134748
135640
  };
134749
135641
  }
134750
- async function entryKind(target3) {
135642
+ async function entryKind2(target3) {
134751
135643
  let info;
134752
135644
  try {
134753
135645
  info = await stat8(target3);
@@ -134756,7 +135648,7 @@ async function entryKind(target3) {
134756
135648
  throw error51;
134757
135649
  }
134758
135650
  if (!info.isDirectory()) return "other";
134759
- return (await readdir8(target3)).length === 0 ? "empty-dir" : "dir";
135651
+ return (await readdir9(target3)).length === 0 ? "empty-dir" : "dir";
134760
135652
  }
134761
135653
  function bindingView(binding) {
134762
135654
  return {
@@ -134769,11 +135661,11 @@ function bindingView(binding) {
134769
135661
  folder: binding.path
134770
135662
  };
134771
135663
  }
134772
- function nextSteps(folder) {
135664
+ function nextSteps2(folder) {
134773
135665
  return [`${cliInvocation()} list --dir ${commandToken(folder)}`, `${cliInvocation()} status --dir ${commandToken(folder)}`];
134774
135666
  }
134775
135667
  async function assertStandaloneFolder(folder) {
134776
- const parent = path55.dirname(folder);
135668
+ const parent = path56.dirname(folder);
134777
135669
  const enclosing = await findBundleRoot(parent).catch(() => null);
134778
135670
  if (enclosing) {
134779
135671
  throw new CliError("FORBIDDEN", `refusing to check out inside the local bundle at ${enclosing}`, {
@@ -134832,17 +135724,17 @@ function lockFailure2(error51, folder) {
134832
135724
  return error51;
134833
135725
  }
134834
135726
  async function canonicalFolder(folder) {
134835
- const parent = path55.dirname(folder);
134836
- await mkdir4(parent, { recursive: true });
135727
+ const parent = path56.dirname(folder);
135728
+ await mkdir5(parent, { recursive: true });
134837
135729
  let link4 = false;
134838
135730
  try {
134839
- link4 = (await lstat9(folder)).isSymbolicLink();
135731
+ link4 = (await lstat10(folder)).isSymbolicLink();
134840
135732
  } catch (error51) {
134841
135733
  if (error51.code !== "ENOENT") throw error51;
134842
135734
  }
134843
- if (!link4) return path55.join(await realpath12(parent), path55.basename(folder));
135735
+ if (!link4) return path56.join(await realpath13(parent), path56.basename(folder));
134844
135736
  try {
134845
- return await realpath12(folder);
135737
+ return await realpath13(folder);
134846
135738
  } catch {
134847
135739
  throw new CliError("USAGE", `the --dir folder ${folder} is a symbolic link to a folder that does not exist`, { help: "pass --dir <the real folder>" });
134848
135740
  }
@@ -134873,25 +135765,25 @@ async function removePlaced(folder, placed, createdFolder) {
134873
135765
  const dirs = /* @__PURE__ */ new Set();
134874
135766
  for (const [file2, digest3] of placed) {
134875
135767
  try {
134876
- if (digestOf(await readFile5(file2)) === digest3) await unlink13(file2);
135768
+ if (digestOf(await readFile5(file2)) === digest3) await unlink14(file2);
134877
135769
  } catch {
134878
135770
  }
134879
- for (let dir = path55.dirname(file2); dir !== folder && dir.startsWith(`${folder}${path55.sep}`); dir = path55.dirname(dir)) dirs.add(dir);
135771
+ for (let dir = path56.dirname(file2); dir !== folder && dir.startsWith(`${folder}${path56.sep}`); dir = path56.dirname(dir)) dirs.add(dir);
134880
135772
  }
134881
135773
  for (const dir of [...dirs].sort((a, b) => b.length - a.length)) await rmdir3(dir).catch(() => {
134882
135774
  });
134883
135775
  if (createdFolder) await rmdir3(folder).catch(() => {
134884
135776
  });
134885
- return await entryKind(folder) !== "dir";
135777
+ return await entryKind2(folder) !== "dir";
134886
135778
  }
134887
135779
  async function release(folderArg, deps2, mode) {
134888
- const folder = path55.resolve(deps2.cwd, folderArg);
135780
+ const folder = path56.resolve(deps2.cwd, folderArg);
134889
135781
  let canonical2;
134890
135782
  try {
134891
- canonical2 = (await lstat9(folder)).isSymbolicLink() ? await realpath12(folder) : path55.join(await realpath12(path55.dirname(folder)), path55.basename(folder));
135783
+ canonical2 = (await lstat10(folder)).isSymbolicLink() ? await realpath13(folder) : path56.join(await realpath13(path56.dirname(folder)), path56.basename(folder));
134892
135784
  } catch {
134893
135785
  try {
134894
- canonical2 = path55.join(await realpath12(path55.dirname(folder)), path55.basename(folder));
135786
+ canonical2 = path56.join(await realpath13(path56.dirname(folder)), path56.basename(folder));
134895
135787
  } catch {
134896
135788
  canonical2 = folder;
134897
135789
  }
@@ -134928,7 +135820,7 @@ async function release(folderArg, deps2, mode) {
134928
135820
  }
134929
135821
  async function checkoutHost(flag, folder, typed, values, home2, env, fetchImpl) {
134930
135822
  if (flag === void 0) {
134931
- const real = await realpath12(folder).catch(() => null);
135823
+ const real = await realpath13(folder).catch(() => null);
134932
135824
  const bound = real ? await bindingForPath(home2, real).catch(() => null) : null;
134933
135825
  if (bound) return { target: checkoutTarget(bound), workspace: values.workspace, origin: {} };
134934
135826
  }
@@ -134942,7 +135834,7 @@ async function checkoutHost(flag, folder, typed, values, home2, env, fetchImpl)
134942
135834
  async function checkout(argv2, partial2 = {}) {
134943
135835
  const deps2 = checkoutDeps(partial2);
134944
135836
  const { values, positionals } = parseLeafOrUsage(
134945
- () => parseArgs41({
135837
+ () => parseArgs42({
134946
135838
  args: argv2,
134947
135839
  options: {
134948
135840
  host: { type: "string" },
@@ -134984,21 +135876,21 @@ async function checkout(argv2, partial2 = {}) {
134984
135876
  throw new CliError("USAGE", `'${positionals[0]}' is not a hosted bundle id or <workspace>/<bundle-id>`, { help: `${cliInvocation()} checkout --help` });
134985
135877
  }
134986
135878
  const bundleId2 = typed.bundleId;
134987
- const folder = path55.resolve(deps2.cwd, values.dir ?? bundleId2);
135879
+ const folder = path56.resolve(deps2.cwd, values.dir ?? bundleId2);
134988
135880
  assertBundleOutsidePrivateState(folder, deps2.auth.home);
134989
135881
  const { target: target3, workspace: workspaceFlag2, origin: hostOrigin } = await checkoutHost(values.host, folder, typed, values, deps2.auth.home, deps2.auth.env, deps2.auth.fetch);
134990
135882
  const prefix = syncRoutePrefix(target3);
134991
135883
  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``}`;
134992
- const found = await entryKind(folder);
135884
+ const found = await entryKind2(folder);
134993
135885
  if (found === "other") {
134994
135886
  throw new CliError("ALREADY_EXISTS", `${folder} exists and is not a folder`, { help: "pass --dir <new folder>" });
134995
135887
  }
134996
135888
  if (found === "dir") {
134997
- const existing = await bindingForPath(deps2.auth.home, await realpath12(folder));
135889
+ const existing = await bindingForPath(deps2.auth.home, await realpath13(folder));
134998
135890
  const sameWorkspace = workspaceFlag2 === void 0 || workspaceFlag2 === existing?.workspace_slug || workspaceFlag2 === existing?.workspace;
134999
135891
  const asked = typed.slug === null && sameWorkspace ? { slug: existing?.workspace_slug ?? null, bundleId: bundleId2 } : typed;
135000
135892
  if (existing && bindsBundle(existing, target3, asked)) {
135001
- deps2.stdout(render({ checkout: "unchanged", ...bindingView(existing), help: nextSteps(existing.path) }, mode));
135893
+ deps2.stdout(render({ checkout: "unchanged", ...bindingView(existing), help: nextSteps2(existing.path) }, mode));
135002
135894
  return;
135003
135895
  }
135004
135896
  const marker = existing ? null : readCheckoutMarker(folder);
@@ -135009,7 +135901,7 @@ async function checkout(argv2, partial2 = {}) {
135009
135901
  });
135010
135902
  }
135011
135903
  await assertStandaloneFolder(folder);
135012
- const { identity, reader, listed: listed2, workspace, reference, definitionWrites, documentInputBytes } = await connectHostedBundle(typed, target3, workspaceFlag2, deps2, resume2);
135904
+ const { identity, reader, listed: listed2, workspace, reference, client, definitionWrites, documentInputBytes } = await connectHostedBundle(typed, target3, workspaceFlag2, deps2, resume2, { deadlineMs: EXPORT_DEADLINE_MS });
135013
135905
  const canonical2 = await canonicalFolder(folder);
135014
135906
  let createdFolder = false;
135015
135907
  const placed = /* @__PURE__ */ new Map();
@@ -135021,7 +135913,7 @@ async function checkout(argv2, partial2 = {}) {
135021
135913
  help: "wait for it to finish, then retry the same command"
135022
135914
  });
135023
135915
  }
135024
- const kind2 = await entryKind(canonical2);
135916
+ const kind2 = await entryKind2(canonical2);
135025
135917
  if (kind2 === "dir" || kind2 === "other") {
135026
135918
  throw new CliError("ALREADY_EXISTS", `${canonical2} is no longer empty`, { details: { reason: "not_empty", folder: canonical2 }, help: "pass --dir <new or empty folder>" });
135027
135919
  }
@@ -135031,7 +135923,7 @@ async function checkout(argv2, partial2 = {}) {
135031
135923
  await releaseCheckout(deps2.auth.home, replaced);
135032
135924
  }
135033
135925
  if (kind2 === "absent") {
135034
- await mkdir4(canonical2);
135926
+ await mkdir5(canonical2);
135035
135927
  createdFolder = true;
135036
135928
  }
135037
135929
  const identityNow = await folderIdentity(canonical2);
@@ -135066,9 +135958,12 @@ async function checkout(argv2, partial2 = {}) {
135066
135958
  const stored = await store.readHeads({ project: (head) => head.id });
135067
135959
  assertProjectable(stored, bundleId2, target3);
135068
135960
  const exported = await exportFresh(store, canonical2, (file2, digest3) => placed.set(file2, digest3));
135069
- if (exported.kept.length > 0) {
135961
+ const portable = await exportOrReason({ client: reference.slug === null ? client : client.within(reference.slug), slug: reference.slug, source: { target: target3, bundleId: bundleId2, slug: reference.slug, workspace: workspaceFlag2 ?? null, binding: null }, resume: resume2 });
135962
+ const extras = typeof portable === "string" ? NO_EXTRAS : await placeExtras(portable, canonical2, (file2, digest3) => placed.set(file2, digest3));
135963
+ const kept = [...exported.kept, ...extras.kept];
135964
+ if (kept.length > 0) {
135070
135965
  throw new CliError("CONFLICT", `files appeared in ${canonical2} during checkout`, {
135071
- details: { reason: "folder_changed", kept: exported.kept.slice(0, 20), kept_total: exported.kept.length },
135966
+ details: { reason: "folder_changed", kept: kept.slice(0, 20), kept_total: kept.length },
135072
135967
  help: "retry the same command once nothing else writes to the folder"
135073
135968
  });
135074
135969
  }
@@ -135079,14 +135974,14 @@ async function checkout(argv2, partial2 = {}) {
135079
135974
  if (id !== ROOT_INDEX && version4) files[id] = { digest: digest3, version: version4 };
135080
135975
  }
135081
135976
  const rootBase = exported.exported[ROOT_INDEX] !== void 0 ? (await store.readReserved("", "index.md"))?.version ?? null : null;
135082
- await writeProjection(deps2.auth.home, binding.checkout_id, { files, root: exported.exported[ROOT_INDEX] ?? null, rootBase });
135977
+ await writeProjection(deps2.auth.home, binding.checkout_id, { files, root: exported.exported[ROOT_INDEX] ?? null, rootBase, extras: extras.placed });
135083
135978
  const markerFile = await writeCheckoutMarker(canonical2, binding);
135084
135979
  if (markerFile) placed.set(markerFile, digestOf(checkoutMarkerBytes(binding)));
135085
135980
  const ready = { ...binding, state: "ready" };
135086
135981
  await writeBinding(deps2.auth.home, ready);
135087
135982
  await recordPulled(deps2.auth.home, ready.checkout_id);
135088
135983
  await indexCheckoutPath(deps2.auth.home, ready);
135089
- return { binding: ready, documents: exported.documents, root: exported.root, digest: marker.headsDigest ?? null };
135984
+ return { binding: ready, documents: exported.documents, root: exported.root, unplaced: typeof portable === "string" ? portable : null, reserved: extras.reserved, other: extras.other, digest: marker.headsDigest ?? null };
135090
135985
  } catch (error51) {
135091
135986
  await store?.close().catch(() => {
135092
135987
  });
@@ -135119,22 +136014,96 @@ async function checkout(argv2, partial2 = {}) {
135119
136014
  catalog: cataloged,
135120
136015
  documents: result3.documents,
135121
136016
  root_index: result3.root,
136017
+ ...result3.unplaced === null ? { reserved_files: result3.reserved, other_files: result3.other } : {
136018
+ other_files: `not placed: ${result3.unplaced}, so reserved files below the root and files other than documents stay on the host; superbee export copies them`,
136019
+ warning: "this checkout lacks the host's files other than documents, and sync never brings them: check out again into a new folder to get them"
136020
+ },
135122
136021
  heads_digest: result3.digest,
135123
136022
  ...replacedBinding ? { replaced_stale_checkout: { bundle_id: replacedBinding.bundle_id, host: replacedBinding.origin } } : {},
135124
136023
  mode: "sync",
135125
136024
  refused: REFUSED_SUMMARY,
135126
- help: nextSteps(result3.binding.path)
136025
+ help: nextSteps2(result3.binding.path)
135127
136026
  },
135128
136027
  mode
135129
136028
  )
135130
136029
  );
135131
136030
  }
135132
- async function connectHostedBundle(typed, target3, workspaceFlag2, deps2, resume2) {
136031
+ async function exportOrReason(request3) {
136032
+ try {
136033
+ return await fetchExportThrough(request3);
136034
+ } catch (error51) {
136035
+ if (!(error51 instanceof CliError)) throw error51;
136036
+ if (error51.details?.code === "not_found" && error51.details?.status === 404) return `${request3.source.target.origin} serves no bundle export`;
136037
+ const reason = error51.details?.reason ?? error51.details?.code;
136038
+ return `the bundle export could not be read: ${error51.message.replace(/; nothing was written$/, "")}${typeof reason === "string" ? ` (${reason})` : ""}`;
136039
+ }
136040
+ }
136041
+ async function adoptedExtras(folder, request3) {
136042
+ const portable = await exportOrReason(request3);
136043
+ if (typeof portable === "string") return { extras: {}, placed: /* @__PURE__ */ new Map(), unplaced: portable };
136044
+ const extras = {};
136045
+ const placed = /* @__PURE__ */ new Map();
136046
+ for (const entry of portable.entries) {
136047
+ if (entry.kind === "document" || entry.path === ROOT_INDEX) continue;
136048
+ const file2 = path56.join(folder, ...entry.path.split("/"));
136049
+ if (await parentUnsafe(folder, file2)) continue;
136050
+ const found = readRegularFileNoFollowSync(file2);
136051
+ if (found.state === "missing") {
136052
+ try {
136053
+ await ensureParentInside(folder, file2);
136054
+ } catch (error51) {
136055
+ if (error51 instanceof UnsafePlacementError) continue;
136056
+ throw error51;
136057
+ }
136058
+ if ((await placeNew(file2, entry.bytes)).placed) {
136059
+ extras[entry.path] = digestOf(entry.bytes);
136060
+ placed.set(file2, digestOf(entry.bytes));
136061
+ }
136062
+ continue;
136063
+ }
136064
+ if (found.state === "present" && Buffer.from(entry.bytes).equals(found.bytes)) extras[entry.path] = digestOf(entry.bytes);
136065
+ }
136066
+ return { extras, placed, unplaced: null };
136067
+ }
136068
+ async function placeExtras(exported, folder, onPlaced) {
136069
+ const placed = {};
136070
+ const kept = [];
136071
+ let reserved = 0;
136072
+ let other = 0;
136073
+ for (const entry of exported.entries) {
136074
+ if (entry.kind === "document" || entry.path === ROOT_INDEX) continue;
136075
+ const file2 = path56.join(folder, ...entry.path.split("/"));
136076
+ try {
136077
+ await ensureParentInside(folder, file2);
136078
+ } catch (error51) {
136079
+ if (!(error51 instanceof UnsafePlacementError)) throw error51;
136080
+ kept.push(entry.path);
136081
+ continue;
136082
+ }
136083
+ const outcome = await placeNew(file2, entry.bytes);
136084
+ if (!outcome.placed) {
136085
+ kept.push(entry.path);
136086
+ continue;
136087
+ }
136088
+ const digest3 = digestOf(entry.bytes);
136089
+ onPlaced(file2, digest3);
136090
+ placed[entry.path] = digest3;
136091
+ if (entry.kind === "reserved") reserved += 1;
136092
+ else other += 1;
136093
+ }
136094
+ return { placed, reserved, other, kept };
136095
+ }
136096
+ async function connectHostedBundle(typed, target3, workspaceFlag2, deps2, resume2, options = {}) {
135133
136097
  const { bundleId: bundleId2 } = typed;
135134
136098
  const command = (named) => `${cliInvocation()} checkout ${commandToken(named)} --host ${commandToken(hostArgument(target3))}`;
135135
136099
  const account = await connectHostedAccount(
135136
136100
  target3,
135137
- { workspace: workspaceFlag2, resume: resume2, otherWorkspace: `${command(hostedBundleReferenceText(typed))} --workspace <id>` },
136101
+ {
136102
+ workspace: workspaceFlag2,
136103
+ resume: resume2,
136104
+ otherWorkspace: `${command(hostedBundleReferenceText(typed))} --workspace <id>`,
136105
+ ...options.deadlineMs !== void 0 ? { deadlineMs: options.deadlineMs } : {}
136106
+ },
135138
136107
  deps2
135139
136108
  );
135140
136109
  const { client, identity, workspace } = account;
@@ -135218,7 +136187,7 @@ function assertProjectable(ids, bundleId2, target3) {
135218
136187
  });
135219
136188
  }
135220
136189
  }
135221
- var CHECKOUT_DOCUMENT_LIMIT, CHECKOUT_USAGE, REFUSED_SUMMARY;
136190
+ var CHECKOUT_DOCUMENT_LIMIT, CHECKOUT_USAGE, NO_EXTRAS, REFUSED_SUMMARY;
135222
136191
  var init_checkout = __esm({
135223
136192
  "../cli/src/commands/checkout.ts"() {
135224
136193
  "use strict";
@@ -135236,6 +136205,7 @@ var init_checkout = __esm({
135236
136205
  init_invocation();
135237
136206
  init_output2();
135238
136207
  init_private_state_bundle_boundary();
136208
+ init_nofollow_read();
135239
136209
  init_session();
135240
136210
  init_account();
135241
136211
  init_freshness2();
@@ -135247,6 +136217,7 @@ var init_checkout = __esm({
135247
136217
  init_catalog();
135248
136218
  init_marker();
135249
136219
  init_checkout_adopt();
136220
+ init_export();
135250
136221
  init_reference();
135251
136222
  CHECKOUT_DOCUMENT_LIMIT = 1e4;
135252
136223
  CHECKOUT_USAGE = `superbee checkout \u2014 mirror a hosted bundle into a local folder
@@ -135262,8 +136233,11 @@ hosted bundle into --dir (default: ./<bundle-id>), which must be new or empty. T
135262
136233
  else, for a folder that is already a checkout, its own host, else the host of your last sign-in
135263
136234
  when it is the only host you are signed in to (never SUPERBEE_HOST alone); signed in to more than
135264
136235
  one host, a checkout without --host is refused and names them. The receipt names the host it
135265
- bound. The folder holds plain bundle files, so every command runs on it with --dir <folder>. The
135266
- link to the host is kept in private state, keyed by the folder's path, never in the folder.
136236
+ bound. The folder holds plain bundle files, so every command runs on it with --dir <folder>: the
136237
+ same files 'superbee export' writes (documents, every index.md and log.md, and other files such as
136238
+ data/*.json), with the bytes the host stores. Sync sends documents only; it leaves the other files
136239
+ be while they are as placed. The link to the host is kept in private state, keyed by the folder's
136240
+ path, never in the folder.
135267
136241
  Re-running for the same folder and bundle is a no-op. A checkout whose folder was deleted, or
135268
136242
  replaced by a new empty folder, is replaced, unless it holds changes sync has not sent yet; a
135269
136243
  checkout emptied in place is refused, because removing every file is a pending edit.
@@ -135321,6 +136295,7 @@ Examples:
135321
136295
  superbee checkout --adopt ~/restored/team --host https://mcp.getsuperbee.com
135322
136296
  superbee checkout --release ~/work/team
135323
136297
  `;
136298
+ NO_EXTRAS = Object.freeze({ placed: {}, reserved: 0, other: 0, kept: [] });
135324
136299
  REFUSED_SUMMARY = Object.freeze(
135325
136300
  HOSTED_CHECKOUT_REFUSALS.filter((row4) => row4.reason !== "checkout_target").map((row4) => {
135326
136301
  const words = row4.words.join(" ");
@@ -135330,800 +136305,6 @@ Examples:
135330
136305
  }
135331
136306
  });
135332
136307
 
135333
- // ../cli/src/commands/export.ts
135334
- import { randomBytes as randomBytes9 } from "node:crypto";
135335
- import { homedir as homedir40 } from "node:os";
135336
- import { link as link3, lstat as lstat10, mkdir as mkdir5, open as open4, readdir as readdir9, realpath as realpath13, rename as rename2, rm as rm2, unlink as unlink14 } from "node:fs/promises";
135337
- import path56 from "node:path";
135338
- import { parseArgs as parseArgs42 } from "node:util";
135339
- function exportDeps(partial2) {
135340
- return {
135341
- stdout: partial2.stdout ?? ((text5) => void process.stdout.write(text5)),
135342
- auth: partial2.auth ?? defaultHostedAuthDeps(homedir40()),
135343
- cwd: partial2.cwd ?? process.cwd(),
135344
- ...partial2.fetch ? { fetch: partial2.fetch } : {}
135345
- };
135346
- }
135347
- async function entryKind2(target3) {
135348
- let info;
135349
- try {
135350
- info = await lstat10(target3);
135351
- } catch (error51) {
135352
- if (error51.code === "ENOENT") return "absent";
135353
- throw error51;
135354
- }
135355
- if (!info.isDirectory()) return "other";
135356
- return (await readdir9(target3)).length === 0 ? "empty-dir" : "dir";
135357
- }
135358
- function shown(paths) {
135359
- return [...paths].sort().slice(0, SHOWN);
135360
- }
135361
- function refusalCode(body) {
135362
- const error51 = body?.error;
135363
- if (typeof error51 === "string") return error51;
135364
- const code3 = error51?.code;
135365
- return typeof code3 === "string" ? code3 : void 0;
135366
- }
135367
- async function namedClient(source, deps2, resume2) {
135368
- const { target: target3 } = source;
135369
- const account = await connectHostedAccount(target3, { ...source.workspace !== null ? { workspace: source.workspace } : {}, resume: resume2, deadlineMs: EXPORT_DEADLINE_MS }, deps2);
135370
- const { reference } = resolveBundleReference(
135371
- { slug: source.slug, bundleId: source.bundleId },
135372
- account,
135373
- target3,
135374
- (named) => `${cliInvocation()} export ${commandToken(named)} --host ${commandToken(hostArgument(target3))} --to <folder>`
135375
- );
135376
- return { client: reference.slug === null ? account.client : account.client.within(reference.slug), slug: reference.slug };
135377
- }
135378
- async function fetchExport(source, deps2, resume2) {
135379
- const { bundleId: bundleId2, target: target3 } = source;
135380
- const named = source.binding ? null : await namedClient(source, deps2, resume2);
135381
- const client = named ? named.client : (await connectCheckout(source.binding, { resume: resume2, deadlineMs: EXPORT_DEADLINE_MS }, deps2)).client;
135382
- const slug = named ? named.slug : source.binding.workspace_slug ?? null;
135383
- const request3 = { client, slug, source, resume: resume2 };
135384
- for (let attempt = 1; ; attempt += 1) {
135385
- const chain = new ExportPageChain();
135386
- let bytes = 0;
135387
- let cursor;
135388
- let moved = false;
135389
- for (; ; ) {
135390
- let page;
135391
- for (let tries = 1; page === void 0; tries += 1) {
135392
- const answer2 = await exportAnswer(request3, { bundleId: bundleId2, paged: true, ...cursor !== void 0 ? { cursor } : {} });
135393
- if (answer2.refused === "invalid_input" && cursor === void 0 && attempt === 1) return verified(await readArchive(await wholeAnswer(request3), source, MAX_EXPORT_BYTES), source);
135394
- if (answer2.refused === "concurrent_change") {
135395
- moved = true;
135396
- break;
135397
- }
135398
- try {
135399
- if (answer2.refused !== void 0) throw await exportRefusal(request3, answer2.refused, answer2.status);
135400
- page = verified(await readArchive(answer2.ok, source, MAX_EXPORT_BYTES - bytes), source, { paged: true });
135401
- } catch (error51) {
135402
- const again = error51 instanceof CliError && (error51.details?.reason === "export_incomplete" || answer2.refused === "backend_unavailable" && error51.code === "TRANSIENT");
135403
- if (!again || tries >= 2) throw error51;
135404
- await pause2(PAGE_RETRY_MS);
135405
- }
135406
- }
135407
- if (moved) break;
135408
- bytes += page.bytes;
135409
- cursor = joining(source, () => chain.add(page));
135410
- if (cursor === void 0) return joining(source, () => chain.joined());
135411
- }
135412
- if (attempt >= PAGED_EXPORT_ATTEMPTS) {
135413
- throw new CliError("TRANSIENT", `'${bundleId2}' kept changing on ${target3.origin} while it was exported; nothing was written`, {
135414
- details: { reason: "export_source_changed", bundle_id: bundleId2, host: target3.origin, retryable: true },
135415
- help: "retry the same command once the bundle is not being edited"
135416
- });
135417
- }
135418
- const base = PAGED_EXPORT_RESTART_MS[attempt - 1];
135419
- await pause2(Math.round(base / 2 + Math.random() * base / 2));
135420
- }
135421
- }
135422
- async function exportAnswer({ client, source, resume: resume2 }, input) {
135423
- let answer2;
135424
- try {
135425
- answer2 = await client.carrier.stream(`${client.prefix}/export`, input, client.signal);
135426
- } catch (error51) {
135427
- throw hostedFailure(error51, source.target, resume2);
135428
- }
135429
- if (!answer2.ok) return { refused: refusalCode(answer2.body) ?? "RUNTIME", status: answer2.status };
135430
- return { ok: answer2.body };
135431
- }
135432
- async function wholeAnswer(request3) {
135433
- const answer2 = await exportAnswer(request3, { bundleId: request3.source.bundleId });
135434
- if (answer2.refused !== void 0) throw await exportRefusal(request3, answer2.refused, answer2.status);
135435
- return answer2.ok;
135436
- }
135437
- function exportTooLarge(source) {
135438
- return new CliError("RUNTIME", `${source.target.origin} answered an export larger than ${MAX_EXPORT_BYTES} bytes`, {
135439
- details: { reason: "export_too_large", host: source.target.origin, bundle_id: source.bundleId, retryable: false, next: "the person exports it with Export bundle in the Superbee app" },
135440
- help: `${cliInvocation()} whoami --host ${commandToken(hostArgument(source.target))}`
135441
- });
135442
- }
135443
- async function exportRefusal({ client, slug, source, resume: resume2 }, code3, status2) {
135444
- const { target: target3, bundleId: bundleId2 } = source;
135445
- if (code3 === "bundle_not_found") {
135446
- if (source.binding) return await bundleAbsent(source.binding, client);
135447
- const text5 = hostedBundleReferenceText({ slug, bundleId: bundleId2 });
135448
- return new CliError("NOT_FOUND", `no hosted bundle '${text5}' is visible to you on ${target3.origin}`, {
135449
- details: { bundle_id: bundleId2, ...slug !== null ? { reference: text5 } : {}, host: target3.origin },
135450
- help: hostedListCommand(target3)
135451
- });
135452
- }
135453
- if (code3 === "result_too_large") {
135454
- return new CliError("FORBIDDEN", `hosted bundle '${bundleId2}' is larger than an export carries`, {
135455
- details: { reason: "bundle_too_large", bundle_id: bundleId2, host: target3.origin, next: "the person exports it with Export bundle in the Superbee app" },
135456
- help: `${cliInvocation()} whoami --host ${commandToken(hostArgument(target3))}`
135457
- });
135458
- }
135459
- if (code3 === "validation_failed") {
135460
- return new CliError("FORBIDDEN", `hosted bundle '${bundleId2}' holds a path an export cannot carry`, {
135461
- details: { reason: "unexportable_path", bundle_id: bundleId2, host: target3.origin, next: "the person renames the document or file in the Superbee app, then the same command is retried" },
135462
- help: `${cliInvocation()} whoami --host ${commandToken(hostArgument(target3))}`
135463
- });
135464
- }
135465
- return hostedFailure(new RemoteError(`hosted export answered ${status2}`, code3, status2), target3, resume2);
135466
- }
135467
- async function readArchive(body, source, budget) {
135468
- const { target: target3, bundleId: bundleId2 } = source;
135469
- const reader = body.getReader();
135470
- const chunks = [];
135471
- let size = 0;
135472
- try {
135473
- for (; ; ) {
135474
- const part = await reader.read();
135475
- if (part.done) break;
135476
- size += part.value.byteLength;
135477
- if (size > budget) throw exportTooLarge(source);
135478
- chunks.push(part.value);
135479
- }
135480
- } catch (error51) {
135481
- if (error51 instanceof CliError) throw error51;
135482
- throw new CliError("TRANSIENT", `the export of '${bundleId2}' from ${target3.origin} stopped part way; nothing was written`, {
135483
- details: { reason: "export_incomplete", bundle_id: bundleId2, host: target3.origin, retryable: true },
135484
- help: "retry the same command"
135485
- });
135486
- } finally {
135487
- void reader.cancel().catch(() => {
135488
- });
135489
- }
135490
- const archive = new Uint8Array(size);
135491
- let offset = 0;
135492
- for (const chunk of chunks) {
135493
- archive.set(chunk, offset);
135494
- offset += chunk.byteLength;
135495
- }
135496
- return archive;
135497
- }
135498
- function verified(archive, source, options = {}) {
135499
- return refusingArchive(source, () => verifyExport(archive, source.bundleId, options));
135500
- }
135501
- function joining(source, join19) {
135502
- return refusingArchive(source, join19);
135503
- }
135504
- function refusingArchive(source, verify) {
135505
- try {
135506
- return verify();
135507
- } catch (error51) {
135508
- if (!(error51 instanceof ExportArchiveError)) throw error51;
135509
- if (error51.problem === "incomplete") {
135510
- throw new CliError("TRANSIENT", `the export of '${source.bundleId}' was not completed by the host; nothing was written`, {
135511
- details: { reason: "export_incomplete", bundle_id: source.bundleId, host: source.target.origin, retryable: true },
135512
- help: "retry the same command"
135513
- });
135514
- }
135515
- throw new CliError("RUNTIME", `${source.target.origin} answered an export this CLI refuses (${error51.message}); nothing was written`, {
135516
- details: { reason: `export_${error51.problem}`, bundle_id: source.bundleId, host: source.target.origin, retryable: false },
135517
- help: "upgrade Superbee (npm install -g superbee); if it persists, report this bundle and reason"
135518
- });
135519
- }
135520
- }
135521
- async function writeNewFile(file2, bytes) {
135522
- const handle = await open4(file2, "wx", 420);
135523
- try {
135524
- await handle.writeFile(bytes);
135525
- await handle.sync();
135526
- } finally {
135527
- await handle.close();
135528
- }
135529
- }
135530
- async function writeEntries(root, entries) {
135531
- for (const entry of entries) {
135532
- const file2 = path56.join(root, ...entry.path.split("/"));
135533
- await mkdir5(path56.dirname(file2), { recursive: true });
135534
- await writeNewFile(file2, entry.bytes);
135535
- }
135536
- }
135537
- function gitRun(dir, args) {
135538
- let result3;
135539
- try {
135540
- result3 = runGit(dir, args);
135541
- } catch (error51) {
135542
- const missing2 = error51.code === "GIT_MISSING";
135543
- throw new CliError(missing2 ? "GIT_MISSING" : "RUNTIME", `git could not run (${error51 instanceof Error ? error51.message : String(error51)})`, {
135544
- details: { reason: missing2 ? "git_missing" : "git_unavailable" },
135545
- help: "install git, or export without --git"
135546
- });
135547
- }
135548
- if (result3.status !== 0) {
135549
- throw new CliError("RUNTIME", `git ${args.find((arg) => !arg.startsWith("-") && !arg.includes("=")) ?? ""} failed: ${result3.stderr.trim().split("\n").at(-1) ?? ""}`, {
135550
- details: { reason: "git_failed" },
135551
- help: "fix the git error, then retry the same command"
135552
- });
135553
- }
135554
- return result3.stdout.trim();
135555
- }
135556
- function commitExport(dir, message, options) {
135557
- const quiet = ["-c", "core.hooksPath=/dev/null"];
135558
- gitRun(dir, [...quiet, "init", "-q"]);
135559
- gitRun(dir, ["symbolic-ref", "HEAD", `refs/heads/${BOARD_BRANCH}`]);
135560
- const excluded = ["--", ".", `:(exclude)${IN_PLACE_STAGING}`, `:(exclude)${CHECKOUT_MARKER_DIR}`];
135561
- gitRun(dir, ["add", "-A", ...options.force ? ["--force"] : [], ...excluded]);
135562
- gitRun(dir, [...quiet, ...identityFlags(dir), "-c", "commit.gpgsign=false", "commit", "-q", "--no-verify", "--allow-empty", "-m", message]);
135563
- const committed = { branch: BOARD_BRANCH, commit: gitRun(dir, ["rev-parse", "HEAD"]) };
135564
- if (options.force) return committed;
135565
- const ignored = gitRun(dir, ["ls-files", "--others", "--ignored", "--exclude-standard", ...excluded]).split("\n").filter(Boolean);
135566
- return ignored.length === 0 ? committed : { ...committed, ignored: { count: ignored.length, paths: shown(ignored) } };
135567
- }
135568
- function commitMessage(source, exported) {
135569
- return `Export ${source.bundleId} from ${source.target.origin} at revision ${exported.source.revision}
135570
-
135571
- superbee export, ${exported.exportedAt}: ${exported.counts.documents} documents, ${exported.counts.reserved} reserved files, ${exported.counts.blobs} blobs. History is not included.
135572
- `;
135573
- }
135574
- function stagingName(target3) {
135575
- return path56.join(path56.dirname(target3), `.${path56.basename(target3)}.superbee-export-${process.pid}-${randomBytes9(6).toString("hex")}.partial`);
135576
- }
135577
- function processAlive(pid) {
135578
- try {
135579
- process.kill(pid, 0);
135580
- return true;
135581
- } catch (error51) {
135582
- return error51.code === "EPERM";
135583
- }
135584
- }
135585
- async function removeAbandonedStaging(target3) {
135586
- const prefix = `.${path56.basename(target3)}.superbee-export-`;
135587
- let removed = 0;
135588
- let names;
135589
- try {
135590
- names = await readdir9(path56.dirname(target3));
135591
- } catch {
135592
- return 0;
135593
- }
135594
- for (const name of names) {
135595
- if (!name.startsWith(prefix)) continue;
135596
- const match = /^(\d+)-[0-9a-f]{12}\.partial$/.exec(name.slice(prefix.length));
135597
- if (!match) continue;
135598
- const age = await lstat10(path56.join(path56.dirname(target3), name)).then((info) => Date.now() - info.mtimeMs, () => 0);
135599
- if (processAlive(Number(match[1])) && age < ABANDONED_AFTER_MS) continue;
135600
- await rm2(path56.join(path56.dirname(target3), name), { recursive: true, force: true });
135601
- removed += 1;
135602
- }
135603
- return removed;
135604
- }
135605
- async function assertStandalone(target3, home2) {
135606
- const parent = path56.dirname(target3);
135607
- const help2 = "pass --to <folder> outside any bundle, board or checkout";
135608
- const checkout2 = await hostedCheckoutAt(parent, home2);
135609
- if (checkout2) {
135610
- throw new CliError("FORBIDDEN", `refusing to export inside the hosted checkout at ${checkout2.path}`, { details: { reason: "inside_checkout", enclosing: checkout2.path }, help: help2 });
135611
- }
135612
- const enclosing = await findBundleRoot(parent).catch(() => null);
135613
- if (enclosing) {
135614
- throw new CliError("FORBIDDEN", `refusing to export inside the local bundle at ${enclosing}`, { details: { reason: "inside_bundle", enclosing }, help: help2 });
135615
- }
135616
- const binding = await resolveProjectBinding(parent).catch(() => null);
135617
- if (binding) {
135618
- throw new CliError("FORBIDDEN", `refusing to export inside a project bound to a board (${binding.file})`, { details: { reason: "inside_bound_project", binding: binding.file }, help: help2 });
135619
- }
135620
- }
135621
- async function exportToFolder(source, toArg, git2, deps2, mode, resume2) {
135622
- const requested = path56.resolve(deps2.cwd, toArg);
135623
- assertBundleOutsidePrivateState(requested, deps2.auth.home);
135624
- const found = await entryKind2(requested);
135625
- if (found === "other") throw new CliError("ALREADY_EXISTS", `${requested} exists and is not a folder`, { details: { reason: "not_a_folder", folder: requested }, help: "pass --to <new folder>" });
135626
- if (found === "dir") throw new CliError("ALREADY_EXISTS", `${requested} is not empty`, { details: { reason: "not_empty", folder: requested }, help: "pass --to <new or empty folder>" });
135627
- await mkdir5(path56.dirname(requested), { recursive: true });
135628
- const target3 = path56.join(await realpath13(path56.dirname(requested)), path56.basename(requested));
135629
- assertBundleOutsidePrivateState(target3, deps2.auth.home);
135630
- await assertStandalone(target3, deps2.auth.home);
135631
- const exported = await fetchExport(source, deps2, resume2);
135632
- const abandoned = await removeAbandonedStaging(target3);
135633
- const staging = stagingName(target3);
135634
- await mkdir5(staging);
135635
- let gitResult = null;
135636
- try {
135637
- await writeEntries(staging, exported.entries);
135638
- if (git2) gitResult = commitExport(staging, commitMessage(source, exported), { force: true });
135639
- const now = await entryKind2(target3);
135640
- if (now === "dir" || now === "other") throw new CliError("ALREADY_EXISTS", `${target3} is no longer empty`, { details: { reason: "not_empty", folder: target3 }, help: "pass --to <new or empty folder>" });
135641
- try {
135642
- await rename2(staging, target3);
135643
- } catch (error51) {
135644
- const code3 = error51.code;
135645
- if (code3 === "ENOTEMPTY" || code3 === "EEXIST" || code3 === "ENOTDIR") {
135646
- throw new CliError("ALREADY_EXISTS", `${target3} is no longer empty`, { details: { reason: "not_empty", folder: target3 }, help: "pass --to <new or empty folder>" });
135647
- }
135648
- throw error51;
135649
- }
135650
- } catch (error51) {
135651
- await rm2(staging, { recursive: true, force: true }).catch(() => {
135652
- });
135653
- throw error51;
135654
- }
135655
- const home2 = await bundleHomeAt(target3, { home: deps2.auth.home });
135656
- deps2.stdout(
135657
- render(
135658
- {
135659
- export: "created",
135660
- folder: target3,
135661
- home: home2.home,
135662
- bundle_id: source.bundleId,
135663
- host: source.target.origin,
135664
- revision: exported.source.revision,
135665
- exported_at: exported.exportedAt,
135666
- okf_edition: exported.source.okfEdition,
135667
- documents: exported.counts.documents,
135668
- reserved: exported.counts.reserved,
135669
- blobs: exported.counts.blobs,
135670
- bytes: exported.bytes,
135671
- root_index: exported.entries.some((entry) => entry.path === "index.md"),
135672
- ...gitResult ? { git: gitResult } : {},
135673
- ...abandoned > 0 ? { removed_abandoned_exports: abandoned } : {},
135674
- hosted: HOSTED_UNCHANGED,
135675
- history: NO_HISTORY,
135676
- help: nextSteps2(target3, gitResult !== null)
135677
- },
135678
- mode
135679
- )
135680
- );
135681
- }
135682
- function nextSteps2(folder, git2) {
135683
- const steps = [commandFragment`${cliInvocation()} status --dir ${commandToken(folder)}`];
135684
- if (git2) steps.push(commandFragment`git -C ${commandToken(folder)} remote add origin <url> && ${cliInvocation()} sync --establish --dir ${commandToken(folder)}`);
135685
- return steps;
135686
- }
135687
- function isJournal(value) {
135688
- const record6 = value;
135689
- return record6 !== null && typeof record6 === "object" && record6.schema === JOURNAL_SCHEMA && typeof record6.bundle_id === "string" && typeof record6.host === "string" && typeof record6.audience === "string" && Number.isSafeInteger(record6.revision) && typeof record6.exported_at === "string" && typeof record6.git === "boolean" && Array.isArray(record6.adds) && record6.adds.every((entry) => typeof entry === "string") && Number.isSafeInteger(record6.same) && Array.isArray(record6.kept_local) && record6.kept_local.every((entry) => typeof entry === "string") && Array.isArray(record6.deleted_locally) && record6.deleted_locally.every((entry) => typeof entry === "string") && Number.isSafeInteger(record6.unsent_kept);
135690
- }
135691
- async function stagingDir(folder) {
135692
- const staging = path56.join(folder, IN_PLACE_STAGING);
135693
- try {
135694
- if (!(await lstat10(staging)).isDirectory()) return null;
135695
- return await realpath13(staging) === path56.join(await realpath13(folder), IN_PLACE_STAGING) ? staging : null;
135696
- } catch {
135697
- return null;
135698
- }
135699
- }
135700
- async function readJournal(folder) {
135701
- const staging = await stagingDir(folder);
135702
- if (!staging) return null;
135703
- let journal;
135704
- const read = readRegularFileNoFollowSync(path56.join(staging, JOURNAL));
135705
- if (read.state !== "present" || read.bytes.byteLength > MAX_JOURNAL_BYTES) return null;
135706
- try {
135707
- const value = JSON.parse(read.bytes.toString("utf8"));
135708
- if (!isJournal(value)) return null;
135709
- journal = value;
135710
- } catch {
135711
- return null;
135712
- }
135713
- const marker = readCheckoutMarker(folder);
135714
- if (!marker || marker.bundle_id !== journal.bundle_id || marker.host !== bindingHostArgument({ origin: journal.host, audience: journal.audience })) return null;
135715
- return journal;
135716
- }
135717
- async function sameBytes(file2, bytes) {
135718
- const read = readRegularFileNoFollowSync(file2);
135719
- return read.state === "present" && Buffer.compare(read.bytes, Buffer.from(bytes)) === 0;
135720
- }
135721
- async function placementOf(folder, entry) {
135722
- let info;
135723
- try {
135724
- info = await lstat10(path56.join(folder, ...entry.path.split("/")));
135725
- } catch (error51) {
135726
- const code3 = error51.code;
135727
- if (code3 === "ENOENT") return "add";
135728
- if (code3 === "ENOTDIR") return "kept";
135729
- throw error51;
135730
- }
135731
- if (!info.isFile()) return "kept";
135732
- return await sameBytes(path56.join(folder, ...entry.path.split("/")), entry.bytes) ? "same" : "kept";
135733
- }
135734
- async function placeStaged(folder, staging, relative2) {
135735
- const final = path56.join(folder, ...relative2.split("/"));
135736
- const staged = path56.join(staging, "files", ...relative2.split("/"));
135737
- try {
135738
- if ((await lstat10(staged)).isFile()) {
135739
- const stagedParent = await realpath13(path56.dirname(staged));
135740
- if (!stagedParent.startsWith(`${await realpath13(staging)}${path56.sep}`)) return "kept";
135741
- } else return "kept";
135742
- } catch (error51) {
135743
- if (error51.code !== "ENOENT") return "kept";
135744
- return await lstat10(final).then((info) => info.isFile(), () => false) ? "same" : "kept";
135745
- }
135746
- try {
135747
- await mkdir5(path56.dirname(final), { recursive: true });
135748
- const parent = await realpath13(path56.dirname(final));
135749
- if (parent !== folder && !parent.startsWith(`${folder}${path56.sep}`)) return "kept";
135750
- } catch {
135751
- return "kept";
135752
- }
135753
- let outcome;
135754
- try {
135755
- await link3(staged, final);
135756
- outcome = "added";
135757
- } catch (error51) {
135758
- const code3 = error51.code;
135759
- if (code3 !== "EEXIST") throw error51;
135760
- const stagedRead = readRegularFileNoFollowSync(staged);
135761
- outcome = stagedRead.state === "present" && await sameBytes(final, stagedRead.bytes) ? "same" : "kept";
135762
- }
135763
- await unlink14(staged).catch(() => {
135764
- });
135765
- return outcome;
135766
- }
135767
- async function writeJournal(staging, journal) {
135768
- const temp = path56.join(staging, `.${JOURNAL}.${randomBytes9(6).toString("hex")}.tmp`);
135769
- await writeNewFile(temp, Buffer.from(`${JSON.stringify(journal)}
135770
- `, "utf8"));
135771
- await rename2(temp, path56.join(staging, JOURNAL));
135772
- }
135773
- async function finishInPlace(folder, journal) {
135774
- const staging = await stagingDir(folder);
135775
- if (!staging) throw new CliError("RUNTIME", `the in-place export's staging folder in ${folder} is gone`, { help: `${cliInvocation()} export --in-place --dir ${commandToken(folder)}` });
135776
- const added = [];
135777
- const kept = [...journal.kept_local];
135778
- let same = journal.same;
135779
- for (const relative2 of journal.adds) {
135780
- classifyEntryPath(relative2);
135781
- const outcome = await placeStaged(folder, staging, relative2);
135782
- if (outcome === "added") added.push(relative2);
135783
- else if (outcome === "same") same += 1;
135784
- else kept.push(relative2);
135785
- }
135786
- let git2 = null;
135787
- if (journal.git) {
135788
- git2 = await ownCommit(folder) ?? commitExport(folder, `Export ${journal.bundle_id} from ${journal.host} at revision ${journal.revision}
135789
-
135790
- superbee export --in-place, ${journal.exported_at}. History is not included.
135791
- `, { force: false });
135792
- }
135793
- await rm2(path56.join(staging, "files"), { recursive: true, force: true });
135794
- await unlink14(path56.join(staging, JOURNAL)).catch(() => {
135795
- });
135796
- await rm2(staging, { recursive: true, force: true });
135797
- const marker = await removeCheckoutMarker(folder, { origin: journal.host, audience: journal.audience, bundle_id: journal.bundle_id }).catch(() => false) ? "removed" : "none";
135798
- return { added, kept, same, git: git2, marker };
135799
- }
135800
- function inPlaceReceipt(folder, journal, finished, homeName, resumed) {
135801
- return {
135802
- export: "converted",
135803
- folder,
135804
- home: homeName,
135805
- bundle_id: journal.bundle_id,
135806
- host: journal.host,
135807
- revision: journal.revision,
135808
- exported_at: journal.exported_at,
135809
- ...resumed ? { resumed: true } : {},
135810
- binding: "removed (the folder is no longer a hosted checkout)",
135811
- marker: finished.marker,
135812
- added: finished.added.length,
135813
- ...finished.added.length > 0 ? { added_paths: shown(finished.added) } : {},
135814
- unchanged: finished.same,
135815
- kept_local: finished.kept.length,
135816
- ...finished.kept.length > 0 ? { kept_local_paths: shown(finished.kept), kept_local_note: "these files differ from the host's (or block its path); the folder's own were kept" } : {},
135817
- ...journal.deleted_locally.length > 0 ? { deleted_locally: journal.deleted_locally.length, deleted_locally_paths: shown(journal.deleted_locally), deleted_locally_note: "deleted in this folder and not sent; the host's copies were not put back" } : {},
135818
- ...journal.unsent_kept > 0 ? { unsent_kept: journal.unsent_kept, unsent_note: "changes sync had not sent stay in this folder only" } : {},
135819
- ...finished.git ? { git: finished.git } : {},
135820
- hosted: HOSTED_UNCHANGED,
135821
- history: NO_HISTORY,
135822
- help: nextSteps2(folder, finished.git !== null)
135823
- };
135824
- }
135825
- async function ownCommit(folder) {
135826
- const head = runGit(folder, ["rev-parse", "--verify", "--quiet", "HEAD"]);
135827
- const top = runGit(folder, ["rev-parse", "--show-toplevel"]);
135828
- const own5 = top.status === 0 && await realpath13(top.stdout.trim()).catch(() => "") === await realpath13(folder).catch(() => folder);
135829
- if (!own5 || head.status !== 0) return null;
135830
- return { branch: runGit(folder, ["symbolic-ref", "-q", "--short", "HEAD"]).stdout.trim() || BOARD_BRANCH, commit: head.stdout.trim() };
135831
- }
135832
- async function assertNoRepository(folder) {
135833
- if (await lstat10(path56.join(folder, ".git")).then(() => true, () => false)) {
135834
- throw new CliError("ALREADY_EXISTS", `${folder} already holds a Git repository`, {
135835
- details: { reason: "already_git", folder },
135836
- help: `${cliInvocation()} export --in-place --dir ${commandToken(folder)}`
135837
- });
135838
- }
135839
- }
135840
- async function exportInPlace(dirArg, git2, keepUnsent, deps2, mode, resume2) {
135841
- const requested = path56.resolve(deps2.cwd, dirArg ?? ".");
135842
- assertBundleOutsidePrivateState(requested, deps2.auth.home);
135843
- const binding = await hostedCheckoutFor(dirArg === void 0 ? [] : ["--dir", dirArg], deps2.auth.home, deps2.cwd);
135844
- if (!binding) {
135845
- const folder2 = await realpath13(requested).catch(() => requested);
135846
- const journal = await readJournal(folder2);
135847
- if (journal) {
135848
- const finished = await finishInPlace(folder2, journal);
135849
- const home4 = await bundleHomeAt(folder2, { home: deps2.auth.home });
135850
- deps2.stdout(render(inPlaceReceipt(folder2, journal, finished, home4.home, true), mode));
135851
- return;
135852
- }
135853
- if (await entryKind2(folder2) === "absent") throw new CliError("NOT_FOUND", `${folder2} does not exist`, { help: `${cliInvocation()} export --in-place --dir <checkout folder>` });
135854
- const marker = readCheckoutMarker(folder2);
135855
- if (marker) {
135856
- const existing = git2 ? await ownCommit(folder2) : null;
135857
- if (git2 && !existing) await assertNoRepository(folder2);
135858
- const staging = await stagingDir(folder2);
135859
- if (staging && !await lstat10(path56.join(staging, JOURNAL)).then(() => true, () => false)) await rm2(staging, { recursive: true, force: true });
135860
- await removeCheckoutMarker(folder2, { origin: marker.host, audience: `${marker.host}/mcp`, bundle_id: marker.bundle_id });
135861
- const committed = existing ?? (git2 ? commitExport(folder2, `Export ${marker.bundle_id} (an unbound copy of a hosted checkout)
135862
-
135863
- superbee export --in-place. Nothing was fetched from the host; history is not included.
135864
- `, { force: false }) : null);
135865
- const home4 = await bundleHomeAt(folder2, { home: deps2.auth.home });
135866
- deps2.stdout(
135867
- render(
135868
- {
135869
- export: "converted",
135870
- folder: folder2,
135871
- home: home4.home,
135872
- bundle_id: marker.bundle_id,
135873
- from: "an unbound copy of a hosted checkout",
135874
- marker: "removed",
135875
- fetched: false,
135876
- note: `nothing was fetched: the files are kept as they are. To fill in what the copy lacks from the host first, adopt it (${cliInvocation()} checkout --adopt <folder> --host <url>), then export --in-place`,
135877
- ...committed ? { git: committed } : {},
135878
- hosted: HOSTED_UNCHANGED,
135879
- history: NO_HISTORY,
135880
- help: nextSteps2(folder2, committed !== null)
135881
- },
135882
- mode
135883
- )
135884
- );
135885
- return;
135886
- }
135887
- const home3 = await bundleHomeAt(folder2, { home: deps2.auth.home });
135888
- deps2.stdout(render({ export: "unchanged", folder: folder2, home: home3.home, reason: "not a hosted checkout: nothing to convert" }, mode));
135889
- return;
135890
- }
135891
- const folder = binding.path;
135892
- if (git2) await assertNoRepository(folder);
135893
- const status2 = await hostedStatus(binding, deps2.auth.home);
135894
- if (status2.sync.state === "busy") {
135895
- throw new CliError("CONFLICT", `another command holds the checkout lock for ${folder}`, { details: { reason: "checkout_busy", folder }, help: "wait for it to finish, then retry the same command" });
135896
- }
135897
- const unsentRefusal = (count5, sync3) => new CliError("CONFLICT", `the checkout of '${binding.bundle_id}' at ${folder} has ${count5} change(s) not on the host`, {
135898
- details: {
135899
- reason: "unsent_changes",
135900
- folder,
135901
- ...sync3,
135902
- keep_them_here_only: commandFragment`${cliInvocation()} export --in-place --dir ${commandToken(folder)} --keep-unsent${git2 ? commandFragment` --git` : commandFragment``}`
135903
- },
135904
- help: commandFragment`${cliInvocation()} sync --dir ${commandToken(folder)}`
135905
- });
135906
- const early = Number(status2.sync.unsent ?? 0) + Number(status2.sync.conflicts ?? 0) + Number(status2.sync.held_files ?? 0) + Number(status2.sync.held_deletions ?? 0);
135907
- if (early > 0 && !keepUnsent) throw unsentRefusal(early, status2.sync);
135908
- const source = { target: resolveHostedTarget(binding.audience), bundleId: binding.bundle_id, slug: binding.workspace_slug ?? null, workspace: null, binding };
135909
- const exported = await fetchExport(source, deps2, resume2);
135910
- const result3 = await filesystemPushRoleLocks().request(checkoutLockName(folder), { ifAvailable: true }, async (lock) => {
135911
- if (!lock) {
135912
- throw new CliError("CONFLICT", `another command holds the checkout lock for ${folder}`, { details: { reason: "checkout_busy", folder }, help: "wait for it to finish, then retry the same command" });
135913
- }
135914
- const current = await bindingForPath(deps2.auth.home, folder);
135915
- if (!current || current.checkout_id !== binding.checkout_id) {
135916
- throw new CliError("CONFLICT", `the checkout at ${folder} changed while it was exported`, { details: { reason: "checkout_changed", folder }, help: "retry the same command" });
135917
- }
135918
- const store = await FileJournaledBackend.open({ directory: checkoutStoreDir(deps2.auth.home, binding.checkout_id), readOnly: true });
135919
- let pending;
135920
- try {
135921
- const classified = await classifyCheckout(binding, deps2.auth.home, store);
135922
- pending = /* @__PURE__ */ new Set([...classified.unsent, ...classified.conflicts, ...classified.held.keys(), ...classified.heldDeletions]);
135923
- } finally {
135924
- await store.close();
135925
- }
135926
- if (pending.size > 0 && !keepUnsent) throw unsentRefusal(pending.size, { unsent_ids: shown([...pending]) });
135927
- const staging = path56.join(folder, IN_PLACE_STAGING);
135928
- await rm2(staging, { recursive: true, force: true });
135929
- await mkdir5(path56.join(staging, "files"), { recursive: true });
135930
- const adds = [];
135931
- const kept = [];
135932
- const deletedLocally = [];
135933
- let same = 0;
135934
- for (const entry of exported.entries) {
135935
- const id = entry.kind === "document" ? entry.path.slice(0, -3) : entry.path;
135936
- const placement = await placementOf(folder, entry);
135937
- if (placement === "add" && pending.has(id)) {
135938
- deletedLocally.push(entry.path);
135939
- continue;
135940
- }
135941
- if (placement === "same") same += 1;
135942
- else if (placement === "kept") kept.push(entry.path);
135943
- else {
135944
- const file2 = path56.join(staging, "files", ...entry.path.split("/"));
135945
- await mkdir5(path56.dirname(file2), { recursive: true });
135946
- await writeNewFile(file2, entry.bytes);
135947
- adds.push(entry.path);
135948
- }
135949
- }
135950
- const journal = {
135951
- schema: JOURNAL_SCHEMA,
135952
- bundle_id: binding.bundle_id,
135953
- host: binding.origin,
135954
- audience: binding.audience,
135955
- revision: exported.source.revision,
135956
- exported_at: exported.exportedAt,
135957
- git: git2,
135958
- adds,
135959
- same,
135960
- kept_local: kept,
135961
- deleted_locally: deletedLocally,
135962
- unsent_kept: pending.size
135963
- };
135964
- await writeJournal(staging, journal);
135965
- await releaseCheckout(deps2.auth.home, binding);
135966
- return { journal, finished: await finishInPlace(folder, journal) };
135967
- });
135968
- const home2 = await bundleHomeAt(folder, { home: deps2.auth.home });
135969
- deps2.stdout(render(inPlaceReceipt(folder, result3.journal, result3.finished, home2.home, false), mode));
135970
- }
135971
- async function exportCommand(argv2, partial2 = {}) {
135972
- const deps2 = exportDeps(partial2);
135973
- const { values, positionals } = parseLeafOrUsage(
135974
- () => parseArgs42({
135975
- args: argv2,
135976
- options: {
135977
- to: { type: "string" },
135978
- "in-place": { type: "boolean" },
135979
- dir: { type: "string" },
135980
- host: { type: "string" },
135981
- workspace: { type: "string" },
135982
- git: { type: "boolean" },
135983
- "keep-unsent": { type: "boolean" },
135984
- json: { type: "boolean" },
135985
- help: { type: "boolean", short: "h" }
135986
- },
135987
- allowPositionals: true
135988
- }),
135989
- CLI_LEAVES.export
135990
- );
135991
- if (values.help) {
135992
- deps2.stdout(renderUsage(EXPORT_USAGE));
135993
- return;
135994
- }
135995
- const mode = resolveMode(values);
135996
- const usage3 = (message) => new CliError("USAGE", message, { help: `${cliInvocation()} export --help` });
135997
- const named = positionals[0];
135998
- const inPlace = values["in-place"] === true;
135999
- if (inPlace === (values.to !== void 0)) throw usage3("pass exactly one of --to <folder> and --in-place");
136000
- if (named !== void 0 && values.dir !== void 0) throw usage3("pass a bundle id or --dir <checkout>, not both");
136001
- if (named === void 0 && (values.host !== void 0 || values.workspace !== void 0)) throw usage3("--host and --workspace go with a bundle id; a checkout uses its own");
136002
- if (inPlace && named !== void 0) throw usage3("--in-place converts a checkout folder: pass --dir <checkout>, not a bundle id");
136003
- if (!inPlace && values["keep-unsent"]) throw usage3("--keep-unsent goes with --in-place");
136004
- const reference = named === void 0 ? void 0 : parseHostedBundleReference(named);
136005
- if (named !== void 0 && !reference) throw usage3(`'${named}' is not a hosted bundle id or <workspace>/<bundle-id>`);
136006
- const git2 = values.git === true;
136007
- const resume2 = commandFragment`${cliInvocation()} export${named !== void 0 ? commandFragment` ${commandToken(named)}` : commandFragment``}${values.dir !== void 0 ? commandFragment` --dir ${commandToken(path56.resolve(deps2.cwd, values.dir))}` : commandFragment``}${values.to !== void 0 ? commandFragment` --to ${commandToken(path56.resolve(deps2.cwd, values.to))}` : commandFragment``}${inPlace ? commandFragment` --in-place` : commandFragment``}${values.host !== void 0 ? commandFragment` --host ${commandToken(values.host)}` : commandFragment``}${values.workspace !== void 0 ? commandFragment` --workspace ${commandToken(values.workspace)}` : commandFragment``}${git2 ? commandFragment` --git` : commandFragment``}${values["keep-unsent"] ? commandFragment` --keep-unsent` : commandFragment``}${values.json ? commandFragment` --json` : commandFragment``}`;
136008
- if (values.dir !== void 0) assertBundleOutsidePrivateState(path56.resolve(deps2.cwd, values.dir), deps2.auth.home);
136009
- if (inPlace) {
136010
- await exportInPlace(values.dir, git2, values["keep-unsent"] === true, deps2, mode, resume2);
136011
- return;
136012
- }
136013
- let source;
136014
- if (reference) {
136015
- const named2 = await requireHostedBundleHost(values.host, deps2.auth);
136016
- source = {
136017
- target: named2.target,
136018
- bundleId: reference.bundleId,
136019
- slug: reference.slug,
136020
- workspace: workspaceForNamedHost(named2, values.workspace) ?? null,
136021
- binding: null
136022
- };
136023
- } else {
136024
- const binding = await hostedCheckoutFor(values.dir === void 0 ? [] : ["--dir", values.dir], deps2.auth.home, deps2.cwd);
136025
- if (!binding) {
136026
- throw new CliError("NOT_FOUND", `${path56.resolve(deps2.cwd, values.dir ?? ".")} is not a hosted checkout`, {
136027
- details: { reason: "not_a_checkout" },
136028
- help: `${cliInvocation()} export <bundle-id> --to ${commandToken(values.to)}`
136029
- });
136030
- }
136031
- source = { target: resolveHostedTarget(binding.audience), bundleId: binding.bundle_id, slug: binding.workspace_slug ?? null, workspace: null, binding };
136032
- }
136033
- await exportToFolder(source, values.to, git2, deps2, mode, resume2);
136034
- }
136035
- var EXPORT_USAGE, EXPORT_DEADLINE_MS, SHOWN, JOURNAL, JOURNAL_SCHEMA, MAX_JOURNAL_BYTES, NO_HISTORY, HOSTED_UNCHANGED, PAGED_EXPORT_ATTEMPTS, PAGED_EXPORT_RESTART_MS, PAGE_RETRY_MS, pause2, ABANDONED_AFTER_MS;
136036
- var init_export = __esm({
136037
- "../cli/src/commands/export.ts"() {
136038
- "use strict";
136039
- init_define_SUPERBEE_BUILD_IDENTITY();
136040
- init_define_SUPERBEE_UPDATE_POLICY();
136041
- init_src();
136042
- init_filesystem_push_role();
136043
- init_src2();
136044
- init_args();
136045
- init_bundle2();
136046
- init_bundle_home();
136047
- init_command_spec();
136048
- init_command_text();
136049
- init_errors4();
136050
- init_invocation();
136051
- init_output2();
136052
- init_private_state_bundle_boundary();
136053
- init_nofollow_read();
136054
- init_autopull2();
136055
- init_session();
136056
- init_discovery();
136057
- init_binding();
136058
- init_client();
136059
- init_account();
136060
- init_refusals();
136061
- init_reference();
136062
- init_sync2();
136063
- init_status();
136064
- init_file_journaled_backend();
136065
- init_marker();
136066
- init_export_archive();
136067
- init_export_archive();
136068
- EXPORT_USAGE = `superbee export \u2014 copy a hosted bundle out of hosted Superbee
136069
-
136070
- Usage:
136071
- superbee export <bundle-id> --to <folder> [--host <url>] [--workspace <id>] [--git] [--json]
136072
- superbee export [--dir <checkout>] --to <folder> [--git] [--json]
136073
- superbee export [--dir <checkout>] --in-place [--git] [--keep-unsent] [--json]
136074
-
136075
- Fetches the hosted bundle's portable export: every document, reserved file (index.md, log.md)
136076
- and blob at its latest confirmed revision, byte for byte as the host stores them. The archive is
136077
- verified whole (every entry against the host's digest manifest) before any file is written.
136078
- Signs in if needed (AUTH_REQUIRED, exit 4, carries the one link to relay and the command to
136079
- re-run). The hosted bundle is never changed. History is not exported: the folder holds the
136080
- current revision only.
136081
-
136082
- --to <folder> writes a new local bundle there. The folder must be new or empty; it appears
136083
- complete or not at all. With a bundle id the host is --host, else your last sign-in; with
136084
- --dir (or run inside a checkout) the checkout's own host and bundle are used. A bundle id in more
136085
- than one of your workspaces is named <workspace>/<bundle-id>, or with --workspace.
136086
-
136087
- --in-place converts a hosted checkout into a plain local bundle: it adds the files the checkout
136088
- lacks (blobs, reserved files, documents added on the host), never overwrites a file, then
136089
- forgets the checkout's binding. It refuses a checkout with changes sync has not sent, conflicts
136090
- or held files; run 'superbee sync' first, or pass --keep-unsent to keep them in this folder only.
136091
- If it is interrupted, re-running the same command finishes it.
136092
-
136093
- --git makes the result a Git board: a repository on branch '${BOARD_BRANCH}' whose first commit is the
136094
- export. Share it with 'git remote add origin <url>' and 'superbee sync --establish'.
136095
-
136096
- Options:
136097
- --to <folder> New or empty folder to export into
136098
- --in-place Convert the hosted checkout (--dir, else the current folder) into a local bundle
136099
- --dir <checkout> The hosted checkout to export (default: the current folder)
136100
- --host <url> Hosted Superbee URL, with a bundle id; default: your last sign-in
136101
- --workspace <id> With a bundle id: your workspace that holds it, by id or slug
136102
- --git Initialize a Git repository on branch '${BOARD_BRANCH}' and commit the export
136103
- --keep-unsent With --in-place: convert even with unsent changes, conflicts or held files
136104
- --json Emit compact JSON instead of TOON
136105
- -h, --help Show this help
136106
-
136107
- Examples:
136108
- superbee export team.knowledge --to ~/work/team-knowledge --git
136109
- superbee export --dir ~/work/team --to ~/work/team-copy
136110
- superbee export --dir ~/work/team --in-place
136111
- `;
136112
- EXPORT_DEADLINE_MS = 6e4;
136113
- SHOWN = 20;
136114
- JOURNAL = IN_PLACE_JOURNAL;
136115
- JOURNAL_SCHEMA = 1;
136116
- MAX_JOURNAL_BYTES = 8 * 1024 * 1024;
136117
- NO_HISTORY = "not exported: the folder holds the current revision only";
136118
- HOSTED_UNCHANGED = "unchanged: the hosted bundle still exists and was not modified";
136119
- PAGED_EXPORT_ATTEMPTS = 3;
136120
- PAGED_EXPORT_RESTART_MS = [500, 1500];
136121
- PAGE_RETRY_MS = 1e3;
136122
- pause2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
136123
- ABANDONED_AFTER_MS = 60 * 60 * 1e3;
136124
- }
136125
- });
136126
-
136127
136308
  // ../cli/src/commands/op.ts
136128
136309
  import { homedir as homedir41 } from "node:os";
136129
136310
  import path57 from "node:path";
@@ -136410,8 +136591,9 @@ function cleanAuthor(author) {
136410
136591
  function gitVersions(board, id, rel, current, okfVersion, now, documentInputBytes) {
136411
136592
  const repoPath = board.prefix === "" ? rel : `${board.prefix}/${rel}`;
136412
136593
  const log = runGit(board.top, ["log", "--no-renames", "--format=%H%x1f%an <%ae>%x1f%aI", "HEAD", "--", repoPath]);
136413
- if (log.status !== 0) return { rows: [], skipped: 0 };
136594
+ if (log.status !== 0) return { rows: [], skipped: 0, oversized: [] };
136414
136595
  const rows = [];
136596
+ const oversized = [];
136415
136597
  let skipped = 0;
136416
136598
  let previous3 = current;
136417
136599
  for (const line2 of log.stdout.split("\n").filter(Boolean)) {
@@ -136438,19 +136620,24 @@ function gitVersions(board, id, rel, current, okfVersion, now, documentInputByte
136438
136620
  skipped += 1;
136439
136621
  continue;
136440
136622
  }
136623
+ const frontmatter = Object.fromEntries(
136624
+ Object.entries(parsed2.frontmatter).filter(([key2]) => !IMPORT_DROPPED_FIELDS.includes(key2))
136625
+ );
136626
+ if (Buffer.byteLength(JSON.stringify(frontmatter)) > FRONTMATTER_JSON_BYTES) {
136627
+ skipped += 1;
136628
+ oversized.push(`${rel}@${sha.slice(0, 12)}`);
136629
+ continue;
136630
+ }
136441
136631
  rows.push({
136442
136632
  documentId: id,
136443
136633
  label: `imported:git/${sha}`,
136444
136634
  author: cleanAuthor(author ?? ""),
136445
136635
  authoredAt: new Date(when).toISOString(),
136446
- // An imported version never asserts verification or host attribution, as a current document does not.
136447
- frontmatter: Object.fromEntries(
136448
- Object.entries(parsed2.frontmatter).filter(([key2]) => !IMPORT_DROPPED_FIELDS.includes(key2))
136449
- ),
136636
+ frontmatter,
136450
136637
  body: parsed2.body ?? ""
136451
136638
  });
136452
136639
  }
136453
- return { rows: rows.reverse(), skipped };
136640
+ return { rows: rows.reverse(), skipped, oversized };
136454
136641
  }
136455
136642
  async function okfVersionOf(rootIndex) {
136456
136643
  if (rootIndex === null) return void 0;
@@ -136593,7 +136780,12 @@ async function planPublish(folder, options) {
136593
136780
  throw error51;
136594
136781
  }
136595
136782
  if (request3.kind !== "create") throw new Error(`'${id}' became a ${request3.kind} request`);
136596
- if (Buffer.byteLength(JSON.stringify(request3.payload.frontmatter)) > FRONTMATTER_JSON_BYTES) {
136783
+ const frontmatterBytes = Buffer.byteLength(JSON.stringify(request3.payload.frontmatter));
136784
+ if ("verified" in request3.payload.frontmatter && frontmatterBytes <= FRONTMATTER_JSON_BYTES && frontmatterBytes > FRONTMATTER_JSON_BYTES - VERIFIED_STAMP_ROOM_BYTES) {
136785
+ blockers.push({ path: entry.rel, reason: "too_large", message: `'${id}' carries verified and leaves less than ${VERIFIED_STAMP_ROOM_BYTES} bytes of the ${FRONTMATTER_JSON_BYTES / 1024} KiB of frontmatter the host stores for its stamps on later edits; shorten its frontmatter` });
136786
+ continue;
136787
+ }
136788
+ if (frontmatterBytes > FRONTMATTER_JSON_BYTES) {
136597
136789
  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(", ")}` });
136598
136790
  continue;
136599
136791
  }
@@ -136633,6 +136825,7 @@ async function planPublish(folder, options) {
136633
136825
  const versions = gitVersions(options.board, file2.id, file2.rel, file2.text, okfVersion, options.now ?? Date.now(), documentInputBytes);
136634
136826
  history.push(...versions.rows);
136635
136827
  skippedVersions += versions.skipped;
136828
+ for (const version4 of versions.oversized) skipped.push({ path: version4, reason: `an earlier version with more than the ${FRONTMATTER_JSON_BYTES / 1024} KiB of frontmatter the host stores; its history is imported without it` });
136636
136829
  }
136637
136830
  historyPlan = {
136638
136831
  mode: "git",
@@ -136773,7 +136966,7 @@ function packParts(content3, versions) {
136773
136966
  }
136774
136967
  return parts;
136775
136968
  }
136776
- var MiB, PUBLISH_BOUNDS, STAGED_PUBLISH_BOUNDS, CONTENT_TYPES, HOSTED_KIND_WRITE, FORMAT_AT_EDGE, FORMAT_INSIDE, WIDEST_TARGET;
136969
+ var MiB, PUBLISH_BOUNDS, STAGED_PUBLISH_BOUNDS, CONTENT_TYPES, HOSTED_KIND_WRITE, VERIFIED_STAMP_ROOM_BYTES, FORMAT_AT_EDGE, FORMAT_INSIDE, WIDEST_TARGET;
136777
136970
  var init_publish_plan = __esm({
136778
136971
  "../cli/src/hosted/publish-plan.ts"() {
136779
136972
  "use strict";
@@ -136833,6 +137026,7 @@ var init_publish_plan = __esm({
136833
137026
  ".xml": "application/xml"
136834
137027
  };
136835
137028
  HOSTED_KIND_WRITE = Object.freeze({ strict: true, persistActor: true, producer: "process:superbee-hosted" });
137029
+ VERIFIED_STAMP_ROOM_BYTES = 512;
136836
137030
  FORMAT_AT_EDGE = new RegExp("^\\p{Cf}|\\p{Cf}$", "u");
136837
137031
  FORMAT_INSIDE = new RegExp("(?![\\u200c\\u200d])\\p{Cf}", "u");
136838
137032
  WIDEST_TARGET = Object.freeze({ workspace: "w".repeat(64), bundleId: "b".repeat(128), name: "n".repeat(128) });
@@ -137193,7 +137387,7 @@ function provenanceOf(plan) {
137193
137387
  return {
137194
137388
  carried: plan.provenance.carried,
137195
137389
  dropped: plan.provenance.dropped,
137196
- 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"
137390
+ note: "provenance travels as each file states it (a claim, not a verification), so documents read on the host as they do here; the host records the creation as yours and stamps the writer itself on every later edit"
137197
137391
  };
137198
137392
  }
137199
137393
  function createRefusal(code3, message, context) {
@@ -137220,6 +137414,14 @@ function createRefusal(code3, message, context) {
137220
137414
  details,
137221
137415
  help: `put the files back as they were and re-run the same command to finish it; if the creation already finished, bind this folder to it (your edits become sync conflicts): ${cliInvocation()} checkout --adopt ${commandToken(context.folder)} --host ${commandToken(bindingHostArgument(context.target))}`
137222
137416
  });
137417
+ case "validation_failed":
137418
+ if (/sets (superbee_updated_by|verified)\b.*which only the host writes/.test(message)) {
137419
+ return new CliError("FORBIDDEN", `${context.target.origin} does not yet keep each document's superbee_updated_by and verified on a new bundle, which this CLI carries`, {
137420
+ details: { ...details, reason: "host_predates_provenance" },
137421
+ help: "leave the files as they are: publish again once the host is updated, or publish with an earlier superbee CLI, which leaves those fields behind"
137422
+ });
137423
+ }
137424
+ return new CliError("USAGE", `${context.target.origin} refused the bundle (${code3}): ${message}`, { details, help: "fix the files it names, then preview again" });
137223
137425
  default:
137224
137426
  return new CliError("USAGE", `${context.target.origin} refused the bundle (${code3}): ${message}`, { details, help: "fix the files it names, then preview again" });
137225
137427
  }
@@ -137666,9 +137868,10 @@ Without --yes, previews only, with no network: what travels (documents, reserved
137666
137868
  files), what stays (dot-files, links), how it is sent, every bound the host enforces, the history
137667
137869
  plan, and what will happen to the folder.
137668
137870
 
137669
- Each document's provenance (generated, timestamp, actor, okf_version) travels as its file states
137670
- it, a claim rather than a verification; verified and superbee_updated_by never travel. The
137671
- preview and the receipt count both, per field.
137871
+ Each document's provenance (generated, timestamp, actor, okf_version, superbee_updated_by,
137872
+ verified) travels as its file states it, a claim rather than a verification, so the bundle reads
137873
+ on the host as it does here. The host still records the creation as yours, and stamps the writer
137874
+ itself on every later edit. The preview and the receipt count each field.
137672
137875
 
137673
137876
  A bundle within one request's bounds (at most 1,000 documents, 100 other files of 1 MB each,
137674
137877
  1,000 earlier versions, 1,500 objects in all, 3 MiB) is sent in one request. A larger one is sent