@senticor/hive 1.47.0 → 1.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/hive.cjs +469 -112
  2. package/package.json +1 -1
package/hive.cjs CHANGED
@@ -3303,8 +3303,8 @@ var require_utils = __commonJS({
3303
3303
  }
3304
3304
  return ind;
3305
3305
  }
3306
- function removeDotSegments(path9) {
3307
- let input = path9;
3306
+ function removeDotSegments(path10) {
3307
+ let input = path10;
3308
3308
  const output2 = [];
3309
3309
  let nextSlash = -1;
3310
3310
  let len = 0;
@@ -3714,8 +3714,8 @@ var require_schemes = __commonJS({
3714
3714
  }
3715
3715
  if (wsComponent.resourceName) {
3716
3716
  const queryIndex = wsComponent.resourceName.indexOf("?");
3717
- const path9 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
3718
- wsComponent.path = path9 && path9 !== "/" ? path9 : void 0;
3717
+ const path10 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
3718
+ wsComponent.path = path10 && path10 !== "/" ? path10 : void 0;
3719
3719
  wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
3720
3720
  wsComponent.resourceName = void 0;
3721
3721
  }
@@ -8531,13 +8531,9 @@ var HiveClient = class {
8531
8531
  this.tenant = opts.tenant === null ? null : opts.tenant || process.env.HIVE_TENANT || process.env.HIVE_TENANT_ID || "default";
8532
8532
  this.verbose = !!opts.verbose;
8533
8533
  }
8534
- /** Low-level request helper (no external deps, uses Node built-ins) */
8535
- async _request(method, path9, body) {
8536
- const url2 = new import_node_url2.URL(path9, this.baseUrl);
8537
- const mod = url2.protocol === "https:" ? import_node_https2.default : import_node_http2.default;
8538
- const headers = {
8539
- accept: "application/json"
8540
- };
8534
+ /** Tenant + auth headers every request to the Hive API carries. */
8535
+ async _baseHeaders(accept) {
8536
+ const headers = { accept };
8541
8537
  if (this.tenant) headers["x-hive-tenant"] = this.tenant;
8542
8538
  try {
8543
8539
  const token = process.env.HIVE_TOKEN || process.env.HIVE_TEST_TOKEN || process.env.HIVE_BEARER_TOKEN || await getValidToken();
@@ -8545,6 +8541,13 @@ var HiveClient = class {
8545
8541
  } catch (e) {
8546
8542
  if (this.verbose) console.error("Warning: Could not fetch auth token", e.message);
8547
8543
  }
8544
+ return headers;
8545
+ }
8546
+ /** Low-level request helper (no external deps, uses Node built-ins) */
8547
+ async _request(method, path10, body) {
8548
+ const url2 = new import_node_url2.URL(path10, this.baseUrl);
8549
+ const mod = url2.protocol === "https:" ? import_node_https2.default : import_node_http2.default;
8550
+ const headers = await this._baseHeaders("application/json");
8548
8551
  let payload = null;
8549
8552
  if (body !== void 0 && body !== null) {
8550
8553
  payload = typeof body === "string" ? body : JSON.stringify(body);
@@ -8572,7 +8575,7 @@ var HiveClient = class {
8572
8575
  `);
8573
8576
  }
8574
8577
  if (!isHttpOk(res.statusCode)) {
8575
- recordRemoteFailure({ method, path: path9, status: res.statusCode, body: data });
8578
+ recordRemoteFailure({ method, path: path10, status: res.statusCode, body: data });
8576
8579
  }
8577
8580
  resolve3({ status: res.statusCode, data });
8578
8581
  });
@@ -8582,20 +8585,42 @@ var HiveClient = class {
8582
8585
  req2.end();
8583
8586
  });
8584
8587
  }
8585
- get(path9) {
8586
- return this._request("GET", path9);
8588
+ /**
8589
+ * Streaming request: resolves once the response headers arrive and hands back
8590
+ * the body unread, for responses too large or too binary for `_request`
8591
+ * (a mission export, a document's bytes). Sends the same tenant and auth
8592
+ * headers. The caller reads or discards `body` and reports failures itself.
8593
+ */
8594
+ async getRaw(path10) {
8595
+ const url2 = new import_node_url2.URL(path10, this.baseUrl);
8596
+ const mod = url2.protocol === "https:" ? import_node_https2.default : import_node_http2.default;
8597
+ const headers = await this._baseHeaders("*/*");
8598
+ if (this.verbose) process.stderr.write(`\u2192 GET ${url2.href} (stream)
8599
+ `);
8600
+ return new Promise((resolve3, reject) => {
8601
+ const req2 = mod.request(url2, { method: "GET", headers }, (res) => {
8602
+ if (this.verbose) process.stderr.write(`\u2190 ${res.statusCode} (stream)
8603
+ `);
8604
+ resolve3({ status: res.statusCode, headers: res.headers, body: res });
8605
+ });
8606
+ req2.on("error", reject);
8607
+ req2.end();
8608
+ });
8609
+ }
8610
+ get(path10) {
8611
+ return this._request("GET", path10);
8587
8612
  }
8588
- post(path9, body) {
8589
- return this._request("POST", path9, body || {});
8613
+ post(path10, body) {
8614
+ return this._request("POST", path10, body || {});
8590
8615
  }
8591
- put(path9, body) {
8592
- return this._request("PUT", path9, body || {});
8616
+ put(path10, body) {
8617
+ return this._request("PUT", path10, body || {});
8593
8618
  }
8594
- patch(path9, body) {
8595
- return this._request("PATCH", path9, body || {});
8619
+ patch(path10, body) {
8620
+ return this._request("PATCH", path10, body || {});
8596
8621
  }
8597
- del(path9) {
8598
- return this._request("DELETE", path9);
8622
+ del(path10) {
8623
+ return this._request("DELETE", path10);
8599
8624
  }
8600
8625
  };
8601
8626
 
@@ -8831,7 +8856,7 @@ function fieldText(value) {
8831
8856
  function schemaErrorFields(data) {
8832
8857
  const errors = data?.schemaErrors;
8833
8858
  if (!Array.isArray(errors)) return [];
8834
- const paths = errors.map((entry) => String(entry?.instancePath ?? "").trim()).filter(Boolean).map((path9) => path9.replace(/^\//, ""));
8859
+ const paths = errors.map((entry) => String(entry?.instancePath ?? "").trim()).filter(Boolean).map((path10) => path10.replace(/^\//, ""));
8835
8860
  return [...new Set(paths)];
8836
8861
  }
8837
8862
  function remoteFailureRemediation(data) {
@@ -9177,11 +9202,11 @@ function parseBoolish(value) {
9177
9202
  }
9178
9203
  function readTlsKeysFromEnvFile(file2) {
9179
9204
  const out = {};
9180
- const path9 = cleanString(file2);
9181
- if (!path9) return out;
9205
+ const path10 = cleanString(file2);
9206
+ if (!path10) return out;
9182
9207
  let text;
9183
9208
  try {
9184
- text = import_node_fs3.default.readFileSync(path9, "utf-8");
9209
+ text = import_node_fs3.default.readFileSync(path10, "utf-8");
9185
9210
  } catch {
9186
9211
  return out;
9187
9212
  }
@@ -9449,8 +9474,8 @@ function resolvePrincipal(args) {
9449
9474
  }
9450
9475
  return email3 ? { principalEmail: email3.toLowerCase() } : { principalSub: sub };
9451
9476
  }
9452
- function dryRunResult(method, path9, body) {
9453
- return body === void 0 ? { dryRun: true, method, path: path9 } : { dryRun: true, method, path: path9, body };
9477
+ function dryRunResult(method, path10, body) {
9478
+ return body === void 0 ? { dryRun: true, method, path: path10 } : { dryRun: true, method, path: path10, body };
9454
9479
  }
9455
9480
  function runScript(script) {
9456
9481
  try {
@@ -9495,22 +9520,22 @@ var artifactName = injectedString(
9495
9520
  true ? "hive-cli" : void 0
9496
9521
  ) || String(process.env.HIVE_CLI_ARTIFACT_NAME || "hive-cli").trim() || "hive-cli";
9497
9522
  var packageVersion = injectedString(
9498
- true ? "1.47.0" : void 0
9523
+ true ? "1.48.0" : void 0
9499
9524
  ) || String(process.env.HIVE_CLI_PACKAGE_VERSION || "").trim() || readPackageVersion();
9500
9525
  var releaseVersion = injectedString(
9501
- true ? "1.47.0" : void 0
9526
+ true ? "1.48.0" : void 0
9502
9527
  ) || String(process.env.HIVE_CLI_RELEASE_VERSION || "").trim() || packageVersion || "dev";
9503
9528
  var releaseChannel = injectedString(
9504
9529
  true ? "final" : void 0
9505
9530
  ) || String(process.env.HIVE_CLI_RELEASE_CHANNEL || "").trim() || (releaseVersion.includes("-rc.") ? "rc" : releaseVersion === "dev" ? "dev" : "final");
9506
9531
  var buildCommit = injectedString(
9507
- true ? "aabcbc962684f6b4130138072c53314c80c0437b" : void 0
9532
+ true ? "3faa9b71ef73e2fbcf86dce4bdd838ca7fb1fe85" : void 0
9508
9533
  ) || String(process.env.HIVE_CLI_BUILD_COMMIT || "").trim() || "unknown";
9509
9534
  var buildTimestamp = injectedString(
9510
- true ? "2026-09-29T12:03:30Z" : void 0
9535
+ true ? "2026-09-30T15:02:20Z" : void 0
9511
9536
  ) || String(process.env.HIVE_CLI_BUILD_TIMESTAMP || "").trim() || "unknown";
9512
9537
  var ociRef = injectedString(
9513
- true ? "registry.onstackit.cloud/senticor/hive-cli:1.47.0" : void 0
9538
+ true ? "registry.onstackit.cloud/senticor/hive-cli:1.48.0" : void 0
9514
9539
  ) || String(process.env.HIVE_CLI_OCI_REF || "").trim() || `registry.onstackit.cloud/senticor/${artifactName}:${releaseVersion}`;
9515
9540
  var RELEASE_INFO = Object.freeze({
9516
9541
  packageVersion,
@@ -11530,10 +11555,10 @@ function mergeDefs(...defs) {
11530
11555
  function cloneDef(schema) {
11531
11556
  return mergeDefs(schema._zod.def);
11532
11557
  }
11533
- function getElementAtPath(obj, path9) {
11534
- if (!path9)
11558
+ function getElementAtPath(obj, path10) {
11559
+ if (!path10)
11535
11560
  return obj;
11536
- return path9.reduce((acc, key) => acc?.[key], obj);
11561
+ return path10.reduce((acc, key) => acc?.[key], obj);
11537
11562
  }
11538
11563
  function promiseAllObject(promisesObj) {
11539
11564
  const keys = Object.keys(promisesObj);
@@ -11942,11 +11967,11 @@ function explicitlyAborted(x, startIndex = 0) {
11942
11967
  }
11943
11968
  return false;
11944
11969
  }
11945
- function prefixIssues(path9, issues) {
11970
+ function prefixIssues(path10, issues) {
11946
11971
  return issues.map((iss) => {
11947
11972
  var _a3;
11948
11973
  (_a3 = iss).path ?? (_a3.path = []);
11949
- iss.path.unshift(path9);
11974
+ iss.path.unshift(path10);
11950
11975
  return iss;
11951
11976
  });
11952
11977
  }
@@ -12093,16 +12118,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
12093
12118
  }
12094
12119
  function formatError(error51, mapper = (issue2) => issue2.message) {
12095
12120
  const fieldErrors = { _errors: [] };
12096
- const processError = (error52, path9 = []) => {
12121
+ const processError = (error52, path10 = []) => {
12097
12122
  for (const issue2 of error52.issues) {
12098
12123
  if (issue2.code === "invalid_union" && issue2.errors.length) {
12099
- issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
12124
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
12100
12125
  } else if (issue2.code === "invalid_key") {
12101
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
12126
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
12102
12127
  } else if (issue2.code === "invalid_element") {
12103
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
12128
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
12104
12129
  } else {
12105
- const fullpath = [...path9, ...issue2.path];
12130
+ const fullpath = [...path10, ...issue2.path];
12106
12131
  if (fullpath.length === 0) {
12107
12132
  fieldErrors._errors.push(mapper(issue2));
12108
12133
  } else {
@@ -12129,17 +12154,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
12129
12154
  }
12130
12155
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
12131
12156
  const result = { errors: [] };
12132
- const processError = (error52, path9 = []) => {
12157
+ const processError = (error52, path10 = []) => {
12133
12158
  var _a3, _b;
12134
12159
  for (const issue2 of error52.issues) {
12135
12160
  if (issue2.code === "invalid_union" && issue2.errors.length) {
12136
- issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
12161
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
12137
12162
  } else if (issue2.code === "invalid_key") {
12138
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
12163
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
12139
12164
  } else if (issue2.code === "invalid_element") {
12140
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
12165
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
12141
12166
  } else {
12142
- const fullpath = [...path9, ...issue2.path];
12167
+ const fullpath = [...path10, ...issue2.path];
12143
12168
  if (fullpath.length === 0) {
12144
12169
  result.errors.push(mapper(issue2));
12145
12170
  continue;
@@ -12171,8 +12196,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
12171
12196
  }
12172
12197
  function toDotPath(_path) {
12173
12198
  const segs = [];
12174
- const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
12175
- for (const seg of path9) {
12199
+ const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
12200
+ for (const seg of path10) {
12176
12201
  if (typeof seg === "number")
12177
12202
  segs.push(`[${seg}]`);
12178
12203
  else if (typeof seg === "symbol")
@@ -23964,8 +23989,8 @@ function hex2(_params) {
23964
23989
  return _stringFormat(ZodCustomStringFormat, "hex", regexes_exports.hex, _params);
23965
23990
  }
23966
23991
  function hash(alg, params) {
23967
- const enc2 = params?.enc ?? "hex";
23968
- const format = `${alg}_${enc2}`;
23992
+ const enc3 = params?.enc ?? "hex";
23993
+ const format = `${alg}_${enc3}`;
23969
23994
  const regex = regexes_exports[format];
23970
23995
  if (!regex)
23971
23996
  throw new Error(`Unrecognized hash format: ${format}`);
@@ -24945,13 +24970,13 @@ function resolveRef(ref, ctx2) {
24945
24970
  if (!ref.startsWith("#")) {
24946
24971
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
24947
24972
  }
24948
- const path9 = ref.slice(1).split("/").filter(Boolean);
24949
- if (path9.length === 0) {
24973
+ const path10 = ref.slice(1).split("/").filter(Boolean);
24974
+ if (path10.length === 0) {
24950
24975
  return ctx2.rootSchema;
24951
24976
  }
24952
24977
  const defsKey = ctx2.version === "draft-2020-12" ? "$defs" : "definitions";
24953
- if (path9[0] === defsKey) {
24954
- const key = path9[1];
24978
+ if (path10[0] === defsKey) {
24979
+ const key = path10[1];
24955
24980
  if (!key || !ctx2.defs[key]) {
24956
24981
  throw new Error(`Reference not found: ${ref}`);
24957
24982
  }
@@ -25514,8 +25539,8 @@ function loadConfig(raw) {
25514
25539
  const result = BootstrapConfigSchema.safeParse(raw);
25515
25540
  if (!result.success) {
25516
25541
  const lines = result.error.issues.map((issue2) => {
25517
- const path9 = issue2.path.length ? issue2.path.join(".") : "(root)";
25518
- return ` \u2022 ${path9}: ${issue2.message}`;
25542
+ const path10 = issue2.path.length ? issue2.path.join(".") : "(root)";
25543
+ return ` \u2022 ${path10}: ${issue2.message}`;
25519
25544
  });
25520
25545
  throw new Error(`Invalid customer config:
25521
25546
  ${lines.join("\n")}`);
@@ -25601,7 +25626,7 @@ function createHttpClient(baseUrl, token, fetchImpl = fetch) {
25601
25626
  const base = baseUrl.replace(/\/$/, "");
25602
25627
  return {
25603
25628
  baseUrl: base,
25604
- async request(method, path9, opts = {}) {
25629
+ async request(method, path10, opts = {}) {
25605
25630
  const headers = {
25606
25631
  Authorization: `Bearer ${token}`,
25607
25632
  Accept: "application/json"
@@ -25612,7 +25637,7 @@ function createHttpClient(baseUrl, token, fetchImpl = fetch) {
25612
25637
  headers["Content-Type"] = "application/json";
25613
25638
  body = JSON.stringify(opts.body);
25614
25639
  }
25615
- const res = await fetchImpl(`${base}${path9}`, { method, headers, body });
25640
+ const res = await fetchImpl(`${base}${path10}`, { method, headers, body });
25616
25641
  const text = await res.text().catch(() => "");
25617
25642
  let json2 = null;
25618
25643
  if (text) {
@@ -25633,21 +25658,21 @@ init_cjs_shims();
25633
25658
  // src/admin/state.mts
25634
25659
  init_cjs_shims();
25635
25660
  var import_node_fs7 = require("fs");
25636
- function readState(path9) {
25637
- if (!(0, import_node_fs7.existsSync)(path9)) return {};
25661
+ function readState(path10) {
25662
+ if (!(0, import_node_fs7.existsSync)(path10)) return {};
25638
25663
  try {
25639
- const parsed = JSON.parse((0, import_node_fs7.readFileSync)(path9, "utf-8"));
25664
+ const parsed = JSON.parse((0, import_node_fs7.readFileSync)(path10, "utf-8"));
25640
25665
  return parsed && typeof parsed === "object" ? parsed : {};
25641
25666
  } catch {
25642
25667
  return {};
25643
25668
  }
25644
25669
  }
25645
- function writeState(path9, state) {
25646
- (0, import_node_fs7.writeFileSync)(path9, `${JSON.stringify(state, null, 2)}
25670
+ function writeState(path10, state) {
25671
+ (0, import_node_fs7.writeFileSync)(path10, `${JSON.stringify(state, null, 2)}
25647
25672
  `, "utf-8");
25648
25673
  }
25649
- function mergeState(path9, patch2, now) {
25650
- const current = readState(path9);
25674
+ function mergeState(path10, patch2, now) {
25675
+ const current = readState(path10);
25651
25676
  const completed = /* @__PURE__ */ new Set([
25652
25677
  ...current.completedSteps ?? [],
25653
25678
  ...patch2.completedSteps ?? []
@@ -25658,7 +25683,7 @@ function mergeState(path9, patch2, now) {
25658
25683
  completedSteps: [...completed],
25659
25684
  ...now ? { updatedAt: now } : {}
25660
25685
  };
25661
- writeState(path9, merged);
25686
+ writeState(path10, merged);
25662
25687
  return merged;
25663
25688
  }
25664
25689
 
@@ -25760,8 +25785,8 @@ async function ensureMission(client, mission2, opts) {
25760
25785
  }
25761
25786
  const body = { userIntent: mission2.userIntent };
25762
25787
  if (mission2.instantiationConfig) body.instantiationConfig = mission2.instantiationConfig;
25763
- const path9 = `/api/mission-templates/${encodeURIComponent(mission2.templateId)}/instantiate`;
25764
- const res = await client.request("POST", path9, { body, tenant: opts.tenant });
25788
+ const path10 = `/api/mission-templates/${encodeURIComponent(mission2.templateId)}/instantiate`;
25789
+ const res = await client.request("POST", path10, { body, tenant: opts.tenant });
25765
25790
  if (!res.ok) {
25766
25791
  throw new Error(
25767
25792
  `Instantiate '${mission2.templateId}' failed (HTTP ${res.status}): ${res.text}`
@@ -26125,10 +26150,10 @@ function defaultStatePath(configDir, override, cwd = process.cwd()) {
26125
26150
  }
26126
26151
 
26127
26152
  // src/admin/admin.mts
26128
- function loadEnvFile(path9) {
26153
+ function loadEnvFile(path10) {
26129
26154
  let text;
26130
26155
  try {
26131
- text = (0, import_node_fs9.readFileSync)(path9, "utf-8");
26156
+ text = (0, import_node_fs9.readFileSync)(path10, "utf-8");
26132
26157
  } catch {
26133
26158
  return;
26134
26159
  }
@@ -27281,7 +27306,7 @@ var completion = defineCommand({
27281
27306
 
27282
27307
  // src/commands/core.ts
27283
27308
  init_cjs_shims();
27284
- var import_node_fs11 = require("fs");
27309
+ var import_node_fs12 = require("fs");
27285
27310
 
27286
27311
  // ../hive-api-contracts/src/cases-import.ts
27287
27312
  init_cjs_shims();
@@ -27392,9 +27417,282 @@ function parseCasesImportInput(body) {
27392
27417
  };
27393
27418
  }
27394
27419
 
27420
+ // src/lib/mission-transfer.ts
27421
+ init_cjs_shims();
27422
+ var import_node_crypto5 = require("crypto");
27423
+ var import_node_fs11 = require("fs");
27424
+ var import_node_path11 = __toESM(require("path"), 1);
27425
+ var import_promises = require("stream/promises");
27426
+ var EXPORT_FILE = "export.jsonl";
27427
+ var OBJECTS_DIR = "objects";
27428
+ var EXPORT_FORMAT = "hive.mission.export.v1";
27429
+ var BATCH_MAX_ROWS = 200;
27430
+ var BATCH_MAX_BYTES = 4 * 1024 * 1024;
27431
+ var enc2 = encodeURIComponent;
27432
+ function asRow(value) {
27433
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
27434
+ }
27435
+ function sha256(buf) {
27436
+ return (0, import_node_crypto5.createHash)("sha256").update(buf).digest("hex");
27437
+ }
27438
+ async function readAll(stream) {
27439
+ const chunks = [];
27440
+ for await (const chunk of stream) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
27441
+ return Buffer.concat(chunks);
27442
+ }
27443
+ function parseBody(buf) {
27444
+ const text = buf.toString("utf8");
27445
+ try {
27446
+ return JSON.parse(text);
27447
+ } catch {
27448
+ return { _raw: text };
27449
+ }
27450
+ }
27451
+ function objectFileName(docId) {
27452
+ return enc2(docId);
27453
+ }
27454
+ function parseExport(text) {
27455
+ const lines = text.split("\n").filter((l) => l.trim() !== "");
27456
+ const parsed = lines.map((line, i) => {
27457
+ try {
27458
+ return JSON.parse(line);
27459
+ } catch {
27460
+ throw commandError("EXPORT_UNREADABLE", 1, `export line ${i + 1} is not JSON`);
27461
+ }
27462
+ });
27463
+ const header = parsed[0];
27464
+ if (!header || header.kind !== "header" || header.format !== EXPORT_FORMAT) {
27465
+ throw commandError("EXPORT_UNREADABLE", 1, `not a ${EXPORT_FORMAT} export (first line must be its header)`);
27466
+ }
27467
+ const source = asRow(header.source);
27468
+ if (!source || typeof source.tenantId !== "string" || typeof source.missionId !== "string") {
27469
+ throw commandError("EXPORT_UNREADABLE", 1, "the export header names no source tenant and mission");
27470
+ }
27471
+ const summary = parsed[parsed.length - 1];
27472
+ if (!summary || summary.kind !== "summary") {
27473
+ throw commandError("EXPORT_INCOMPLETE", 1, "the export has no closing summary line: the stream was cut short");
27474
+ }
27475
+ const out = {
27476
+ header,
27477
+ source: { tenantId: source.tenantId, missionId: source.missionId },
27478
+ cases: [],
27479
+ documents: [],
27480
+ records: [],
27481
+ members: [],
27482
+ summary
27483
+ };
27484
+ for (const line of parsed.slice(1, -1)) {
27485
+ if (line.kind === "case" && asRow(line.case)) out.cases.push(line.case);
27486
+ else if (line.kind === "document" && asRow(line.document)) out.documents.push({ document: line.document, content: asRow(line.content) });
27487
+ else if (line.kind === "record" && asRow(line.record)) out.records.push(line.record);
27488
+ else if (line.kind === "member" && asRow(line.member)) out.members.push(line.member);
27489
+ }
27490
+ const counts = asRow(summary.counts) || {};
27491
+ const expected = [
27492
+ ["cases", out.cases.length],
27493
+ ["documents", out.documents.length],
27494
+ ["records", out.records.length],
27495
+ ["members", out.members.length]
27496
+ ];
27497
+ for (const [kind, actual] of expected) {
27498
+ if (Number(counts[kind]) !== actual) {
27499
+ throw commandError("EXPORT_INCOMPLETE", 1, `the export summary counts ${String(counts[kind])} ${kind} but the stream holds ${actual}`);
27500
+ }
27501
+ }
27502
+ return out;
27503
+ }
27504
+ async function downloadDocument(client, content, fetchImpl) {
27505
+ const minted = await client.get(String(content.url));
27506
+ if (isHttpOk(minted.status)) {
27507
+ const url2 = asRow(minted.data)?.url;
27508
+ if (typeof url2 !== "string" || !url2) throw commandError("DOCUMENT_URL_MISSING", 1, `${String(content.url)} answered without a url`);
27509
+ const res = await fetchImpl(url2);
27510
+ if (!res.ok) throw commandError("DOCUMENT_DOWNLOAD_FAILED", 1, `direct download failed (HTTP ${res.status}) for ${String(content.url)}`);
27511
+ return { bytes: Buffer.from(await res.arrayBuffer()), via: "direct" };
27512
+ }
27513
+ if (minted.status !== 501) throw remoteFailureError(minted.status, minted.data, "document url");
27514
+ remoteFailureHandled();
27515
+ const raw = await client.getRaw(String(content.content));
27516
+ const body = await readAll(raw.body);
27517
+ if (!isHttpOk(raw.status)) throw remoteFailureError(raw.status, parseBody(body), "document content");
27518
+ return { bytes: body, via: "api" };
27519
+ }
27520
+ async function exportMission(client, opts) {
27521
+ const log = opts.log || (() => void 0);
27522
+ const fetchImpl = opts.fetchImpl || globalThis.fetch;
27523
+ const exportPath = import_node_path11.default.join(opts.outDir, EXPORT_FILE);
27524
+ if ((0, import_node_fs11.existsSync)(exportPath)) {
27525
+ throw commandError("EXPORT_EXISTS", 2, `${exportPath} already exists; choose an empty --out directory`);
27526
+ }
27527
+ (0, import_node_fs11.mkdirSync)(import_node_path11.default.join(opts.outDir, OBJECTS_DIR), { recursive: true, mode: 448 });
27528
+ const res = await client.getRaw(`/api/admin/missions/${enc2(opts.missionId)}/export`);
27529
+ if (!isHttpOk(res.status)) throw remoteFailureError(res.status, parseBody(await readAll(res.body)), "mission export");
27530
+ const partial2 = `${exportPath}.partial`;
27531
+ await (0, import_promises.pipeline)(res.body, (0, import_node_fs11.createWriteStream)(partial2, { mode: 384 }));
27532
+ const exported = parseExport((0, import_node_fs11.readFileSync)(partial2, "utf8"));
27533
+ (0, import_node_fs11.renameSync)(partial2, exportPath);
27534
+ log(`export: ${exported.records.length} records, ${exported.documents.length} documents, ${exported.cases.length} cases`);
27535
+ let direct = 0;
27536
+ let viaApi = 0;
27537
+ let reused = 0;
27538
+ for (const { document: document3, content } of exported.documents) {
27539
+ if (!content) continue;
27540
+ const docId = String(document3.docId);
27541
+ const file2 = import_node_path11.default.join(opts.outDir, OBJECTS_DIR, objectFileName(docId));
27542
+ const expected = typeof content.sha256 === "string" ? content.sha256.toLowerCase() : null;
27543
+ if (expected && (0, import_node_fs11.existsSync)(file2) && sha256((0, import_node_fs11.readFileSync)(file2)) === expected) {
27544
+ reused += 1;
27545
+ continue;
27546
+ }
27547
+ const { bytes, via } = await downloadDocument(client, content, fetchImpl);
27548
+ if (expected && sha256(bytes) !== expected) {
27549
+ throw commandError("DOCUMENT_HASH_MISMATCH", 1, `${docId}: downloaded bytes do not match the exported sha256`);
27550
+ }
27551
+ (0, import_node_fs11.writeFileSync)(file2, bytes, { mode: 384 });
27552
+ if (via === "direct") direct += 1;
27553
+ else viaApi += 1;
27554
+ }
27555
+ return {
27556
+ ok: true,
27557
+ source: exported.source,
27558
+ outDir: opts.outDir,
27559
+ counts: exported.summary.counts,
27560
+ documentsWithoutContent: exported.summary.documentsWithoutContent,
27561
+ downloads: { direct, viaApi, reused }
27562
+ };
27563
+ }
27564
+ function emptyTotals() {
27565
+ return { create: [], replace: [], unchanged: [] };
27566
+ }
27567
+ function batches(rows, maxRows = BATCH_MAX_ROWS, maxBytes = BATCH_MAX_BYTES) {
27568
+ const out = [];
27569
+ let current = [];
27570
+ let size = 0;
27571
+ for (const row of rows) {
27572
+ const bytes = Buffer.byteLength(JSON.stringify(row));
27573
+ if (current.length > 0 && (current.length >= maxRows || size + bytes > maxBytes)) {
27574
+ out.push(current);
27575
+ current = [];
27576
+ size = 0;
27577
+ }
27578
+ current.push(row);
27579
+ size += bytes;
27580
+ }
27581
+ if (current.length > 0) out.push(current);
27582
+ return out;
27583
+ }
27584
+ async function runImportPass(client, exported, opts, dryRun) {
27585
+ const base = `/api/admin/missions/${enc2(opts.missionId)}/import`;
27586
+ const principalMap = opts.principalMap || {};
27587
+ const documents = emptyTotals();
27588
+ const failures = [];
27589
+ const withoutContent = [];
27590
+ for (const { document: document3, content } of exported.documents) {
27591
+ const docId = String(document3.docId);
27592
+ if (!content) {
27593
+ withoutContent.push(docId);
27594
+ continue;
27595
+ }
27596
+ const file2 = import_node_path11.default.join(opts.fromDir, OBJECTS_DIR, objectFileName(docId));
27597
+ if (!(0, import_node_fs11.existsSync)(file2)) throw commandError("DOCUMENT_BYTES_MISSING", 1, `${file2} is missing; re-run the export into this directory to fetch it`);
27598
+ const res = await client.post(`${base}/documents`, {
27599
+ source: exported.source,
27600
+ document: document3,
27601
+ bytesBase64: (0, import_node_fs11.readFileSync)(file2).toString("base64"),
27602
+ principalMap,
27603
+ dryRun,
27604
+ ...opts.changeId ? { changeId: opts.changeId } : {}
27605
+ });
27606
+ if (!isHttpOk(res.status)) {
27607
+ remoteFailureHandled();
27608
+ failures.push({ kind: "document", id: docId, status: res.status, error: asRow(res.data)?.error ?? res.data });
27609
+ continue;
27610
+ }
27611
+ const action = String(asRow(res.data)?.action || "");
27612
+ if (action === "create" || action === "replace" || action === "unchanged") documents[action].push(docId);
27613
+ }
27614
+ const records = emptyTotals();
27615
+ const cases = emptyTotals();
27616
+ const collisions = [];
27617
+ const invalid = [];
27618
+ const unresolvedDocumentRefs = [];
27619
+ const unmapped = /* @__PURE__ */ new Set();
27620
+ const sourcePrincipals = exported.members.map((m) => String(m.userId || "")).filter(Boolean);
27621
+ const calls = [
27622
+ ...batches(exported.cases).map((rows) => ({ cases: rows })),
27623
+ ...batches(exported.records).map((rows) => ({ records: rows }))
27624
+ ];
27625
+ for (const rows of calls) {
27626
+ const res = await client.post(base, {
27627
+ source: exported.source,
27628
+ ...rows,
27629
+ principalMap,
27630
+ sourcePrincipals,
27631
+ dryRun,
27632
+ ...opts.changeId ? { changeId: opts.changeId } : {}
27633
+ });
27634
+ const body = asRow(res.data) || {};
27635
+ if (!isHttpOk(res.status)) remoteFailureHandled();
27636
+ if (!isHttpOk(res.status) && res.status !== 400 && res.status !== 409) {
27637
+ throw remoteFailureError(res.status, res.data, "mission import");
27638
+ }
27639
+ for (const [key, totals] of [["records", records], ["cases", cases]]) {
27640
+ const part = asRow(body[key]) || {};
27641
+ for (const action of ["create", "replace", "unchanged"]) {
27642
+ const ids = part[action];
27643
+ if (Array.isArray(ids)) totals[action].push(...ids.map(String));
27644
+ }
27645
+ }
27646
+ for (const [list, key] of [[collisions, "collisions"], [invalid, "invalid"], [unresolvedDocumentRefs, "unresolvedDocumentRefs"]]) {
27647
+ const items = body[key];
27648
+ if (Array.isArray(items)) list.push(...items);
27649
+ }
27650
+ const unmappedHere = body.unmappedPrincipals;
27651
+ if (Array.isArray(unmappedHere)) unmappedHere.forEach((p) => unmapped.add(String(p)));
27652
+ }
27653
+ return {
27654
+ ok: failures.length === 0 && collisions.length === 0 && invalid.length === 0,
27655
+ dryRun,
27656
+ source: exported.source,
27657
+ target: { missionId: opts.missionId },
27658
+ documents: { ...documents, withoutContent, failures },
27659
+ records,
27660
+ cases,
27661
+ collisions,
27662
+ invalid,
27663
+ unresolvedDocumentRefs,
27664
+ unmappedPrincipals: [...unmapped].sort()
27665
+ };
27666
+ }
27667
+ async function importMission(client, opts) {
27668
+ const exportPath = import_node_path11.default.join(opts.fromDir, EXPORT_FILE);
27669
+ if (!(0, import_node_fs11.existsSync)(exportPath)) throw commandError("EXPORT_NOT_FOUND", 2, `${exportPath} not found`);
27670
+ const exported = parseExport((0, import_node_fs11.readFileSync)(exportPath, "utf8"));
27671
+ if (!opts.dryRun && !opts.changeId) throw commandError("CHANGE_ID_REQUIRED", 2, "--change-id is required unless --dry-run");
27672
+ const plan = await runImportPass(client, exported, opts, true);
27673
+ if (opts.dryRun) return plan;
27674
+ if (!plan.ok) {
27675
+ throw commandError("IMPORT_BLOCKED", 1, `the dry-run found problems; nothing was written: ${JSON.stringify({
27676
+ documentFailures: asRow(plan.documents)?.failures,
27677
+ collisions: plan.collisions,
27678
+ invalid: plan.invalid
27679
+ })}`);
27680
+ }
27681
+ opts.log?.("import: dry-run clean, writing");
27682
+ const written = await runImportPass(client, exported, opts, false);
27683
+ if (!written.ok) {
27684
+ throw commandError("IMPORT_INCOMPLETE", 1, `the import stopped part-way; re-run it once resolved: ${JSON.stringify({
27685
+ documentFailures: asRow(written.documents)?.failures,
27686
+ collisions: written.collisions,
27687
+ invalid: written.invalid
27688
+ })}`);
27689
+ }
27690
+ return written;
27691
+ }
27692
+
27395
27693
  // src/commands/core.ts
27396
- function readItemsFile(path9) {
27397
- const trimmed2 = (0, import_node_fs11.readFileSync)(path9, "utf-8").trim();
27694
+ function readItemsFile(path10) {
27695
+ const trimmed2 = (0, import_node_fs12.readFileSync)(path10, "utf-8").trim();
27398
27696
  if (trimmed2.startsWith("[")) {
27399
27697
  const arr = JSON.parse(trimmed2);
27400
27698
  if (!Array.isArray(arr)) throw new Error("--file JSON must be an array of row objects");
@@ -27874,6 +28172,26 @@ var missionArgs = withArgs({
27874
28172
  dryRun: { type: "boolean", description: "Print the request that would be sent; perform no write" },
27875
28173
  pin: { type: "boolean", description: "Pin created/reused mission as CLI context" }
27876
28174
  });
28175
+ var missionTransferArgs = withArgs({
28176
+ out: { type: "string", description: "mission export: directory to write export.jsonl and objects/ into (must not hold an export yet)" },
28177
+ from: { type: "string", description: "mission import: directory written by `hive mission export`" },
28178
+ changeId: { type: "string", description: "mission import: change or ticket id, recorded in the audit event (required unless --dry-run)" },
28179
+ principalMap: { type: "string", description: "mission import: JSON file mapping source principal ids to target principal ids" },
28180
+ dryRun: { type: "boolean", description: "mission import: report what would change; write nothing" }
28181
+ });
28182
+ function explicitMissionId(args, action) {
28183
+ const missionId = String(args.missionId || args.id || "").trim();
28184
+ if (!missionId) throw commandError("MISSION_REQUIRED", 2, `${action} needs --mission-id <id> (a pinned mission is not used here)`);
28185
+ return missionId;
28186
+ }
28187
+ function readPrincipalMap(file2) {
28188
+ if (!file2) return {};
28189
+ const raw = readJsonFile(String(file2));
28190
+ if (!raw || typeof raw !== "object" || Array.isArray(raw) || !Object.values(raw).every((v) => typeof v === "string" && v !== "")) {
28191
+ throw commandError("INVALID_PRINCIPAL_MAP", 2, "--principal-map must be a JSON object of source id \u2192 target id strings");
28192
+ }
28193
+ return raw;
28194
+ }
27877
28195
  var mission = defineCommand({
27878
28196
  meta: { name: "mission", description: "Missions, their cases, bundles and members" },
27879
28197
  args: missionArgs,
@@ -27914,6 +28232,45 @@ var mission = defineCommand({
27914
28232
  return runMissionSummary(args);
27915
28233
  }
27916
28234
  }),
28235
+ export: defineCommand({
28236
+ meta: {
28237
+ name: "export",
28238
+ description: "Export a mission (records, cases, documents with their bytes, member ids) into a directory (--mission-id, --out; admin)"
28239
+ },
28240
+ args: missionTransferArgs,
28241
+ async run({ args }) {
28242
+ const { client, fmt } = ctx(args);
28243
+ const missionId = explicitMissionId(args, "mission export");
28244
+ const outDir = String(args.out || "").trim();
28245
+ if (!outDir) throw commandError("OUT_REQUIRED", 2, "mission export needs --out <directory>");
28246
+ const result = await exportMission(client, { missionId, outDir, log: (l) => process.stderr.write(`${l}
28247
+ `) });
28248
+ return output(result, fmt);
28249
+ }
28250
+ }),
28251
+ import: defineCommand({
28252
+ meta: {
28253
+ name: "import",
28254
+ description: "Import a `hive mission export` directory into an existing mission of this tenant, without re-evaluation (--mission-id, --from, --change-id; admin)"
28255
+ },
28256
+ args: missionTransferArgs,
28257
+ async run({ args }) {
28258
+ const { client, fmt } = ctx(args);
28259
+ const missionId = explicitMissionId(args, "mission import");
28260
+ const fromDir = String(args.from || "").trim();
28261
+ if (!fromDir) throw commandError("FROM_REQUIRED", 2, "mission import needs --from <directory>");
28262
+ const result = await importMission(client, {
28263
+ missionId,
28264
+ fromDir,
28265
+ changeId: args.changeId ? String(args.changeId) : void 0,
28266
+ principalMap: readPrincipalMap(args.principalMap),
28267
+ dryRun: args.dryRun === true,
28268
+ log: (l) => process.stderr.write(`${l}
28269
+ `)
28270
+ });
28271
+ return output(result, fmt);
28272
+ }
28273
+ }),
27917
28274
  use: defineCommand({
27918
28275
  meta: { name: "use", description: "Pin a mission id for later commands (--id)" },
27919
28276
  args: missionArgs,
@@ -28094,9 +28451,9 @@ var mission = defineCommand({
28094
28451
  const missionId = requireMissionContext(args, "mission member grant");
28095
28452
  const principal = resolvePrincipal(args);
28096
28453
  const body = { ...principal, role: validateMissionGrantRole(args.role) };
28097
- const path9 = `/api/missions/${enc(missionId)}/members`;
28098
- if (args.dryRun) return output(dryRunResult("POST", path9, body), fmt);
28099
- const res = await client.post(path9, body);
28454
+ const path10 = `/api/missions/${enc(missionId)}/members`;
28455
+ if (args.dryRun) return output(dryRunResult("POST", path10, body), fmt);
28456
+ const res = await client.post(path10, body);
28100
28457
  assertMissionMembershipOk(res.status, res.data, "grant mission member");
28101
28458
  const data = recordOf3(res.data);
28102
28459
  const created = data.created === true;
@@ -28122,9 +28479,9 @@ var mission = defineCommand({
28122
28479
  throw commandError("EMAIL_INVALID", 2, `--email '${raw}' is not an email. admit is by email; use \`mission members grant --principal-sub\` for an OIDC sub.`);
28123
28480
  }
28124
28481
  const body = { principalEmail: raw, role: validateMissionGrantRole(args.role) };
28125
- const path9 = `/api/missions/${enc(missionId)}/members`;
28126
- if (args.dryRun) return output(dryRunResult("POST", path9, body), fmt);
28127
- const res = await client.post(path9, body);
28482
+ const path10 = `/api/missions/${enc(missionId)}/members`;
28483
+ if (args.dryRun) return output(dryRunResult("POST", path10, body), fmt);
28484
+ const res = await client.post(path10, body);
28128
28485
  assertMissionMembershipOk(res.status, res.data, "admit mission member");
28129
28486
  const data = recordOf3(res.data);
28130
28487
  const created = data.created === true;
@@ -28176,9 +28533,9 @@ var mission = defineCommand({
28176
28533
  printContextNotice(args, { mission: true });
28177
28534
  const missionId = requireMissionContext(args, "mission member revoke");
28178
28535
  const userId = reqAny(args, "userId", "id", "principalSub");
28179
- const path9 = `/api/missions/${enc(missionId)}/members/${enc(userId)}`;
28180
- if (args.dryRun) return output(dryRunResult("DELETE", path9), fmt);
28181
- const res = await client.del(path9);
28536
+ const path10 = `/api/missions/${enc(missionId)}/members/${enc(userId)}`;
28537
+ if (args.dryRun) return output(dryRunResult("DELETE", path10), fmt);
28538
+ const res = await client.del(path10);
28182
28539
  if (res.status === 404 && recordOf3(res.data).error === "member_not_found") {
28183
28540
  remoteFailureHandled();
28184
28541
  return output({ revoked: false, notFound: true, userId }, fmt);
@@ -28227,10 +28584,10 @@ var mission = defineCommand({
28227
28584
  "Changing tenantWideRead to true broadens mission visibility to the whole tenant. Re-run with --yes."
28228
28585
  );
28229
28586
  }
28230
- const path9 = `/api/missions/${enc(missionId)}/access-policy`;
28587
+ const path10 = `/api/missions/${enc(missionId)}/access-policy`;
28231
28588
  const body = { tenantWideRead };
28232
- if (args.dryRun) return output(dryRunResult("PATCH", path9, body), fmt);
28233
- const res = await client.patch(path9, body);
28589
+ if (args.dryRun) return output(dryRunResult("PATCH", path10, body), fmt);
28590
+ const res = await client.patch(path10, body);
28234
28591
  assertRemoteOk(res.status, res.data, "set mission access policy");
28235
28592
  return output({ updated: true, missionId, policy: recordOf3(res.data).policy ?? { tenantWideRead } }, fmt);
28236
28593
  }
@@ -28519,16 +28876,16 @@ var upgrade = defineCommand({
28519
28876
 
28520
28877
  // src/commands/data.ts
28521
28878
  init_cjs_shims();
28522
- var import_node_fs13 = __toESM(require("fs"), 1);
28523
- var import_node_path12 = __toESM(require("path"), 1);
28879
+ var import_node_fs14 = __toESM(require("fs"), 1);
28880
+ var import_node_path13 = __toESM(require("path"), 1);
28524
28881
  var ajvModule2 = __toESM(require_ajv(), 1);
28525
28882
  var ajvFormatsModule2 = __toESM(require_dist(), 1);
28526
28883
 
28527
28884
  // src/lib/application-package.ts
28528
28885
  init_cjs_shims();
28529
- var import_node_crypto5 = require("crypto");
28530
- var import_node_fs12 = require("fs");
28531
- var import_node_path11 = require("path");
28886
+ var import_node_crypto6 = require("crypto");
28887
+ var import_node_fs13 = require("fs");
28888
+ var import_node_path12 = require("path");
28532
28889
  var ajvModule = __toESM(require_ajv(), 1);
28533
28890
  var ajvFormatsModule = __toESM(require_dist(), 1);
28534
28891
 
@@ -28646,7 +29003,7 @@ var envelopeAjv = new AjvCtor({ allErrors: true, strict: false });
28646
29003
  addFormats(envelopeAjv);
28647
29004
  var validateStarterEnvelope = envelopeAjv.compile(DEFAULT_ENVELOPE_SCHEMA);
28648
29005
  function sha256Hex(bytes) {
28649
- return (0, import_node_crypto5.createHash)("sha256").update(bytes).digest("hex");
29006
+ return (0, import_node_crypto6.createHash)("sha256").update(bytes).digest("hex");
28650
29007
  }
28651
29008
  function formatBytes(n) {
28652
29009
  if (n >= 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MiB`;
@@ -28654,7 +29011,7 @@ function formatBytes(n) {
28654
29011
  return `${n} B`;
28655
29012
  }
28656
29013
  function loadApplicationPackage(inputPath, opts = {}) {
28657
- const st = (0, import_node_fs12.statSync)(inputPath);
29014
+ const st = (0, import_node_fs13.statSync)(inputPath);
28658
29015
  const envelope = st.isDirectory() ? buildEnvelopeFromDirectory(inputPath) : readEnvelopeJson(inputPath);
28659
29016
  const validation = validateApplicationEnvelope(envelope, {
28660
29017
  inputPath,
@@ -28664,7 +29021,7 @@ function loadApplicationPackage(inputPath, opts = {}) {
28664
29021
  return { envelope, summary: validation.summary, validation };
28665
29022
  }
28666
29023
  function readEnvelopeJson(inputPath) {
28667
- const parsed = JSON.parse((0, import_node_fs12.readFileSync)(inputPath, "utf8"));
29024
+ const parsed = JSON.parse((0, import_node_fs13.readFileSync)(inputPath, "utf8"));
28668
29025
  const envelope = parsed?.envelope && typeof parsed.envelope === "object" ? parsed.envelope : parsed;
28669
29026
  if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
28670
29027
  throw new Error(`${inputPath}: expected a JobApplication envelope object or { "envelope": ... } wrapper`);
@@ -28673,10 +29030,10 @@ function readEnvelopeJson(inputPath) {
28673
29030
  }
28674
29031
  function buildEnvelopeFromDirectory(folder) {
28675
29032
  const entries = [];
28676
- for (const name of (0, import_node_fs12.readdirSync)(folder).sort((a, b) => a.localeCompare(b))) {
29033
+ for (const name of (0, import_node_fs13.readdirSync)(folder).sort((a, b) => a.localeCompare(b))) {
28677
29034
  if (name.startsWith(".")) continue;
28678
- const full = (0, import_node_path11.join)(folder, name);
28679
- if (!(0, import_node_fs12.statSync)(full).isFile()) continue;
29035
+ const full = (0, import_node_path12.join)(folder, name);
29036
+ if (!(0, import_node_fs13.statSync)(full).isFile()) continue;
28680
29037
  const match = name.match(APP_FILE_RE);
28681
29038
  const wireMatch = match ? null : name.match(WIRE_FILE_RE);
28682
29039
  if (!match && !wireMatch) continue;
@@ -28685,7 +29042,7 @@ function buildEnvelopeFromDirectory(folder) {
28685
29042
  const ext = (match ? match[3] : wireMatch[2]).toLowerCase();
28686
29043
  let role = "pdf";
28687
29044
  if (ext === "xml") {
28688
- const xml = (0, import_node_fs12.readFileSync)(full, "utf8");
29045
+ const xml = (0, import_node_fs13.readFileSync)(full, "utf8");
28689
29046
  if (/<Document[\s>]/i.test(xml)) role = "manifest";
28690
29047
  else if (FORM_XML_RE.test(xml)) role = "form";
28691
29048
  else continue;
@@ -28708,8 +29065,8 @@ function buildEnvelopeFromDirectory(folder) {
28708
29065
  group.sort((a, b) => roleOrder[a.role] - roleOrder[b.role] || partNo(a.partName) - partNo(b.partName));
28709
29066
  const applicationId = group[0].applicationId;
28710
29067
  const form = group.find((entry) => entry.role === "form");
28711
- const createdAt = form ? extractElement((0, import_node_fs12.readFileSync)(form.path, "utf8"), "sendtimestamp") : null;
28712
- const files = group.map((entry) => inlineFile(entry.filename, (0, import_node_fs12.readFileSync)(entry.path), entry.ext));
29068
+ const createdAt = form ? extractElement((0, import_node_fs13.readFileSync)(form.path, "utf8"), "sendtimestamp") : null;
29069
+ const files = group.map((entry) => inlineFile(entry.filename, (0, import_node_fs13.readFileSync)(entry.path), entry.ext));
28713
29070
  return {
28714
29071
  schema_version: "1.0",
28715
29072
  application_id: applicationId,
@@ -28815,13 +29172,13 @@ function appendStarterSchemaErrors(envelope, errors) {
28815
29172
  }
28816
29173
  }
28817
29174
  function formatSchemaError(error51) {
28818
- const path9 = error51.instancePath || "/";
29175
+ const path10 = error51.instancePath || "/";
28819
29176
  if (error51.keyword === "additionalProperties") {
28820
29177
  const params = recordOf4(error51.params);
28821
29178
  const prop = String(params.additionalProperty || "");
28822
- return `schema ${path9}: additional property '${prop}' is not allowed`;
29179
+ return `schema ${path10}: additional property '${prop}' is not allowed`;
28823
29180
  }
28824
- return `schema ${path9}: ${error51.message || error51.keyword}`;
29181
+ return `schema ${path10}: ${error51.message || error51.keyword}`;
28825
29182
  }
28826
29183
  function recordOf4(value) {
28827
29184
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
@@ -28905,7 +29262,7 @@ function extractManifestParts(xml) {
28905
29262
  return parts;
28906
29263
  }
28907
29264
  function producerPartName(filename) {
28908
- const match = (0, import_node_path11.basename)(filename).match(APP_FILE_RE);
29265
+ const match = (0, import_node_path12.basename)(filename).match(APP_FILE_RE);
28909
29266
  return match?.[2] || null;
28910
29267
  }
28911
29268
  function textOf(xml, tag) {
@@ -28922,7 +29279,7 @@ function summarizeEnvelope(envelope, opts) {
28922
29279
  return {
28923
29280
  compatibility: APPLICATION_PACKAGE_COMPATIBILITY,
28924
29281
  source: opts.source,
28925
- inputPath: opts.inputPath ? statMaybe(opts.inputPath)?.isDirectory() ? opts.inputPath : (0, import_node_path11.basename)(opts.inputPath) : "",
29282
+ inputPath: opts.inputPath ? statMaybe(opts.inputPath)?.isDirectory() ? opts.inputPath : (0, import_node_path12.basename)(opts.inputPath) : "",
28926
29283
  schemaVersion: envelope.schema_version ? String(envelope.schema_version) : null,
28927
29284
  packageFormatVersion: envelope.package_format_version ? String(envelope.package_format_version) : null,
28928
29285
  applicationId: envelope.application_id ? String(envelope.application_id) : null,
@@ -28945,7 +29302,7 @@ function summarizeEnvelope(envelope, opts) {
28945
29302
  }
28946
29303
  function statMaybe(inputPath) {
28947
29304
  try {
28948
- return (0, import_node_fs12.statSync)(inputPath);
29305
+ return (0, import_node_fs13.statSync)(inputPath);
28949
29306
  } catch {
28950
29307
  return null;
28951
29308
  }
@@ -29026,7 +29383,7 @@ function localValidationOutput(validation) {
29026
29383
  }
29027
29384
  function contentTypeFor(filePath, override) {
29028
29385
  if (typeof override === "string" && override.trim()) return override.trim();
29029
- const ext = import_node_path12.default.extname(filePath).toLowerCase();
29386
+ const ext = import_node_path13.default.extname(filePath).toLowerCase();
29030
29387
  if (ext === ".pdf") return "application/pdf";
29031
29388
  if (ext === ".xml") return "application/xml";
29032
29389
  if (ext === ".json") return "application/json";
@@ -29046,8 +29403,8 @@ var ingest = defineCommand({
29046
29403
  const body = { missionId: args.missionId, caseId: args.caseId };
29047
29404
  if (args.url) body.url = args.url;
29048
29405
  if (args.file) {
29049
- body.filename = import_node_path12.default.basename(args.file);
29050
- body.contentBase64 = import_node_fs13.default.readFileSync(args.file).toString("base64");
29406
+ body.filename = import_node_path13.default.basename(args.file);
29407
+ body.contentBase64 = import_node_fs14.default.readFileSync(args.file).toString("base64");
29051
29408
  }
29052
29409
  return output((await client.post("/api/ingest", body)).data, fmt);
29053
29410
  }
@@ -29635,10 +29992,10 @@ var document2 = defineCommand({
29635
29992
  const missionId = requireMissionContext(args, "document upload");
29636
29993
  req(args, "file");
29637
29994
  const filePath = String(args.file);
29638
- const bytes = import_node_fs13.default.readFileSync(filePath);
29995
+ const bytes = import_node_fs14.default.readFileSync(filePath);
29639
29996
  if (!bytes.length) throw commandError("EMPTY_FILE", 1, `${filePath} is empty`);
29640
29997
  const body = {
29641
- filename: args.filename || import_node_path12.default.basename(filePath),
29998
+ filename: args.filename || import_node_path13.default.basename(filePath),
29642
29999
  contentType: contentTypeFor(filePath, args.contentType),
29643
30000
  bytesBase64: bytes.toString("base64")
29644
30001
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@senticor/hive",
3
- "version": "1.47.0",
3
+ "version": "1.48.0",
4
4
  "description": "Cognitive Hive OS — unified CLI",
5
5
  "type": "commonjs",
6
6
  "bin": {