@lotics/cli 0.157.0 → 0.162.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.
package/dist/src/cli.js CHANGED
@@ -26822,12 +26822,12 @@ var require_tokens = __commonJS({
26822
26822
  });
26823
26823
  }
26824
26824
  exports2.assignCategoriesMapProp = assignCategoriesMapProp;
26825
- function singleAssignCategoriesToksMap(path13, nextNode) {
26826
- utils_1.forEach(path13, function(pathNode) {
26825
+ function singleAssignCategoriesToksMap(path14, nextNode) {
26826
+ utils_1.forEach(path14, function(pathNode) {
26827
26827
  nextNode.categoryMatchesMap[pathNode.tokenTypeIdx] = true;
26828
26828
  });
26829
26829
  utils_1.forEach(nextNode.CATEGORIES, function(nextCategory) {
26830
- var newPath = path13.concat(nextNode);
26830
+ var newPath = path14.concat(nextNode);
26831
26831
  if (!utils_1.contains(newPath, nextCategory)) {
26832
26832
  singleAssignCategoriesToksMap(newPath, nextCategory);
26833
26833
  }
@@ -28590,10 +28590,10 @@ var require_interpreter = __commonJS({
28590
28590
  /** @class */
28591
28591
  (function(_super) {
28592
28592
  __extends(AbstractNextPossibleTokensWalker2, _super);
28593
- function AbstractNextPossibleTokensWalker2(topProd, path13) {
28593
+ function AbstractNextPossibleTokensWalker2(topProd, path14) {
28594
28594
  var _this = _super.call(this) || this;
28595
28595
  _this.topProd = topProd;
28596
- _this.path = path13;
28596
+ _this.path = path14;
28597
28597
  _this.possibleTokTypes = [];
28598
28598
  _this.nextProductionName = "";
28599
28599
  _this.nextProductionOccurrence = 0;
@@ -28647,9 +28647,9 @@ var require_interpreter = __commonJS({
28647
28647
  /** @class */
28648
28648
  (function(_super) {
28649
28649
  __extends(NextAfterTokenWalker2, _super);
28650
- function NextAfterTokenWalker2(topProd, path13) {
28651
- var _this = _super.call(this, topProd, path13) || this;
28652
- _this.path = path13;
28650
+ function NextAfterTokenWalker2(topProd, path14) {
28651
+ var _this = _super.call(this, topProd, path14) || this;
28652
+ _this.path = path14;
28653
28653
  _this.nextTerminalName = "";
28654
28654
  _this.nextTerminalOccurrence = 0;
28655
28655
  _this.nextTerminalName = _this.path.lastTok.name;
@@ -29346,10 +29346,10 @@ var require_lookahead = __commonJS({
29346
29346
  }
29347
29347
  return result;
29348
29348
  }
29349
- function pathToHashKeys(path13) {
29349
+ function pathToHashKeys(path14) {
29350
29350
  var keys3 = [""];
29351
- for (var i2 = 0; i2 < path13.length; i2++) {
29352
- var tokType = path13[i2];
29351
+ for (var i2 = 0; i2 < path14.length; i2++) {
29352
+ var tokType = path14[i2];
29353
29353
  var longerKeys = [];
29354
29354
  for (var j = 0; j < keys3.length; j++) {
29355
29355
  var currShorterKey = keys3[j];
@@ -29661,9 +29661,9 @@ var require_checks = __commonJS({
29661
29661
  return errors2;
29662
29662
  }
29663
29663
  exports2.validateRuleIsOverridden = validateRuleIsOverridden;
29664
- function validateNoLeftRecursion(topRule, currRule, errMsgProvider, path13) {
29665
- if (path13 === void 0) {
29666
- path13 = [];
29664
+ function validateNoLeftRecursion(topRule, currRule, errMsgProvider, path14) {
29665
+ if (path14 === void 0) {
29666
+ path14 = [];
29667
29667
  }
29668
29668
  var errors2 = [];
29669
29669
  var nextNonTerminals = getFirstNoneTerminal(currRule.definition);
@@ -29676,15 +29676,15 @@ var require_checks = __commonJS({
29676
29676
  errors2.push({
29677
29677
  message: errMsgProvider.buildLeftRecursionError({
29678
29678
  topLevelRule: topRule,
29679
- leftRecursionPath: path13
29679
+ leftRecursionPath: path14
29680
29680
  }),
29681
29681
  type: parser_1.ParserDefinitionErrorType.LEFT_RECURSION,
29682
29682
  ruleName
29683
29683
  });
29684
29684
  }
29685
- var validNextSteps = utils2.difference(nextNonTerminals, path13.concat([topRule]));
29685
+ var validNextSteps = utils2.difference(nextNonTerminals, path14.concat([topRule]));
29686
29686
  var errorsFromNextSteps = utils2.map(validNextSteps, function(currRefRule) {
29687
- var newPath = utils2.cloneArr(path13);
29687
+ var newPath = utils2.cloneArr(path14);
29688
29688
  newPath.push(currRefRule);
29689
29689
  return validateNoLeftRecursion(topRule, currRefRule, errMsgProvider, newPath);
29690
29690
  });
@@ -37293,8 +37293,8 @@ var require_utils4 = __commonJS({
37293
37293
  var result = transform2[inputType][outputType](input);
37294
37294
  return result;
37295
37295
  };
37296
- exports2.resolve = function(path13) {
37297
- var parts = path13.split("/");
37296
+ exports2.resolve = function(path14) {
37297
+ var parts = path14.split("/");
37298
37298
  var result = [];
37299
37299
  for (var index = 0; index < parts.length; index++) {
37300
37300
  var part = parts[index];
@@ -43147,18 +43147,18 @@ var require_object = __commonJS({
43147
43147
  var object2 = new ZipObject(name2, zipObjectContent, o);
43148
43148
  this.files[name2] = object2;
43149
43149
  };
43150
- var parentFolder = function(path13) {
43151
- if (path13.slice(-1) === "/") {
43152
- path13 = path13.substring(0, path13.length - 1);
43150
+ var parentFolder = function(path14) {
43151
+ if (path14.slice(-1) === "/") {
43152
+ path14 = path14.substring(0, path14.length - 1);
43153
43153
  }
43154
- var lastSlash = path13.lastIndexOf("/");
43155
- return lastSlash > 0 ? path13.substring(0, lastSlash) : "";
43154
+ var lastSlash = path14.lastIndexOf("/");
43155
+ return lastSlash > 0 ? path14.substring(0, lastSlash) : "";
43156
43156
  };
43157
- var forceTrailingSlash = function(path13) {
43158
- if (path13.slice(-1) !== "/") {
43159
- path13 += "/";
43157
+ var forceTrailingSlash = function(path14) {
43158
+ if (path14.slice(-1) !== "/") {
43159
+ path14 += "/";
43160
43160
  }
43161
- return path13;
43161
+ return path14;
43162
43162
  };
43163
43163
  var folderAdd = function(name2, createFolders) {
43164
43164
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults2.createFolders;
@@ -44160,9 +44160,9 @@ var require_lib4 = __commonJS({
44160
44160
  // src/cli.ts
44161
44161
  import dns from "node:dns";
44162
44162
  import net2 from "node:net";
44163
- import fs13 from "node:fs";
44163
+ import fs14 from "node:fs";
44164
44164
  import os4 from "node:os";
44165
- import path12 from "node:path";
44165
+ import path13 from "node:path";
44166
44166
  import readline from "node:readline";
44167
44167
 
44168
44168
  // ../shared/src/transport_error.ts
@@ -44356,8 +44356,8 @@ var LoticsClient = class {
44356
44356
  }
44357
44357
  return headers;
44358
44358
  }
44359
- async request(method, path13, body) {
44360
- const url2 = `${this.baseUrl}${path13}`;
44359
+ async request(method, path14, body) {
44360
+ const url2 = `${this.baseUrl}${path14}`;
44361
44361
  const headers = this.buildHeaders();
44362
44362
  const init = { method, headers };
44363
44363
  if (body !== void 0) {
@@ -44400,8 +44400,8 @@ var LoticsClient = class {
44400
44400
  async deleteWorkspace(id) {
44401
44401
  return this.request("DELETE", `/v1/workspaces/${encodeURIComponent(id)}`);
44402
44402
  }
44403
- async login() {
44404
- return this.request("POST", "/v1/cli/login");
44403
+ async login(body) {
44404
+ return this.request("POST", "/v1/cli/login", body ?? {});
44405
44405
  }
44406
44406
  async listTools() {
44407
44407
  return this.request("GET", "/v1/tools");
@@ -44468,90 +44468,6 @@ var LoticsClient = class {
44468
44468
  async createApp(body) {
44469
44469
  return this.request("POST", "/v1/apps", body);
44470
44470
  }
44471
- /**
44472
- * Install a package version into the current workspace — ONE endpoint,
44473
- * kind-branched into a discriminated response (`kind`). An `app` package
44474
- * scaffolds the data model / deploys / materializes and returns the installation
44475
- * app (+ advisory knowledge warnings); a `content` package installs only its
44476
- * doc corpus and returns the installation row. `bind_to` (content only)
44477
- * resolves a name collision by adopting an existing same-named doc as
44478
- * package-managed. `version` omitted installs the latest published version.
44479
- */
44480
- async installPackage(package_id, body) {
44481
- return this.request(
44482
- "POST",
44483
- `/v1/packages/${encodeURIComponent(package_id)}/installations`,
44484
- body
44485
- );
44486
- }
44487
- /**
44488
- * Uninstall a standalone content package — delete the installation row. By
44489
- * default the package-bound docs are ARCHIVED; `keep_content` retains them as
44490
- * ordinary workspace docs. Admin-only. Backs `opctl uninstall`.
44491
- */
44492
- async uninstallContentPackage(installation_id, opts = {}) {
44493
- const qs = opts.keep_content ? "?keep_content=true" : "";
44494
- return this.request(
44495
- "DELETE",
44496
- `/v1/content-installations/${encodeURIComponent(installation_id)}${qs}`
44497
- );
44498
- }
44499
- /**
44500
- * Preview upgrading a standalone content installation — the knowledge namespace's
44501
- * per-alias `entries` (added/changed/removed/drifted + a `modified` flag) plus the
44502
- * consent-requiring `templates` (a template the target changed whose live content
44503
- * was locally edited; a clean one auto-updates and is absent). No writes.
44504
- * Admin-only.
44505
- */
44506
- async previewContentInstallationUpgrade(installation_id, opts = {}) {
44507
- const qs = opts.version !== void 0 ? `?version=${opts.version}` : "";
44508
- return this.request(
44509
- "GET",
44510
- `/v1/content-installations/${encodeURIComponent(installation_id)}/upgrade${qs}`
44511
- );
44512
- }
44513
- /**
44514
- * Apply a standalone content upgrade — propagate the target version's content per
44515
- * the resolutions (`knowledge`: a modified change/removal or drift needs consent;
44516
- * `templates`: a locally-edited changed template takes revert|keep), then advance
44517
- * the pin + binding. Returns the updated installation row. Admin-only.
44518
- */
44519
- async applyContentInstallationUpgrade(installation_id, body) {
44520
- return this.request(
44521
- "POST",
44522
- `/v1/content-installations/${encodeURIComponent(installation_id)}/upgrade`,
44523
- body
44524
- );
44525
- }
44526
- /**
44527
- * List a workspace's package-managed knowledge installations, each folded with
44528
- * registry status (name, kind, official badge, latest version, update-available).
44529
- * Member-accessible (workspace-scoped); backs the settings "Managed by" badge.
44530
- */
44531
- async listContentInstallations(workspace_id) {
44532
- return this.request(
44533
- "GET",
44534
- `/v1/workspaces/${encodeURIComponent(workspace_id)}/content-installations`
44535
- );
44536
- }
44537
- /**
44538
- * Uninstall a package installation (backs `opctl uninstall`). Does
44539
- * everything DELETE does plus archives the installation's lifecycle
44540
- * artifacts; with `archive_tables` it also archives the scaffolded entity
44541
- * tables — refused server-side unless this installation created them
44542
- * (provenance) and nothing else references them. Admin-only.
44543
- */
44544
- async uninstallAppPackage(app_id, body) {
44545
- return this.request("POST", `/v1/apps/${encodeURIComponent(app_id)}/uninstall`, body);
44546
- }
44547
- /**
44548
- * Partial-merge a package installation's config (backs `opctl package config
44549
- * --set`). Only the provided keys change; validated against the installed
44550
- * contract. Returns the full effective config. Admin-only.
44551
- */
44552
- async updateAppPackageConfig(app_id, body) {
44553
- return this.request("PATCH", `/v1/apps/${encodeURIComponent(app_id)}/package-config`, body);
44554
- }
44555
44471
  /**
44556
44472
  * Retire (or `undo` un-retire) a registry package (backs `lotics app
44557
44473
  * unpublish` — the endpoint/audit action keep the `retire` name to avoid API
@@ -44562,83 +44478,75 @@ var LoticsClient = class {
44562
44478
  async retirePackage(package_id, body) {
44563
44479
  return this.request("POST", `/v1/packages/${encodeURIComponent(package_id)}/retire`, body);
44564
44480
  }
44481
+ // --- Packages (registry reads + installations) ---
44482
+ // Authoring is server-side: apps via `POST /v1/apps/{id}/package-publish|release`,
44483
+ // content packages via the `publish_content`/`release_content` tools. There is no
44484
+ // client-side create-package / upload-bundle path.
44565
44485
  /**
44566
- * Eject an installation from its package — re-deploy the pinned version's
44567
- * source as a workspace-owned app version, then sever the package link
44568
- * (clears `package_id`/`package_version`, stamps `ejected_at`). One-way: the
44569
- * app becomes a normal bespoke app and can no longer be upgraded. Returns the
44570
- * resulting app.
44486
+ * The starters this organization can copy — Lotics-reviewed ones plus its own,
44487
+ * never a catalogue of everything published. The server returns exactly what
44488
+ * instantiate would accept, so the list cannot offer a refusal. Admin-only.
44571
44489
  */
44572
- async ejectPackage(app_id) {
44573
- return this.request("POST", `/v1/apps/${encodeURIComponent(app_id)}/eject`);
44490
+ async listStarters() {
44491
+ return this.request("GET", "/v1/starters");
44574
44492
  }
44575
44493
  /**
44576
- * Fleet upgrade — bring every installation of a package across the CALLER'S
44577
- * org to the target version (latest when omitted) in one call. Hands-off
44578
- * applies only where the preview is clean; installations with breaking/
44579
- * drift/modified-core findings are skipped and reported for the normal
44580
- * per-installation consent flow. Backs `opctl upgrade <package_id>` (fleet).
44581
- * Admin-only; org-scoped (no workspace header needed).
44582
- */
44583
- /**
44584
- * Yank / unyank a published package version — refuses NEW installs/upgrades/
44585
- * adopts targeting it; pinned installations keep running. Owner-org
44586
- * admin-only. Backs `opctl package yank`.
44494
+ * Copy a starter into the current workspace.
44495
+ *
44496
+ * Server-side this scaffolds the schema, creates the templates, docs and
44497
+ * sample records, creates a BESPOKE app and materializes onto it — then stops.
44498
+ * It deploys nothing: a starter ships source only, and the source has to be
44499
+ * built where codegen can bake THIS workspace's field ids. `bundle_url` is a
44500
+ * presigned GET of that source, and finishing the job is the caller's half.
44501
+ * Admin-only.
44587
44502
  */
44588
- async yankPackageVersion(package_id, version2, yanked) {
44503
+ async instantiateStarter(starter_id, body) {
44589
44504
  return this.request(
44590
44505
  "POST",
44591
- `/v1/packages/${encodeURIComponent(package_id)}/versions/${version2}/yank`,
44592
- { yanked }
44593
- );
44594
- }
44595
- async fleetUpgradePackage(package_id, body) {
44596
- return this.request(
44597
- "POST",
44598
- `/v1/packages/${encodeURIComponent(package_id)}/fleet-upgrade`,
44506
+ `/v1/starters/${encodeURIComponent(starter_id)}/instantiate`,
44599
44507
  body
44600
44508
  );
44601
44509
  }
44602
- // --- Packages (registry reads + installations) ---
44603
- // Authoring is server-side: apps via `POST /v1/apps/{id}/package-publish|release`,
44604
- // content packages via the `publish_content`/`release_content` tools. There is no
44605
- // client-side create-package / upload-bundle path.
44606
44510
  /**
44607
- * Fetch a registry app package's metadata (incl. `kind`, `latest_version` and
44608
- * the Lotics-backed `is_official` trust badge). Admin-only; cross-tenant by id.
44511
+ * Which starter this app is the origin of. 404 when it has published none.
44512
+ *
44513
+ * The app row carries no pin, so this is the only app→starter direction there
44514
+ * is — provenance lives on the published version. Admin-only.
44609
44515
  */
44610
- async getPackage(package_id) {
44611
- return this.request("GET", `/v1/packages/${encodeURIComponent(package_id)}`);
44612
- }
44613
- /** Version history newest-first (no contract payloads) — backs `opctl package show`. Admin-only. */
44614
- async listPackageVersions(package_id) {
44615
- return this.request("GET", `/v1/packages/${encodeURIComponent(package_id)}/versions`);
44516
+ async getAppOriginStarter(app_id) {
44517
+ return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/origin-starter`);
44616
44518
  }
44617
44519
  /**
44618
- * Upgrade a package installation to a newer published version — extends the
44619
- * binding additively, re-materializes the target version's
44620
- * queries/workflows/agents (preserving workspace overlay), prunes dropped
44621
- * package artifacts, and bumps the pin. `version` omitted upgrades to the
44622
- * latest. Returns the resulting app. Admin-only.
44520
+ * Capture live records from this workspace as a starter's sample data.
44521
+ *
44522
+ * The alias-keyed shape is produced SERVER-side, because the contract alias
44523
+ * space is minted by extract and exists nowhere a project can read it. Pure
44524
+ * read — the caller writes the returned files into the project and reviews
44525
+ * them, which matters: these rows are copied verbatim into every workspace
44526
+ * that takes the starter. Admin-only.
44623
44527
  */
44624
- async upgradePackage(app_id, body) {
44528
+ async captureStarterFixtures(app_id, opts = {}) {
44529
+ const params = new URLSearchParams();
44530
+ if (opts.entities !== void 0 && opts.entities.length > 0) {
44531
+ params.set("entities", opts.entities.join(","));
44532
+ }
44533
+ if (opts.limit !== void 0) params.set("limit", String(opts.limit));
44534
+ const qs = params.toString();
44625
44535
  return this.request(
44626
- "POST",
44627
- `/v1/apps/${encodeURIComponent(app_id)}/package-upgrade`,
44628
- body
44536
+ "GET",
44537
+ `/v1/apps/${encodeURIComponent(app_id)}/fixtures-capture${qs ? `?${qs}` : ""}`
44629
44538
  );
44630
44539
  }
44631
44540
  /**
44632
- * Preview a package upgrade — the additive plan, informational removals,
44633
- * breaking contract changes, the binding drift report, and the modified-core
44634
- * report — with no writes. Admin-only.
44541
+ * Fetch a registry starter's metadata (`latest_version` and the Lotics-backed
44542
+ * `is_official` trust badge). Admin-only; cross-tenant by id.
44635
44543
  */
44636
- async previewPackageUpgrade(app_id, opts = {}) {
44637
- const query = opts.version !== void 0 ? `?version=${opts.version}` : "";
44638
- return this.request(
44639
- "GET",
44640
- `/v1/apps/${encodeURIComponent(app_id)}/package-upgrade${query}`
44641
- );
44544
+ async getPackage(package_id) {
44545
+ return this.request("GET", `/v1/packages/${encodeURIComponent(package_id)}`);
44546
+ }
44547
+ /** Version history newest-first (no contract payloads) — backs `opctl package show`. Admin-only. */
44548
+ async listPackageVersions(package_id) {
44549
+ return this.request("GET", `/v1/packages/${encodeURIComponent(package_id)}/versions`);
44642
44550
  }
44643
44551
  /**
44644
44552
  * Workspace-wide dangling-reference sweep — active app/workflow artifacts
@@ -44648,14 +44556,6 @@ var LoticsClient = class {
44648
44556
  async getWorkspaceDanglingReferences() {
44649
44557
  return this.request("GET", "/v1/workspaces/dangling-references");
44650
44558
  }
44651
- /**
44652
- * Health check for a package installation — version pin vs. registry latest,
44653
- * binding drift, and locally modified core artifacts. Read-only; backs
44654
- * `opctl package doctor`. Admin-only.
44655
- */
44656
- async getPackageHealth(app_id) {
44657
- return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/package-health`);
44658
- }
44659
44559
  /**
44660
44560
  * Preview a release — the dry run behind `opctl app release`. Runs the
44661
44561
  * binding-aware extract of the origin (aliases stable through the app's current
@@ -44671,9 +44571,6 @@ var LoticsClient = class {
44671
44571
  if (opts.knowledge !== void 0 && opts.knowledge.length > 0) {
44672
44572
  params.set("knowledge", JSON.stringify(opts.knowledge));
44673
44573
  }
44674
- if (opts.config !== void 0) {
44675
- params.set("config", JSON.stringify(opts.config));
44676
- }
44677
44574
  const query = params.toString();
44678
44575
  return this.request(
44679
44576
  "GET",
@@ -44706,9 +44603,6 @@ var LoticsClient = class {
44706
44603
  if (opts.knowledge !== void 0 && opts.knowledge.length > 0) {
44707
44604
  params.set("knowledge", JSON.stringify(opts.knowledge));
44708
44605
  }
44709
- if (opts.config !== void 0 && opts.config.length > 0) {
44710
- params.set("config", JSON.stringify(opts.config));
44711
- }
44712
44606
  if (opts.renames !== void 0 && opts.renames.length > 0) {
44713
44607
  params.set("renames", JSON.stringify(opts.renames));
44714
44608
  }
@@ -44812,10 +44706,6 @@ var LoticsClient = class {
44812
44706
  const qs = group_id ? `?group_id=${encodeURIComponent(group_id)}` : "";
44813
44707
  return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/members${qs}`);
44814
44708
  }
44815
- /** A package installation's alias→id maps (fields/options/roles) — the app's runtime F/OPT resolution. */
44816
- async appBinding(app_id) {
44817
- return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/binding`);
44818
- }
44819
44709
  /**
44820
44710
  * Resolve the full option set (key, label, color) of a named query's select
44821
44711
  * columns — the picker companion to `appQuery`. Mirrors
@@ -45955,12 +45845,23 @@ var COMMANDS = [
45955
45845
  ]
45956
45846
  },
45957
45847
  {
45958
- verbs: ["install"],
45959
- help: [" lotics install <package_id> Materialize a published package into this workspace"]
45960
- },
45961
- {
45962
- verbs: ["upgrade"],
45963
- help: [" lotics upgrade Take the installed package's next version"]
45848
+ verbs: ["starter"],
45849
+ help: [
45850
+ " lotics starter list Starters you can copy into this workspace",
45851
+ " lotics starter show <starter_id> What one carries: tables, docs, templates, sample data",
45852
+ " lotics starter init <starter_id> [path]",
45853
+ " Copy it in \u2014 schema, templates, knowledge docs,",
45854
+ " sample records and an editable app project. A COPY:",
45855
+ " everything it creates is yours outright, with no",
45856
+ " link back and nothing to upgrade. Builds and deploys",
45857
+ " locally, so it needs node + a few minutes.",
45858
+ " --no-sample-data skips the sample records;",
45859
+ " --adopt allows a workspace that is not empty",
45860
+ " lotics starter fixtures capture --entity <alias> --limit <n>",
45861
+ " (authoring) Write reviewable sample records into the",
45862
+ " app project. READ WHAT IT WROTE before committing \u2014",
45863
+ " these rows ship to everyone who copies the starter"
45864
+ ]
45964
45865
  },
45965
45866
  {
45966
45867
  verbs: ["docs"],
@@ -46214,36 +46115,10 @@ import { tmpdir } from "node:os";
46214
46115
  // src/starter_template.ts
46215
46116
  var STARTER_REACT_NATIVE_VERSION = "0.85.3";
46216
46117
  var VITEST_SETUP_FILENAME = "vitest.setup.ts";
46217
- var VITEST_SETUP_CONTENT = `import { vi } from "vitest";
46218
-
46219
- // A package-linked app's generated .lotics/app_fields.ts resolves F/OPT/ROLE
46220
- // from the installation's live binding at module load (\`await getAppBinding()\`,
46221
- // a network call over the host bridge). Under vitest/jsdom there is no host, so
46222
- // that call throws while a test is still COLLECTING \u2014 failing every test that
46223
- // imports the app graph, even pure logic tests. getAppBinding is the network
46224
- // boundary; mock it (and only it) so the module graph evaluates in tests.
46225
- //
46226
- // The stub returns an ECHO binding: any alias resolves to a synthetic,
46227
- // self-identifying id (fld:test:<entity>.<field>, opt:test:\u2026, grp:test:\u2026). Echo,
46228
- // not empty maps \u2014 app_fields's bound() throws on a missing key, so empty maps
46229
- // would just re-break collection; and a ':test:' id can never be confused with a
46230
- // real fld_\u2026/opt_\u2026/grp_\u2026 id, so a test that depends on a concrete binding fails
46231
- // loud instead of silently reading undefined.
46232
- vi.mock("@lotics/app-sdk", async (importOriginal) => {
46233
- const actual = await importOriginal<typeof import("@lotics/app-sdk")>();
46234
- const echoIds = (prefix: string): Record<string, string> =>
46235
- new Proxy(
46236
- {},
46237
- {
46238
- get: (_target, key) => (typeof key === "string" ? \`\${prefix}:test:\${key}\` : undefined),
46239
- },
46240
- ) as Record<string, string>;
46241
- return {
46242
- ...actual,
46243
- getAppBinding: () =>
46244
- Promise.resolve({ fields: echoIds("fld"), options: echoIds("opt"), roles: echoIds("grp") }),
46245
- };
46246
- });
46118
+ var VITEST_SETUP_CONTENT = `// Runs before every test file (wired by vite.config.ts \`test.setupFiles\`).
46119
+ // Empty by default \u2014 put global test setup here: custom matchers, a fetch stub,
46120
+ // timezone pinning, anything your suite needs before it collects.
46121
+ export {};
46247
46122
  `;
46248
46123
  function buildStarterTemplate(args) {
46249
46124
  const uiVersion = args.ui_version;
@@ -46472,7 +46347,7 @@ export default defineConfig({
46472
46347
  },
46473
46348
  test: {
46474
46349
  environment: "jsdom",
46475
- // Stub @lotics/app-sdk's getAppBinding (the network boundary) before any test
46350
+ // Global test setup, run before every test file (empty until an author fills it)
46476
46351
  // collects. A package-linked app's generated .lotics/app_fields.ts awaits it
46477
46352
  // at module load; without the stub that network call throws under jsdom and
46478
46353
  // every test that imports the app graph fails to collect. See vitest.setup.ts.
@@ -46987,7 +46862,6 @@ var SUPPORTED_OPS = /* @__PURE__ */ new Set([
46987
46862
  "workflow",
46988
46863
  "members",
46989
46864
  "context",
46990
- "binding",
46991
46865
  "upload_url",
46992
46866
  "upload_complete",
46993
46867
  "agentRuns",
@@ -47008,11 +46882,10 @@ async function dispatchRpc(client, body, opts) {
47008
46882
  }
47009
46883
  switch (body.op) {
47010
46884
  case "context": {
47011
- const [who, app] = await Promise.all([client.whoami(), client.getApp(body.app_id)]);
46885
+ const who = await client.whoami();
47012
46886
  return {
47013
46887
  member_id: who.member_id,
47014
- comments_enabled: opts?.commentsEnabled ?? false,
47015
- config: app.config ?? {}
46888
+ comments_enabled: opts?.commentsEnabled ?? false
47016
46889
  };
47017
46890
  }
47018
46891
  case "query": {
@@ -47048,8 +46921,6 @@ async function dispatchRpc(client, body, opts) {
47048
46921
  const p = body.payload;
47049
46922
  return client.appMembers(body.app_id, p?.group);
47050
46923
  }
47051
- case "binding":
47052
- return client.appBinding(body.app_id);
47053
46924
  case "upload_url": {
47054
46925
  const p = body.payload;
47055
46926
  if (!p || typeof p.filename !== "string" || typeof p.mime_type !== "string" || typeof p.file_size !== "number") {
@@ -48490,123 +48361,6 @@ export type AppOptions = typeof OPT;
48490
48361
  `;
48491
48362
  }
48492
48363
 
48493
- // src/generate_package_fields.ts
48494
- var HEADER2 = `// Auto-generated by 'lotics app codegen' and 'lotics app pull' (linked/published app).
48495
- // DO NOT EDIT \u2014 regenerated from the installation's live binding.
48496
- //
48497
- // A package installation resolves F/OPT/ROLE at MODULE LOAD from its binding
48498
- // (contract alias \u2192 THIS workspace's concrete id) via the SDK's \`binding\` RPC.
48499
- // Top-level await: the module graph waits for the binding before any importer
48500
- // evaluates, so every entry is a plain string.
48501
- import { getAppBinding } from "@lotics/app-sdk";
48502
-
48503
- const binding = await getAppBinding();
48504
-
48505
- function bound(map: Record<string, string>, key: string, kind: string): string {
48506
- const id = map[key];
48507
- if (id === undefined) {
48508
- throw new Error(
48509
- \`app_fields: \${kind} "\${key}" is not in this installation's binding \u2014 \` +
48510
- \`the generated app_fields.ts is stale relative to the installed contract version.\`,
48511
- );
48512
- }
48513
- return id;
48514
- }
48515
- `;
48516
- function parseBinding(binding) {
48517
- const entities = [];
48518
- const entityByAlias = /* @__PURE__ */ new Map();
48519
- const fieldByKey = /* @__PURE__ */ new Map();
48520
- for (const key of Object.keys(binding.fields)) {
48521
- const dot = key.indexOf(".");
48522
- if (dot <= 0 || dot >= key.length - 1) continue;
48523
- const entityAlias = key.slice(0, dot);
48524
- const fieldAlias = key.slice(dot + 1);
48525
- let entity = entityByAlias.get(entityAlias);
48526
- if (entity === void 0) {
48527
- entity = { alias: entityAlias, fields: [] };
48528
- entityByAlias.set(entityAlias, entity);
48529
- entities.push(entity);
48530
- }
48531
- const field = { alias: fieldAlias, key, options: [] };
48532
- entity.fields.push(field);
48533
- fieldByKey.set(key, field);
48534
- }
48535
- for (const key of Object.keys(binding.options)) {
48536
- const colon = key.indexOf(":");
48537
- if (colon <= 0 || colon >= key.length - 1) continue;
48538
- const fieldKey = key.slice(0, colon);
48539
- const optionAlias = key.slice(colon + 1);
48540
- const field = fieldByKey.get(fieldKey);
48541
- if (field === void 0) continue;
48542
- field.options.push({ alias: optionAlias, key });
48543
- }
48544
- return { entities, roles: Object.keys(binding.roles) };
48545
- }
48546
- function emitFieldMap2(entities) {
48547
- if (entities.length === 0) return `export const F = {} as const;`;
48548
- const blocks = entities.map((entity) => {
48549
- const lines = entity.fields.map(
48550
- (field) => ` ${propKey(field.alias)}: bound(binding.fields, ${JSON.stringify(field.key)}, "field"),`
48551
- );
48552
- return ` ${propKey(entity.alias.toUpperCase())}: {
48553
- ${lines.join("\n")}
48554
- },`;
48555
- });
48556
- return `export const F = {
48557
- ${blocks.join("\n")}
48558
- } as const;`;
48559
- }
48560
- function emitOptionMap2(entities) {
48561
- const entityBlocks = [];
48562
- for (const entity of entities) {
48563
- const fieldBlocks = [];
48564
- for (const field of entity.fields) {
48565
- if (field.options.length === 0) continue;
48566
- const lines = field.options.map(
48567
- (option) => ` ${propKey(option.alias)}: bound(binding.options, ${JSON.stringify(option.key)}, "option"),`
48568
- );
48569
- fieldBlocks.push(` ${propKey(field.alias)}: {
48570
- ${lines.join("\n")}
48571
- },`);
48572
- }
48573
- if (fieldBlocks.length === 0) continue;
48574
- entityBlocks.push(` ${propKey(entity.alias.toUpperCase())}: {
48575
- ${fieldBlocks.join("\n")}
48576
- },`);
48577
- }
48578
- if (entityBlocks.length === 0) return `export const OPT = {} as const;`;
48579
- return `export const OPT = {
48580
- ${entityBlocks.join("\n")}
48581
- } as const;`;
48582
- }
48583
- function emitRoleMap(roles) {
48584
- if (roles.length === 0) return `export const ROLE = {} as const;`;
48585
- const lines = roles.map(
48586
- (role) => ` ${propKey(role)}: bound(binding.roles, ${JSON.stringify(role)}, "role"),`
48587
- );
48588
- return `export const ROLE = {
48589
- ${lines.join("\n")}
48590
- } as const;`;
48591
- }
48592
- function generatePackageAppFields(binding) {
48593
- const { entities, roles } = parseBinding(binding);
48594
- return `${HEADER2}
48595
- ${emitFieldMap2(entities)}
48596
-
48597
- ${emitOptionMap2(entities)}
48598
-
48599
- ${emitRoleMap(roles)}
48600
-
48601
- /** Field-id alias map: \`F[<ENTITY>][<field>]\` is this installation's \`fld_\u2026\` id. */
48602
- export type AppFields = typeof F;
48603
- /** Select-option alias map: \`OPT[<ENTITY>][<field>][<option>]\` is this installation's \`opt_\u2026\` id. */
48604
- export type AppOptions = typeof OPT;
48605
- /** Role alias map: \`ROLE[<role>]\` is this installation's \`grp_\u2026\` id. */
48606
- export type AppRoles = typeof ROLE;
48607
- `;
48608
- }
48609
-
48610
48364
  // src/app_workflow_check.ts
48611
48365
  import fs7 from "node:fs";
48612
48366
  import path9 from "node:path";
@@ -49381,10 +49135,10 @@ function mergeDefs(...defs) {
49381
49135
  function cloneDef(schema) {
49382
49136
  return mergeDefs(schema._zod.def);
49383
49137
  }
49384
- function getElementAtPath(obj, path13) {
49385
- if (!path13)
49138
+ function getElementAtPath(obj, path14) {
49139
+ if (!path14)
49386
49140
  return obj;
49387
- return path13.reduce((acc, key) => acc?.[key], obj);
49141
+ return path14.reduce((acc, key) => acc?.[key], obj);
49388
49142
  }
49389
49143
  function promiseAllObject(promisesObj) {
49390
49144
  const keys3 = Object.keys(promisesObj);
@@ -49793,11 +49547,11 @@ function explicitlyAborted(x2, startIndex = 0) {
49793
49547
  }
49794
49548
  return false;
49795
49549
  }
49796
- function prefixIssues(path13, issues) {
49550
+ function prefixIssues(path14, issues) {
49797
49551
  return issues.map((iss) => {
49798
49552
  var _a4;
49799
49553
  (_a4 = iss).path ?? (_a4.path = []);
49800
- iss.path.unshift(path13);
49554
+ iss.path.unshift(path14);
49801
49555
  return iss;
49802
49556
  });
49803
49557
  }
@@ -49944,16 +49698,16 @@ function flattenError(error52, mapper = (issue2) => issue2.message) {
49944
49698
  }
49945
49699
  function formatError(error52, mapper = (issue2) => issue2.message) {
49946
49700
  const fieldErrors = { _errors: [] };
49947
- const processError = (error53, path13 = []) => {
49701
+ const processError = (error53, path14 = []) => {
49948
49702
  for (const issue2 of error53.issues) {
49949
49703
  if (issue2.code === "invalid_union" && issue2.errors.length) {
49950
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
49704
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
49951
49705
  } else if (issue2.code === "invalid_key") {
49952
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
49706
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
49953
49707
  } else if (issue2.code === "invalid_element") {
49954
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
49708
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
49955
49709
  } else {
49956
- const fullpath = [...path13, ...issue2.path];
49710
+ const fullpath = [...path14, ...issue2.path];
49957
49711
  if (fullpath.length === 0) {
49958
49712
  fieldErrors._errors.push(mapper(issue2));
49959
49713
  } else {
@@ -49980,17 +49734,17 @@ function formatError(error52, mapper = (issue2) => issue2.message) {
49980
49734
  }
49981
49735
  function treeifyError(error52, mapper = (issue2) => issue2.message) {
49982
49736
  const result = { errors: [] };
49983
- const processError = (error53, path13 = []) => {
49737
+ const processError = (error53, path14 = []) => {
49984
49738
  var _a4, _b2;
49985
49739
  for (const issue2 of error53.issues) {
49986
49740
  if (issue2.code === "invalid_union" && issue2.errors.length) {
49987
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
49741
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
49988
49742
  } else if (issue2.code === "invalid_key") {
49989
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
49743
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
49990
49744
  } else if (issue2.code === "invalid_element") {
49991
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
49745
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
49992
49746
  } else {
49993
- const fullpath = [...path13, ...issue2.path];
49747
+ const fullpath = [...path14, ...issue2.path];
49994
49748
  if (fullpath.length === 0) {
49995
49749
  result.errors.push(mapper(issue2));
49996
49750
  continue;
@@ -50022,8 +49776,8 @@ function treeifyError(error52, mapper = (issue2) => issue2.message) {
50022
49776
  }
50023
49777
  function toDotPath(_path) {
50024
49778
  const segs = [];
50025
- const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
50026
- for (const seg of path13) {
49779
+ const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
49780
+ for (const seg of path14) {
50027
49781
  if (typeof seg === "number")
50028
49782
  segs.push(`[${seg}]`);
50029
49783
  else if (typeof seg === "symbol")
@@ -62715,13 +62469,13 @@ function resolveRef(ref2, ctx) {
62715
62469
  if (!ref2.startsWith("#")) {
62716
62470
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
62717
62471
  }
62718
- const path13 = ref2.slice(1).split("/").filter(Boolean);
62719
- if (path13.length === 0) {
62472
+ const path14 = ref2.slice(1).split("/").filter(Boolean);
62473
+ if (path14.length === 0) {
62720
62474
  return ctx.rootSchema;
62721
62475
  }
62722
62476
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
62723
- if (path13[0] === defsKey) {
62724
- const key = path13[1];
62477
+ if (path14[0] === defsKey) {
62478
+ const key = path14[1];
62725
62479
  if (!key || !ctx.defs[key]) {
62726
62480
  throw new Error(`Reference not found: ${ref2}`);
62727
62481
  }
@@ -66073,15 +65827,21 @@ var appSchema = zod_default.object({
66073
65827
  "Alias \u2192 agent declaration map. Each alias binds a streaming tool-loop agent the app runs via `useAgentRun(alias)` (an SSE stream), with declared tools, model, and typed inputs/outputs. Synced from the app's `lotics.agents` manifest on every deploy. The agent runs under the app's IAM principal; runs persist a flat history per session."
66074
65828
  ),
66075
65829
  theme: appThemeSchema.nullable().optional().describe("Theme settings for the app"),
66076
- // App-package installation linkage (see docs/packages.md). Null on a
66077
- // bespoke (non-package) app or after eject — such apps behave exactly as before
66078
- // these columns existed. Declared inline (not imported from packages.ts) to
66079
- // avoid a circular import; the shapes mirror Binding / AppInstallationConfig.
66080
- package_id: zod_default.string().nullable().optional().describe("App-package registry id this app was installed from; null for a bespoke app or after eject."),
66081
- package_version: zod_default.number().int().nullable().optional().describe("Installed package version (the upgrade pin); null for a bespoke app or after eject."),
66082
- binding: zod_default.record(zod_default.string(), zod_default.record(zod_default.string(), zod_default.string())).nullable().optional().describe("App-package install join: per-namespace (entities/fields/options/templates/roles/workflows/knowledge) alias \u2192 concrete-id maps. Null for a bespoke app."),
66083
- config: zod_default.record(zod_default.string(), zod_default.union([zod_default.string(), zod_default.number(), zod_default.boolean()])).nullable().optional().describe("Installation-level customization config values (the customization-ladder first rung). Null for a bespoke app."),
66084
- ejected_at: zod_default.string().nullable().optional().describe("When the app was ejected from its package (severing upgrades); null if never ejected."),
65830
+ /**
65831
+ * The starter this app is the ORIGIN of, when it is one — list enrichment,
65832
+ * read from the registry rather than stored on the app.
65833
+ *
65834
+ * This is provenance in the only direction that exists under one-way copies:
65835
+ * an app can have PUBLISHED a starter, but an app that was COPIED FROM one
65836
+ * records nothing, because it owns everything it received outright. Null for
65837
+ * every app that has published nothing.
65838
+ */
65839
+ starter_origin: zod_default.object({
65840
+ starter_id: zod_default.string(),
65841
+ /** The highest version published from this app. */
65842
+ version: zod_default.number().int(),
65843
+ is_official: zod_default.boolean()
65844
+ }).nullable().optional(),
66085
65845
  created_at: zod_default.string().describe("Timestamp when app was created"),
66086
65846
  updated_at: zod_default.string().describe("Timestamp of last update")
66087
65847
  });
@@ -67431,9 +67191,9 @@ __export(expression_object_exports, {
67431
67191
  pick: () => pick3,
67432
67192
  values: () => values2
67433
67193
  });
67434
- function getNestedValue(obj, path13) {
67194
+ function getNestedValue(obj, path14) {
67435
67195
  if (obj == null) return void 0;
67436
- const parts = path13.split(".");
67196
+ const parts = path14.split(".");
67437
67197
  let value2 = obj;
67438
67198
  for (const part of parts) {
67439
67199
  if (value2 == null) return void 0;
@@ -67472,11 +67232,11 @@ function entries(obj) {
67472
67232
  }
67473
67233
  return Object.entries(obj);
67474
67234
  }
67475
- function get(obj, path13, defaultValue) {
67476
- if (typeof path13 !== "string") {
67235
+ function get(obj, path14, defaultValue) {
67236
+ if (typeof path14 !== "string") {
67477
67237
  throw new Error("get: path must be a string");
67478
67238
  }
67479
- const value2 = getNestedValue(obj, path13);
67239
+ const value2 = getNestedValue(obj, path14);
67480
67240
  return value2 !== void 0 ? value2 : defaultValue;
67481
67241
  }
67482
67242
  function pick3(obj, fields) {
@@ -69359,17 +69119,17 @@ function readFromChanges(chain2) {
69359
69119
  if (first3.kind === "bracket-number" || first3.kind === "bracket-expr") {
69360
69120
  fail(first3.node, "changes is keyed by field name, not numeric index.");
69361
69121
  }
69362
- const path13 = [{ at: "key", key: first3.key }];
69122
+ const path14 = [{ at: "key", key: first3.key }];
69363
69123
  for (const seg of segments.slice(1)) {
69364
69124
  if (seg.kind === "bracket-number") {
69365
- path13.push({ at: "index", index: seg.index });
69125
+ path14.push({ at: "index", index: seg.index });
69366
69126
  } else if (seg.kind === "bracket-expr") {
69367
- path13.push({ at: "index", index: seg.expr });
69127
+ path14.push({ at: "index", index: seg.expr });
69368
69128
  } else {
69369
- path13.push({ at: "key", key: seg.key });
69129
+ path14.push({ at: "key", key: seg.key });
69370
69130
  }
69371
69131
  }
69372
- return { kind: "read", source: { from: "trigger_changes" }, path: path13 };
69132
+ return { kind: "read", source: { from: "trigger_changes" }, path: path14 };
69373
69133
  });
69374
69134
  }
69375
69135
  var TRIGGER_RECORD_VIEWS = /* @__PURE__ */ new Map([
@@ -69387,17 +69147,17 @@ function readFromTrigger(chain2) {
69387
69147
  return view === "trigger_changes" ? readFromChanges(lowered) : readFromRecord(view, lowered);
69388
69148
  }
69389
69149
  return wrapOptionalGuards(chain2, (segments) => {
69390
- const path13 = [];
69150
+ const path14 = [];
69391
69151
  for (const seg of segments) {
69392
69152
  if (seg.kind === "bracket-number") {
69393
- path13.push({ at: "index", index: seg.index });
69153
+ path14.push({ at: "index", index: seg.index });
69394
69154
  } else if (seg.kind === "bracket-expr") {
69395
- path13.push({ at: "index", index: seg.expr });
69155
+ path14.push({ at: "index", index: seg.expr });
69396
69156
  } else {
69397
- path13.push({ at: "key", key: seg.key });
69157
+ path14.push({ at: "key", key: seg.key });
69398
69158
  }
69399
69159
  }
69400
- return { kind: "read", source: { from: "trigger" }, path: path13 };
69160
+ return { kind: "read", source: { from: "trigger" }, path: path14 };
69401
69161
  });
69402
69162
  }
69403
69163
  function readFromRuntime(chain2) {
@@ -69419,17 +69179,17 @@ function readFromRuntime(chain2) {
69419
69179
  const parked = PARKED_RUNTIME_KEYS.get(key);
69420
69180
  if (parked) fail(first3.node, parked, parkedRuntimeKeyConstruct(key));
69421
69181
  const source = { from: "runtime", key };
69422
- const path13 = [];
69182
+ const path14 = [];
69423
69183
  for (const seg of segments.slice(1)) {
69424
69184
  if (seg.kind === "bracket-number") {
69425
- path13.push({ at: "index", index: seg.index });
69185
+ path14.push({ at: "index", index: seg.index });
69426
69186
  } else if (seg.kind === "bracket-expr") {
69427
- path13.push({ at: "index", index: seg.expr });
69187
+ path14.push({ at: "index", index: seg.expr });
69428
69188
  } else {
69429
- path13.push({ at: "key", key: seg.key });
69189
+ path14.push({ at: "key", key: seg.key });
69430
69190
  }
69431
69191
  }
69432
- return { kind: "read", source, path: path13 };
69192
+ return { kind: "read", source, path: path14 };
69433
69193
  });
69434
69194
  }
69435
69195
  function readFromForeachItem(chain2) {
@@ -69465,17 +69225,17 @@ function readFromLexical(name2, chain2) {
69465
69225
  }
69466
69226
  function readFromStepOutput(stepId, chain2) {
69467
69227
  return wrapOptionalGuards(chain2, (segments) => {
69468
- const path13 = [];
69228
+ const path14 = [];
69469
69229
  for (const seg of segments) {
69470
69230
  if (seg.kind === "bracket-number") {
69471
- path13.push({ at: "index", index: seg.index });
69231
+ path14.push({ at: "index", index: seg.index });
69472
69232
  } else if (seg.kind === "bracket-expr") {
69473
- path13.push({ at: "index", index: seg.expr });
69233
+ path14.push({ at: "index", index: seg.expr });
69474
69234
  } else {
69475
- path13.push({ at: "key", key: seg.key });
69235
+ path14.push({ at: "key", key: seg.key });
69476
69236
  }
69477
69237
  }
69478
- return { kind: "read", source: { from: "step_output", step_id: stepId }, path: path13 };
69238
+ return { kind: "read", source: { from: "step_output", step_id: stepId }, path: path14 };
69479
69239
  });
69480
69240
  }
69481
69241
  function classifyRecordPath(segs) {
@@ -71226,1081 +70986,6 @@ function checkWorkflowBodies(tsApi, aliases) {
71226
70986
  }));
71227
70987
  }
71228
70988
 
71229
- // ../shared/src/schemas/table_fields.ts
71230
- var tableFieldTypeNameSchema = zod_default.enum([
71231
- "text",
71232
- "number",
71233
- "date",
71234
- "boolean",
71235
- "select",
71236
- "select_member",
71237
- "select_record_link",
71238
- "files",
71239
- "formula",
71240
- "rollup",
71241
- "lookup",
71242
- "button",
71243
- "autonumber"
71244
- ]);
71245
- var tableFieldBaseSchema = zod_default.object({
71246
- key: zod_default.string().describe("Unique field key"),
71247
- name: zod_default.string().describe("Display name"),
71248
- description: zod_default.string().describe("Field description"),
71249
- confirm_before_update: zod_default.boolean().optional().describe("Show confirmation before AI updates")
71250
- });
71251
- var numberFormatSchema = zod_default.enum(["number", "currency", "percentage"]);
71252
- var textFormatSchema = zod_default.enum(["text", "link", "markdown"]);
71253
- var dateFormatSchema = zod_default.enum(["date", "datetime", "date_range", "datetime_range"]);
71254
- var DEFAULT_VALUE_DESC = "Value pre-filled into a new record when none is supplied for this field. Applied on create only \u2014 existing records are never backfilled. null clears it.";
71255
- var textDefaultValueSchema = zod_default.string().nullish().describe(DEFAULT_VALUE_DESC);
71256
- var numberDefaultValueSchema = zod_default.number().nullish().describe(DEFAULT_VALUE_DESC);
71257
- var booleanDefaultValueSchema = zod_default.boolean().nullish().describe(DEFAULT_VALUE_DESC);
71258
- var dateDefaultValueSchema = zod_default.string().nullish().describe(`${DEFAULT_VALUE_DESC} A date string in the field's format.`);
71259
- var selectDefaultValueSchema = zod_default.array(zod_default.string()).nullish().describe(`${DEFAULT_VALUE_DESC} Option key(s) \u2014 one for single-select.`);
71260
- var memberDefaultValueSchema = zod_default.array(zod_default.string()).nullish().describe(`${DEFAULT_VALUE_DESC} Member ID(s) \u2014 one for single-select.`);
71261
- var tableNumberFieldSchema = tableFieldBaseSchema.extend({
71262
- type: zod_default.literal("number"),
71263
- format: numberFormatSchema,
71264
- currency: zod_default.string().optional().describe("ISO 4217 code"),
71265
- default_value: numberDefaultValueSchema
71266
- });
71267
- var tableTextFieldSchema = tableFieldBaseSchema.extend({
71268
- type: zod_default.literal("text"),
71269
- unique: zod_default.boolean().optional().describe("Unique values required"),
71270
- // it's `optional` only for backward compatibility
71271
- format: textFormatSchema.optional(),
71272
- default_value: textDefaultValueSchema
71273
- });
71274
- var tableDateFieldSchema = tableFieldBaseSchema.extend({
71275
- type: zod_default.literal("date"),
71276
- format: dateFormatSchema.optional(),
71277
- timezone: zod_default.string().optional().describe("IANA timezone"),
71278
- derive_from: zod_default.enum(["created_at", "updated_at"]).optional().describe(
71279
- "Auto-populate from the row's system timestamp. `created_at` stamps once at insert time; `updated_at` re-stamps on every record edit. Derived fields are read-only \u2014 user-supplied values are silently ignored at write time, matching the formula/rollup/lookup pattern. Replaces the per-table after_create workflow pattern."
71280
- ),
71281
- // A derived date is read-only, so derive_from and default_value are mutually
71282
- // exclusive — enforced in validateFieldDefaultValue.
71283
- default_value: dateDefaultValueSchema
71284
- });
71285
- var tableBooleanFieldSchema = tableFieldBaseSchema.extend({
71286
- type: zod_default.literal("boolean"),
71287
- default_value: booleanDefaultValueSchema
71288
- });
71289
- var tableSelectFieldOptionSchema = zod_default.object({
71290
- key: zod_default.string(),
71291
- name: zod_default.string(),
71292
- color: optionColorSchema
71293
- });
71294
- var tableSelectFieldSchema = tableFieldBaseSchema.extend({
71295
- type: zod_default.literal("select"),
71296
- options: zod_default.array(tableSelectFieldOptionSchema),
71297
- multi: zod_default.boolean().optional().describe("Allow multiple selections"),
71298
- default_value: selectDefaultValueSchema
71299
- });
71300
- var tableSelectMemberFieldSchema = tableFieldBaseSchema.extend({
71301
- type: zod_default.literal("select_member"),
71302
- multi: zod_default.boolean().optional().describe("Allow multiple selections"),
71303
- default_value: memberDefaultValueSchema
71304
- });
71305
- var recordLinkItemSchema = zod_default.object({
71306
- id: zod_default.string(),
71307
- display: zod_default.string()
71308
- });
71309
- var selectRecordLinkValueSchema = zod_default.array(recordLinkItemSchema);
71310
- var tableSelectRecordLinkFieldInputSchema = tableFieldBaseSchema.extend({
71311
- type: zod_default.literal("select_record_link"),
71312
- table_id: zod_default.string().describe("Linked table ID"),
71313
- display_field_keys: zod_default.array(zod_default.string()).optional().describe(
71314
- "Field keys of the linked table shown as the link's display text and as the columns in the record picker. If omitted, auto-selects the first text field."
71315
- ),
71316
- display_field_widths: zod_default.record(zod_default.string(), zod_default.number().int().positive()).optional().describe(
71317
- "Per-column widths in pixels for the record picker, keyed by linked-table field key. Missing keys fall back to the default column width."
71318
- ),
71319
- sync_both_ways: zod_default.boolean().optional().describe("Enable bidirectional link sync. If the target table has exactly one existing unpaired link field pointing back, pairs with it instead of creating a new field."),
71320
- paired_field_display_field_keys: zod_default.array(zod_default.string()).optional().describe("Display fields for paired link"),
71321
- paired_field_name: zod_default.string().optional().describe(
71322
- "Name for the auto-created paired field on the target table when sync_both_ways=true. If omitted, falls back to the source table's name (auto-uniquified with a numeric suffix on collision). Rejected as a conflict if a field with this name already exists on the target."
71323
- ),
71324
- cardinality: zod_default.enum(["one", "many"]).optional().describe(
71325
- "How many linked records this field can hold. Default 'many' (multi-select). 'one' = single-select; this side holds exactly one link to the partner. Requires sync_both_ways/paired_field_key. Setting 'one' on both paired sides is rejected."
71326
- )
71327
- });
71328
- var tableSelectRecordLinkFieldSchema = tableFieldBaseSchema.extend({
71329
- type: zod_default.literal("select_record_link").describe("Field type for linking to records in another table"),
71330
- table_id: zod_default.string().describe("ID of the target table that records can be linked to"),
71331
- display_field_keys: zod_default.array(zod_default.string()).optional().default([]).describe(
71332
- "Field keys of the linked table shown as the link's display text and as the columns in the record picker. If empty, the picker shows all fields."
71333
- ),
71334
- display_field_widths: zod_default.record(zod_default.string(), zod_default.number().int().positive()).optional().describe(
71335
- "Per-column widths in pixels for the record picker, keyed by linked-table field key. Missing keys fall back to the default column width."
71336
- ),
71337
- paired_field_key: zod_default.string().optional().describe(
71338
- "Key of the paired link field in the linked table. If set to a string, this indicates a bidirectional link where both tables can reference each other and data synchronizes in both directions. Both fields have paired_field_key pointing to each other. If set to null, explicitly disconnects the bidirectional link (clears paired_field_key on both sides). If undefined, no change is made to the existing paired_field_key."
71339
- ),
71340
- cardinality: zod_default.enum(["one", "many"]).optional().describe(
71341
- "How many linked records this field can hold. Default 'many' (multi-select). 'one' = single-select; this side holds exactly one link to the partner. Requires paired_field_key. Two paired sides cannot both be 'one'."
71342
- )
71343
- });
71344
- var tableRollupFieldSchema = tableFieldBaseSchema.extend({
71345
- type: zod_default.literal("rollup").describe(
71346
- "Field type for aggregating values from linked records (sum, avg, filled, earliest, etc.)"
71347
- ),
71348
- source_field_key: zod_default.string().describe("The field key of the select_record_link field to rollup from"),
71349
- aggregate_option: aggregateOptionSchema.describe(
71350
- "The field aggregation function to apply (e.g., sum, avg, filled, earliest)"
71351
- ),
71352
- filter: tableRecordFiltersGroupNodeSchema.optional().describe(
71353
- "Optional filter to apply to linked records before aggregation. Only records matching the filter conditions will be included in the rollup calculation."
71354
- ),
71355
- aggregate_field_type: tableFieldTypeNameSchema.optional().describe(
71356
- "What this rollup's CELL holds \u2014 'date' for earliest/latest, 'number' for every other operation (counts, sums, percentages). Derived from the operation, not from the aggregated field: a 'filled' count over a files column is a number. Server-derived at write time; ignored on input."
71357
- ),
71358
- aggregate_field_format: zod_default.string().optional().describe(
71359
- "The format of this rollup's own value. Operations that preserve the aggregated value's unit (sum/avg/median/min/max/range/earliest/latest) inherit the target field's format; counting operations are 'number', percentages 'percentage'. Server-derived at write time; ignored on input."
71360
- ),
71361
- aggregate_field_currency: zod_default.string().optional().describe(
71362
- "The currency code of this rollup's own value (e.g. 'USD', 'VND'), inherited from the aggregated field only when the operation preserves its unit \u2014 a COUNT of a currency column carries no currency. Server-derived at write time; ignored on input."
71363
- )
71364
- });
71365
- var lookupOrderBySchema = zod_default.object({
71366
- field_key: zod_default.string(),
71367
- direction: zod_default.enum(["asc", "desc"])
71368
- });
71369
- var tableLookupFieldSchema = tableFieldBaseSchema.extend({
71370
- type: zod_default.literal("lookup").describe("Field type for displaying values from fields in linked records"),
71371
- source_field_key: zod_default.string().describe("The field key of the select_record_link field to lookup from"),
71372
- lookup_field_key: zod_default.string().describe("The field key from the linked records to display"),
71373
- lookup_field_type: tableFieldTypeNameSchema.optional().describe(
71374
- "The type of the target lookup field (e.g. 'text', 'number', 'date'). Resolved from the linked table's field definition at read time."
71375
- ),
71376
- lookup_field_format: zod_default.string().optional().describe(
71377
- "The format of the target lookup field (e.g. 'currency', 'percentage', 'datetime'). Resolved from the linked table's field definition at read time."
71378
- ),
71379
- lookup_field_currency: zod_default.string().optional().describe(
71380
- "The currency code of the target lookup field (e.g. 'USD', 'VND'). Resolved from the linked table's field definition at read time."
71381
- ),
71382
- lookup_field_options: zod_default.array(zod_default.object({ key: zod_default.string(), name: zod_default.string(), color: zod_default.string().optional() })).optional().describe(
71383
- "Options for select-type lookup fields. Synced from the source select field's options."
71384
- ),
71385
- order_by: lookupOrderBySchema.optional().describe(
71386
- "When set, sort the linked records by this field on the linked table and return ONLY the picked field from the single extreme record (desc=latest, asc=earliest), as a one-element array. Omit to return every linked record's value as an array. field_key must be a field on the linked table."
71387
- )
71388
- });
71389
- var tableFilesFieldSchema = tableFieldBaseSchema.extend({
71390
- type: zod_default.literal("files").describe("Field type for file attachments (images, PDFs, documents)")
71391
- });
71392
- var formulaInputSchema = zod_default.object({
71393
- expression: zod_default.string().describe(
71394
- "JavaScript expression. Uses {Field Name} for field references."
71395
- ),
71396
- format: zod_default.enum(["number", "currency", "percentage", "link"]).optional().describe(
71397
- "Display format. 'number' / 'currency' / 'percentage' for numeric results; 'link' for text-output formulas that return a URL \u2014 renders the result as a clickable link."
71398
- ),
71399
- currency: zod_default.string().optional().describe("ISO 4217 currency code, e.g. USD, VND, EUR")
71400
- });
71401
- var formulaSchema = formulaInputSchema.extend({
71402
- output_type: zod_default.enum(["number", "text", "date", "datetime", "boolean"]).optional().describe("Output type of the formula. Inferred by the backend from the expression \u2014 read-only on input. `datetime` when the result carries a time of day (references a datetime field or a time-bearing helper)."),
71403
- volatile: zod_default.boolean().optional().describe("Whether the formula's result depends on `now()` or other non-deterministic helpers. Inferred by the backend \u2014 read-only on input.")
71404
- });
71405
- var tableFormulaFieldSchema = tableFieldBaseSchema.extend({
71406
- type: zod_default.literal("formula").describe("Field type for calculated values based on expressions"),
71407
- formula: formulaSchema.describe("Formula configuration and expression")
71408
- });
71409
- var workflowMetadataSchema = zod_default.object({
71410
- table_ids: zod_default.array(zod_default.string()).describe("IDs of the tables this workflow affects"),
71411
- staged_for_app_id: zod_default.string().optional().describe(
71412
- "Present while the row is a draft-staged fork for this app; cleared when the app publishes the binding. Marked rows left unbound are archived at publish/discard."
71413
- )
71414
- });
71415
- var workflowSchema = zod_default.object({
71416
- id: zod_default.string().describe("Unique identifier for the workflow"),
71417
- name: zod_default.string().describe("Display name of the workflow"),
71418
- description: zod_default.string().describe("Human-readable description of what this workflow does"),
71419
- steps: zod_default.unknown().describe(
71420
- "AST-valued step tree (tool calls, conditionals, loops)."
71421
- ),
71422
- metadata: workflowMetadataSchema.nullable().optional().describe("Metadata for the workflow"),
71423
- current_version: zod_default.number().int().describe("Current version number"),
71424
- enabled: zod_default.boolean().describe("Whether this workflow is active"),
71425
- workspace_id: zod_default.string().describe("ID of the workspace this workflow belongs to"),
71426
- created_at: zod_default.string().describe("Timestamp when workflow was created"),
71427
- updated_at: zod_default.string().describe("Timestamp of last update")
71428
- });
71429
- var tableButtonFieldSchema = tableFieldBaseSchema.extend({
71430
- type: zod_default.literal("button").describe("Field type for action buttons"),
71431
- text: zod_default.string().describe("Button label text displayed to users"),
71432
- workflow_id: zod_default.string().nullable().optional().describe(
71433
- "ID of the workflow the button presses trigger. Null means no action configured \u2014 pressing the button is a no-op. Button authoring is retired: existing bindings keep running, but nothing sets a new one."
71434
- )
71435
- });
71436
- var tableAutonumberFieldSchema = tableFieldBaseSchema.extend({
71437
- type: zod_default.literal("autonumber"),
71438
- prefix: zod_default.string().optional().describe(
71439
- "Literal prefix prepended to every display value (e.g. 'KH-' \u2192 'KH-001'). Ignored when `template` is set."
71440
- ),
71441
- padding: zod_default.number().int().min(1).max(20).optional().describe(
71442
- "Zero-pad the integer to this width. Default 1 (no padding). 3 \u2192 '001', '012', '123', '1234' (overflow uses the actual width). Ignored when `template` is set."
71443
- ),
71444
- template: zod_default.string().optional().describe(
71445
- "Format template with placeholder tokens evaluated at insert time. Tokens: {N} (raw integer), {N:W} (zero-padded to width W, e.g. {N:3} \u2192 001), {YEAR} (4-digit year), {YEAR:2} (2-digit year), {MONTH} (2-digit month), {DAY} (2-digit day). Date tokens use the workspace timezone. Example: 'HM-{YEAR}-{N:3}' yields 'HM-2026-001'. Stored as the composed string; subsequent template edits do NOT re-format existing rows (date tokens would lose the original creation date)."
71446
- )
71447
- });
71448
- var tableFieldSchema = zod_default.discriminatedUnion("type", [
71449
- tableNumberFieldSchema,
71450
- tableTextFieldSchema,
71451
- tableDateFieldSchema,
71452
- tableBooleanFieldSchema,
71453
- tableSelectFieldSchema,
71454
- tableSelectMemberFieldSchema,
71455
- tableSelectRecordLinkFieldSchema,
71456
- tableRollupFieldSchema,
71457
- tableLookupFieldSchema,
71458
- tableFilesFieldSchema,
71459
- tableFormulaFieldSchema,
71460
- tableButtonFieldSchema,
71461
- tableAutonumberFieldSchema
71462
- ]);
71463
- var tableFieldInputSchema = zod_default.discriminatedUnion("type", [
71464
- tableNumberFieldSchema,
71465
- tableTextFieldSchema,
71466
- tableDateFieldSchema,
71467
- tableBooleanFieldSchema,
71468
- tableSelectFieldSchema,
71469
- tableSelectMemberFieldSchema,
71470
- tableSelectRecordLinkFieldInputSchema,
71471
- tableRollupFieldSchema,
71472
- tableLookupFieldSchema,
71473
- tableFilesFieldSchema,
71474
- tableFormulaFieldSchema,
71475
- tableButtonFieldSchema,
71476
- tableAutonumberFieldSchema
71477
- ]);
71478
- var tableFieldsSchema = zod_default.array(tableFieldSchema);
71479
- var tableFieldCreateBaseSchema = zod_default.object({
71480
- name: zod_default.string().describe("Display name"),
71481
- description: zod_default.string().describe("Field description"),
71482
- confirm_before_update: zod_default.boolean().optional().describe("Show confirmation before AI updates")
71483
- });
71484
- var tableSelectFieldOptionCreateSchema = zod_default.object({
71485
- name: zod_default.string(),
71486
- color: optionColorSchema
71487
- });
71488
- var tableFieldTypeConfigSchema = zod_default.discriminatedUnion("type", [
71489
- zod_default.object({
71490
- type: zod_default.literal("number"),
71491
- format: numberFormatSchema.default("number"),
71492
- currency: zod_default.string().optional().describe("ISO 4217 code"),
71493
- default_value: numberDefaultValueSchema
71494
- }),
71495
- zod_default.object({
71496
- type: zod_default.literal("text"),
71497
- unique: zod_default.boolean().optional().describe("Unique values required"),
71498
- format: textFormatSchema.default("text"),
71499
- default_value: textDefaultValueSchema
71500
- }),
71501
- zod_default.object({
71502
- type: zod_default.literal("date"),
71503
- format: dateFormatSchema.optional(),
71504
- timezone: zod_default.string().optional().describe("IANA timezone"),
71505
- derive_from: zod_default.enum(["created_at", "updated_at"]).nullable().optional().describe("Auto-populate from row system timestamp; field becomes read-only. Only valid for date/datetime formats. Pass null to clear and revert to a manual date field."),
71506
- default_value: dateDefaultValueSchema
71507
- }),
71508
- zod_default.object({
71509
- type: zod_default.literal("boolean"),
71510
- default_value: booleanDefaultValueSchema
71511
- }),
71512
- zod_default.object({
71513
- type: zod_default.literal("select"),
71514
- options: zod_default.array(tableSelectFieldOptionCreateSchema),
71515
- multi: zod_default.boolean().optional().describe("Allow multiple selections"),
71516
- default_value: selectDefaultValueSchema
71517
- }),
71518
- zod_default.object({
71519
- type: zod_default.literal("select_member"),
71520
- multi: zod_default.boolean().optional().describe("Allow multiple selections"),
71521
- default_value: memberDefaultValueSchema
71522
- }),
71523
- zod_default.object({
71524
- type: zod_default.literal("select_record_link"),
71525
- table_id: zod_default.string().describe("Linked table ID"),
71526
- display_field_keys: zod_default.array(zod_default.string()).optional().describe(
71527
- "Field keys of the linked table shown as the link's display text and as the columns in the record picker. If omitted, auto-selects the first text field."
71528
- ),
71529
- display_field_widths: zod_default.record(zod_default.string(), zod_default.number().int().positive()).optional().describe(
71530
- "Per-column widths in pixels for the record picker, keyed by linked-table field key. Missing keys fall back to the default column width."
71531
- ),
71532
- sync_both_ways: zod_default.boolean().optional().describe("Enable bidirectional link sync. If the target table has exactly one existing unpaired link field pointing back, pairs with it instead of creating a new field."),
71533
- paired_field_display_field_keys: zod_default.array(zod_default.string()).optional().describe("Paired field display"),
71534
- paired_field_name: zod_default.string().optional().describe(
71535
- "Name for the auto-created paired field on the target table when sync_both_ways=true. Omit to default to the source table's name (auto-uniquified on collision). If supplied and a field with the same name already exists on the target, the create is rejected."
71536
- ),
71537
- cardinality: zod_default.enum(["one", "many"]).optional().describe(
71538
- "How many linked records this field can hold. Default 'many' (multi-select). 'one' = single-select; this side holds exactly one link to the partner. Requires sync_both_ways. Two paired sides cannot both be 'one'."
71539
- )
71540
- }),
71541
- zod_default.object({
71542
- type: zod_default.literal("rollup"),
71543
- source_field_key: zod_default.string().describe("Source link field key"),
71544
- aggregate_option: aggregateOptionSchema,
71545
- filter: tableRecordFiltersGroupNodeSchema.optional().describe("Filter linked records")
71546
- }),
71547
- zod_default.object({
71548
- type: zod_default.literal("lookup"),
71549
- source_field_key: zod_default.string().describe("Source link field key"),
71550
- lookup_field_key: zod_default.string().describe("Field to display"),
71551
- order_by: lookupOrderBySchema.optional().describe("Ordered lookup: pick only the extreme linked record's field (desc=latest, asc=earliest)")
71552
- }),
71553
- zod_default.object({
71554
- type: zod_default.literal("files")
71555
- }),
71556
- zod_default.object({
71557
- type: zod_default.literal("formula"),
71558
- formula: formulaInputSchema
71559
- }),
71560
- // `button` is deliberately absent: button fields are legacy — this union
71561
- // shapes CREATE input only, and new buttons can no longer be created
71562
- // (see LEGACY_FIELD_TYPES). Stored button fields still parse via the
71563
- // stored-field union above, and update paths keep accepting text edits.
71564
- zod_default.object({
71565
- type: zod_default.literal("autonumber"),
71566
- prefix: zod_default.string().optional().describe("Literal prefix prepended to display (ignored when template is set)"),
71567
- padding: zod_default.number().int().min(1).max(20).optional().describe("Zero-pad the integer to this width (default 1) (ignored when template is set)"),
71568
- template: zod_default.string().optional().describe(
71569
- "Format template \u2014 tokens evaluate at insert time: {N}, {N:W} (padded), {YEAR}, {YEAR:2}, {MONTH}, {DAY}. Date tokens use workspace timezone. Example: 'HM-{YEAR}-{N:3}' \u2192 'HM-2026-001'."
71570
- )
71571
- })
71572
- ]);
71573
- var tableFieldCreateInputSchema = zod_default.intersection(
71574
- tableFieldCreateBaseSchema,
71575
- tableFieldTypeConfigSchema
71576
- );
71577
- var fieldVisibilitySchema = zod_default.enum(["visible", "hidden"]).describe(
71578
- "Field visibility state: 'visible' = shown to everyone, 'hidden' = not shown by default but members can toggle"
71579
- );
71580
-
71581
- // ../shared/src/schemas/field_config.ts
71582
- var fieldConfigEntrySchema = zod_default.object({
71583
- key: zod_default.string().min(1).describe("Field key"),
71584
- visibility: fieldVisibilitySchema,
71585
- width: zod_default.number().optional()
71586
- });
71587
-
71588
- // ../shared/src/schemas/iam.ts
71589
- var jsonSchemaSchema = zod_default.string();
71590
- var organizationSchema = zod_default.object({
71591
- id: zod_default.string().describe("Unique identifier for the organization"),
71592
- name: zod_default.string().describe("Display name of the organization"),
71593
- slug: zod_default.string().nullable().describe("Slug for the organization")
71594
- });
71595
- var memberSchema = zod_default.object({
71596
- member_id: zod_default.string().describe("Unique identifier for the member"),
71597
- organization_id: zod_default.string().describe("Organization ID the member belongs to"),
71598
- name: zod_default.string().describe("Display name of the member"),
71599
- email_address: zod_default.string().describe(
71600
- "What the member types to sign in: an email address for a self-managed member, an administrator-issued name (e.g. giamdoc.sunrise) for an admin-managed one. The latter is NOT an address and cannot receive mail \u2014 the field name predates the split."
71601
- ),
71602
- role: zod_default.enum(["owner", "admin", "member"]).describe("Organization role"),
71603
- image: zod_default.string().nullable().optional().describe("URL to the member's profile picture"),
71604
- account_type: zod_default.enum(["self_managed", "admin_managed"]).describe(
71605
- "How the account is credentialed. admin_managed means an admin chose the sign-in name and set the password; the account has NO email address at all, so nothing can be mailed to it until the member claims one they control."
71606
- ),
71607
- archived: zod_default.boolean().optional().describe(
71608
- "True when this person has been removed from the organization. The membership survives removal so records naming them keep resolving; it grants nothing. Optional because an older server omits it \u2014 absent means active."
71609
- ),
71610
- joined_at: zod_default.string().optional().describe(
71611
- "ISO timestamp of when this membership began. Optional because an older server omits it \u2014 absent means not told, never 'joined at the epoch'."
71612
- )
71613
- });
71614
- var pendingInvitationSchema = zod_default.object({
71615
- invitation_id: zod_default.string().describe("Unique identifier for the pending invitation"),
71616
- organization_id: zod_default.string().describe("Organization the invitee will join on accept"),
71617
- email: zod_default.string().describe("Email the invitation was sent to"),
71618
- name: zod_default.string().nullable().describe("Admin-supplied display name (carried onto member.name on accept; invitee can override at accept time)"),
71619
- role: zod_default.enum(["owner", "admin", "member"]).describe("Role the invitee will receive on accept"),
71620
- expires_at: zod_default.string().describe("ISO timestamp when the invitation expires")
71621
- });
71622
- var workspaceSchema = zod_default.object({
71623
- id: zod_default.string().describe("Unique identifier for the workspace"),
71624
- name: zod_default.string().describe("Display name of the workspace"),
71625
- default_currency: zod_default.string().describe("Default currency code for the workspace"),
71626
- timezone: zod_default.string().describe("IANA timezone name (e.g., 'America/New_York', 'Asia/Tokyo')"),
71627
- organization_id: zod_default.string().describe("Organization ID this workspace belongs to"),
71628
- created_at: zod_default.string().describe("Timestamp when workspace was created")
71629
- });
71630
- var memberGroupSchema = zod_default.object({
71631
- id: zod_default.string().describe("Unique identifier for the member group"),
71632
- name: zod_default.string().describe("Display name of the group"),
71633
- description: zod_default.string().optional().describe("Optional description of the group's purpose"),
71634
- member_ids: zod_default.array(zod_default.string()).describe("Array of member IDs in this group"),
71635
- invitation_ids: zod_default.array(zod_default.string()).describe("Array of pending invitation IDs pre-granted membership; migrated to member_ids on accept"),
71636
- organization_id: zod_default.string().describe("ID of the organization this group belongs to"),
71637
- created_at: zod_default.string().describe("Timestamp when group was created"),
71638
- created_by: zod_default.string().describe("Member ID of the user who created this group")
71639
- });
71640
- var principalGroupSchema = zod_default.object({
71641
- id: zod_default.string().describe("Unique identifier for the member group"),
71642
- name: zod_default.string().describe("Display name of the group"),
71643
- description: zod_default.string().optional().describe("Optional description of the group's purpose"),
71644
- member_count: zod_default.number().int().describe("Number of accepted members in the group"),
71645
- invitation_count: zod_default.number().int().describe("Number of pending invitations pre-granted membership")
71646
- });
71647
- var PUBLIC_PRINCIPAL_ID = "public";
71648
- var principalSchema = zod_default.discriminatedUnion("type", [
71649
- zod_default.object({
71650
- type: zod_default.literal("member").describe("Principal type: individual member"),
71651
- id: zod_default.string().describe("Member ID")
71652
- }),
71653
- zod_default.object({
71654
- type: zod_default.literal("member_group").describe("Principal type: group of members"),
71655
- id: zod_default.string().describe("Member group ID")
71656
- }),
71657
- zod_default.object({
71658
- type: zod_default.literal("organization").describe("Principal type: all members in organization"),
71659
- id: zod_default.string().describe("Organization ID")
71660
- }),
71661
- zod_default.object({
71662
- type: zod_default.literal("public").describe("Principal type: anyone, including unauthenticated visitors"),
71663
- id: zod_default.literal(PUBLIC_PRINCIPAL_ID).describe("Always the `public` sentinel \u2014 no entity")
71664
- }),
71665
- // Pending invitation as principal: lets admins pre-grant group membership and
71666
- // resource access before the invitee accepts. Never resolved as a Subject —
71667
- // a pending invitee cannot authenticate, so these bindings stay dormant until
71668
- // accept-time migration rewrites them to type:"member".
71669
- zod_default.object({
71670
- type: zod_default.literal("invitation").describe("Principal type: pending invitation (not yet accepted)"),
71671
- id: zod_default.string().describe("Invitation ID")
71672
- })
71673
- ]);
71674
- var subjectSchema = zod_default.discriminatedUnion("type", [
71675
- zod_default.object({
71676
- type: zod_default.literal("member").describe("Subject type: authenticated member"),
71677
- id: zod_default.string().describe("Member ID")
71678
- }),
71679
- zod_default.object({
71680
- type: zod_default.literal("public").describe("Subject type: unauthenticated visitor")
71681
- })
71682
- ]);
71683
- var resourceTypeSchema = zod_default.enum(["table", "table_view", "app", "automation", "skill", "document_template", "instruction", "knowledge_doc"]);
71684
- var accessPrincipalSchema = zod_default.discriminatedUnion("type", [
71685
- zod_default.object({
71686
- type: zod_default.literal("member").describe("Principal type: an individual member"),
71687
- id: zod_default.string().describe("Member ID")
71688
- }),
71689
- zod_default.object({
71690
- type: zod_default.literal("member_group").describe("Principal type: a member group"),
71691
- id: zod_default.string().describe("Group ID")
71692
- }),
71693
- zod_default.object({
71694
- type: zod_default.literal("organization").describe("Principal type: everyone in the organization"),
71695
- id: zod_default.string().describe("Organization ID")
71696
- })
71697
- ]);
71698
- var resourceAccessSchema = zod_default.object({
71699
- resource_id: zod_default.string().describe("ID of the resource these principals can reach"),
71700
- principals: zod_default.array(accessPrincipalSchema).describe("Members, groups and the organization that have been granted access")
71701
- });
71702
- var resourceRoleBindingSchema = zod_default.object({
71703
- id: zod_default.string().describe("Unique identifier for the role binding"),
71704
- principal: principalSchema.describe(
71705
- "Who this role binding applies to (member, group, or organization)"
71706
- ),
71707
- resource_type: resourceTypeSchema.describe("Type of resource being accessed"),
71708
- resource_id: zod_default.string().describe("ID of the specific resource"),
71709
- role: zod_default.string().describe("Role name (e.g., 'viewer', 'editor', 'manager', 'user')")
71710
- });
71711
-
71712
- // ../shared/src/schemas/table_records.ts
71713
- var tableWorkflowEventSchema = zod_default.enum([
71714
- "before_create",
71715
- "after_create",
71716
- "before_update",
71717
- "after_update",
71718
- "before_delete",
71719
- "after_delete"
71720
- ]);
71721
- var tableWorkflowSchema = zod_default.object({
71722
- id: zod_default.string().describe("Unique table-workflow binding ID (tbw_ prefix)"),
71723
- name: zod_default.string().describe("Human-readable name"),
71724
- description: zod_default.string().describe("Description of what this workflow does"),
71725
- enabled: zod_default.boolean().describe("Whether this workflow is active"),
71726
- event: tableWorkflowEventSchema.describe(
71727
- "Lifecycle event that fires this workflow. before_* runs synchronously and may reject the mutation; after_* runs after commit and does not block."
71728
- ),
71729
- workflow_id: zod_default.string().describe(
71730
- "ID of the workflow row that owns this binding's steps. The workflow's steps_v2 is the source of truth for the AST."
71731
- ),
71732
- // Recursive v2 expression AST. Lazy schema would crash the OpenAPI walker;
71733
- // runtime is `unknown` and the casted Zod type preserves the compile-time
71734
- // signature for callers. Write paths re-parse with the strict schema before
71735
- // storage.
71736
- if: zod_default.unknown().nullable().optional().describe(
71737
- "Optional pre-execution gate. Evaluated against the trigger context (record / prev_record / changes / runtime); the workflow fires only when truthy. Skip gating means the workflow always fires."
71738
- ),
71739
- created_at: zod_default.string().describe("When the binding was created"),
71740
- updated_at: zod_default.string().describe("When the binding was last modified"),
71741
- archived_at: zod_default.string().nullable().optional().describe(
71742
- "Set when the binding was removed (soft-delete). An archived binding never fires and is hidden from active listings, but is restorable; null/absent = active."
71743
- )
71744
- });
71745
- var tableWorkflowMessageSchema = zod_default.object({
71746
- table_workflow_id: zod_default.string().describe("tbw_* binding that emitted the message."),
71747
- workflow_name: zod_default.string().describe("Human name of the workflow at execution time."),
71748
- event: tableWorkflowEventSchema.describe(
71749
- "Lifecycle event that produced the message. Only before_* events can surface here."
71750
- ),
71751
- record_id: zod_default.string().describe(
71752
- "Record that triggered the workflow. Lets the UI scope the message to a specific row in bulk responses."
71753
- ),
71754
- message: zod_default.string().describe("Author-provided text from the workflow's return.message.")
71755
- });
71756
- var tableSchema = zod_default.object({
71757
- id: zod_default.string().describe("Unique identifier for the table"),
71758
- workspace_id: zod_default.string().describe("ID of the workspace this table belongs to"),
71759
- name: zod_default.string().describe("Display name of the table"),
71760
- description: zod_default.string().describe("Description of the table's purpose"),
71761
- position: zod_default.number().int().optional().nullable().describe("Display ordering index for the table. Lower numbers are shown first. "),
71762
- fields: tableFieldsSchema.describe("Array of field definitions for this table"),
71763
- workflows: zod_default.array(tableWorkflowSchema).optional().describe(
71764
- "Workflows attached to this table that fire around record mutations. before_* run synchronously and may reject; after_* run after commit and do not block."
71765
- ),
71766
- private_filters: tableRecordFiltersGroupNodeSchema.nullable().optional().describe("Row-level private filters AND'd to every query as a security boundary (admin bypass)"),
71767
- colors: tableRecordColorsSchema.nullable().optional().describe("Color rules for styling records based on filter conditions"),
71768
- approvers: zod_default.array(principalSchema).nullable().optional().describe(
71769
- "Principals (members, groups, or the organization) who review locked-record change requests on this table. Null/empty = organization admins review. The requester never reviews their own request."
71770
- ),
71771
- created_at: zod_default.string().describe("Timestamp when table was created")
71772
- });
71773
- var recordDataTemplateSchema = zod_default.object({
71774
- id: zod_default.string().describe("Unique identifier for the record data template"),
71775
- name: zod_default.string().describe("Display name of the record data template"),
71776
- description: zod_default.string().describe("Description of the record data template"),
71777
- table_id: zod_default.string().describe("ID of the table this record template belongs to"),
71778
- data: zod_default.record(zod_default.string(), zod_default.unknown()).describe("The data of the record template. The key is the Field key.")
71779
- });
71780
- var tableRecordSchema = zod_default.object({
71781
- id: zod_default.string().describe("Unique identifier for the record"),
71782
- table_id: zod_default.string().describe("ID of the table this record belongs to"),
71783
- workspace_id: zod_default.string().describe("ID of the workspace this record belongs to"),
71784
- data: zod_default.record(zod_default.string(), zod_default.unknown()).describe("The data of the record. The key is the Field key."),
71785
- locked: zod_default.boolean().optional().describe("Whether the entire record is locked from editing"),
71786
- draft: zod_default.boolean().optional().describe("Whether the record is an unsubmitted draft \u2014 UI-only in-progress state, not yet a real row. Row-visibility scoping is enforced at submit, not while a draft is being filled in."),
71787
- updated_at: zod_default.string().describe("Timestamp of last update"),
71788
- created_at: zod_default.string().describe("Timestamp when record was created")
71789
- });
71790
- var viewSummaryEntrySchema = zod_default.object({
71791
- operation: zod_default.string().describe("Operation to perform on the field"),
71792
- field_key: zod_default.string().describe("Field key to display in the summary row")
71793
- });
71794
- var viewSummarySchema = zod_default.record(zod_default.string(), viewSummaryEntrySchema.nullable().optional()).nullable().optional().describe("Map of field keys to summary operations.");
71795
- var visibleToEntrySchema = zod_default.object({
71796
- type: zod_default.enum(["member", "group"]).describe("Principal kind that may see the view: an individual member or a member group"),
71797
- id: zod_default.string().describe("Member ID (type=member) or member-group ID (type=group)")
71798
- });
71799
- var visibleToSchema = zod_default.array(visibleToEntrySchema).nullable();
71800
- var tableViewSchema = zod_default.object({
71801
- id: zod_default.string().describe("Unique identifier for the view"),
71802
- table_id: zod_default.string().describe("ID of the table this view displays"),
71803
- workspace_id: zod_default.string().describe("ID of the workspace this view belongs to"),
71804
- name: zod_default.string().describe("Display name of the view"),
71805
- description: zod_default.string().describe("Description of the view's purpose"),
71806
- visible_to: visibleToSchema.optional().describe(
71807
- "Sidebar declutter list (NOT access control). null/absent = every member with access to the parent table sees this view; a non-empty list of members/groups restricts who sees it in the explorer. [] is normalized to null on write."
71808
- ),
71809
- position: zod_default.number().int().nullable().describe(
71810
- "Display ordering index for the view. Lower numbers are shown first. Use incremental values with gaps (100, 200, 300) instead of consecutive numbers (1, 2, 3) to enable efficient reordering without updating multiple records. Example: To insert between 100 and 200, use 150."
71811
- ),
71812
- frozen_columns: zod_default.number().int().nullable().optional().describe("Number of columns to freeze. Frozen columns are not scrollable."),
71813
- summary: viewSummarySchema,
71814
- default_record_data_template_id: zod_default.string().nullable().optional().describe("ID of the record template to use as the default record initial data"),
71815
- field_config: zod_default.array(fieldConfigEntrySchema).describe(
71816
- "Ordered array of field config entries. Order = display order, visibility = per-entry. Fields not listed are hidden."
71817
- ),
71818
- sort: tableRecordSortSchema.nullable().describe("Sorting configuration for records in this view"),
71819
- filters: tableRecordFiltersGroupNodeSchema.nullable().describe("Filter conditions applied to records in this view"),
71820
- created_at: zod_default.string().describe("Timestamp when view was created")
71821
- });
71822
- var tableWithViewsSchema = tableSchema.extend({
71823
- views: zod_default.array(tableViewSchema).describe("Array of views for this table")
71824
- });
71825
- var explorerViewSchema = zod_default.object({
71826
- id: zod_default.string(),
71827
- name: zod_default.string(),
71828
- owner_member_id: zod_default.string(),
71829
- // Per-view sidebar declutter list (NOT access control). null = every member
71830
- // with table access sees this view; a non-empty member/group list restricts
71831
- // it. Surfaced here so the table share dialog can render and edit each view's
71832
- // audience without a second round-trip.
71833
- visible_to: visibleToSchema.optional(),
71834
- // Per-requesting-member sidebar preference: true if this member has hidden
71835
- // the view. Hiding is UX-only — it never affects access or other members.
71836
- hidden: zod_default.boolean()
71837
- });
71838
- var explorerTableSchema = zod_default.object({
71839
- id: zod_default.string(),
71840
- name: zod_default.string(),
71841
- position: zod_default.number().int().nullable().optional(),
71842
- views: zod_default.array(explorerViewSchema),
71843
- owner_member_id: zod_default.string(),
71844
- // Active package installations whose binding includes this table — the
71845
- // sidebar marks these so members see the structure is app-managed before
71846
- // they try to change it. Absent for unbound tables.
71847
- package_apps: zod_default.array(zod_default.object({ id: zod_default.string(), name: zod_default.string() })).optional()
71848
- });
71849
- var documentTemplateTypeSchema = zod_default.enum(["html", "pdf-form", "excel", "word", "email"]).describe("Template type: 'html' for HTML templates, 'pdf-form' for fillable PDF forms, 'excel' for Excel templates, 'word' for Word templates, 'email' for email HTML templates");
71850
- var documentTemplateSchema = zod_default.object({
71851
- id: zod_default.string().describe("Unique identifier for the document template"),
71852
- workspace_id: zod_default.string().describe("ID of the workspace this template belongs to"),
71853
- name: zod_default.string().describe("Display name of the template"),
71854
- description: zod_default.string().describe("What the template produces, shown under its name in the library"),
71855
- type: documentTemplateTypeSchema,
71856
- template: zod_default.string().describe("Template content with variable placeholders (e.g., {{customer_name}})"),
71857
- format: zod_default.string().describe("Supported document formats.").optional(),
71858
- orientation: zod_default.enum(["portrait", "landscape"]).describe("Page orientation for PDF generation").optional(),
71859
- variables: zod_default.record(zod_default.string(), zod_default.unknown()).describe("Data to pass to the template."),
71860
- current_version: zod_default.number().describe("Current version number of the template"),
71861
- owner_member_id: zod_default.string().nullable().optional().describe("Member who created the template, from the IAM registry. Absent on write responses."),
71862
- created_at: zod_default.string().describe("Timestamp when template was created"),
71863
- template_url: zod_default.string().nullable().describe("Signed URL to download the template file (pdf-form/excel only)")
71864
- });
71865
-
71866
- // ../shared/src/schemas/packages.ts
71867
- var contractAliasSchema = zod_default.string().regex(
71868
- /^[a-z][a-z0-9_]*$/,
71869
- "alias must be a lowercase slug: start with a letter, then letters/digits/underscores"
71870
- );
71871
- var runtimeAliasSchema = zod_default.string().min(1).max(200);
71872
- var contractFieldBaseSchema = zod_default.object({
71873
- alias: contractAliasSchema.describe("Stable local alias, unique within the entity"),
71874
- // No braces: scaffold translates formula expressions from `{alias}` to the
71875
- // platform's `{Field Label}` reference form, so a brace inside a label would
71876
- // corrupt every formula that references the field.
71877
- label: zod_default.string().min(1).regex(/^[^{}]*$/, "field labels cannot contain { or }").describe("Display label used as the field name at scaffold time"),
71878
- description: zod_default.string().optional(),
71879
- required: zod_default.boolean().optional().describe(
71880
- "Advisory only: marks the field required for app-form/workflow UX. The table data model has no required constraint, so scaffold does NOT enforce it at the schema level \u2014 validation lives in the app/workflow layer."
71881
- )
71882
- });
71883
- var contractSelectOptionSchema = zod_default.object({
71884
- alias: contractAliasSchema.describe("Stable local alias, unique within the field"),
71885
- label: zod_default.string().min(1).describe("Display label for the option"),
71886
- color: optionColorSchema
71887
- });
71888
- var contractAutonumberConfigSchema = tableAutonumberFieldSchema.pick({
71889
- prefix: true,
71890
- padding: true,
71891
- template: true
71892
- });
71893
- var contractTextFieldSchema = contractFieldBaseSchema.extend({
71894
- type: zod_default.literal("text"),
71895
- unique: zod_default.boolean().optional().describe("Unique values required"),
71896
- format: textFormatSchema.optional()
71897
- });
71898
- var contractNumberFieldSchema = contractFieldBaseSchema.extend({
71899
- type: zod_default.literal("number"),
71900
- format: numberFormatSchema.optional(),
71901
- currency: zod_default.string().optional().describe("ISO 4217 code")
71902
- });
71903
- var contractDateFieldSchema = contractFieldBaseSchema.extend({
71904
- type: zod_default.literal("date"),
71905
- format: dateFormatSchema.optional(),
71906
- timezone: zod_default.string().optional().describe("IANA timezone"),
71907
- derive_from: zod_default.enum(["created_at", "updated_at"]).optional().describe("Auto-populate from the row's system timestamp; the field becomes read-only.")
71908
- });
71909
- var contractBooleanFieldSchema = contractFieldBaseSchema.extend({
71910
- type: zod_default.literal("boolean")
71911
- });
71912
- var contractSelectFieldSchema = contractFieldBaseSchema.extend({
71913
- type: zod_default.literal("select"),
71914
- options: zod_default.array(contractSelectOptionSchema).min(1),
71915
- multi: zod_default.boolean().optional().describe("Allow multiple selections")
71916
- });
71917
- var contractSelectMemberFieldSchema = contractFieldBaseSchema.extend({
71918
- type: zod_default.literal("select_member"),
71919
- multi: zod_default.boolean().optional().describe("Allow multiple selections")
71920
- });
71921
- var contractSelectRecordLinkFieldSchema = contractFieldBaseSchema.extend({
71922
- type: zod_default.literal("select_record_link"),
71923
- target_entity: contractAliasSchema.describe("Alias of the entity this field links to"),
71924
- sync_both_ways: zod_default.boolean().optional().describe("Create a paired link field on the target entity for bidirectional sync"),
71925
- paired_field_alias: contractAliasSchema.optional().describe(
71926
- "The pair edge of a bidirectional link: the field alias ON THE TARGET ENTITY that is this link's sync partner. Both sides of a pair carry it, each naming the other. Scaffold creates whichever side it reaches first WITH the pairing (the platform auto-creates the partner) and binds the partner alias to the auto-created field \u2014 without this edge the two contract fields would be created independently and collide with the auto-created partner."
71927
- ),
71928
- cardinality: zod_default.enum(["one", "many"]).optional().describe("How many linked records this field holds. Default 'many'."),
71929
- display_field_aliases: zod_default.array(contractAliasSchema).optional().describe("Field aliases on the target entity shown as the link's display text / picker columns")
71930
- });
71931
- var contractFilesFieldSchema = contractFieldBaseSchema.extend({
71932
- type: zod_default.literal("files")
71933
- });
71934
- var contractFormulaFieldSchema = contractFieldBaseSchema.extend({
71935
- type: zod_default.literal("formula"),
71936
- formula: formulaInputSchema.describe(
71937
- "Formula config. The expression references other fields on the SAME entity by alias in braces, e.g. `{quantity} * {unit_price}`."
71938
- )
71939
- });
71940
- var contractRollupFieldSchema = contractFieldBaseSchema.extend({
71941
- type: zod_default.literal("rollup"),
71942
- source_field_alias: contractAliasSchema.describe(
71943
- "Alias of a select_record_link field on this entity to roll up from"
71944
- ),
71945
- aggregate_option: aggregateOptionSchema.describe(
71946
- "Aggregation operation. Its `field_key` names a field alias on the linked entity."
71947
- )
71948
- });
71949
- var contractLookupFieldSchema = contractFieldBaseSchema.extend({
71950
- type: zod_default.literal("lookup"),
71951
- source_field_alias: contractAliasSchema.describe(
71952
- "Alias of a select_record_link field on this entity to look up through"
71953
- ),
71954
- lookup_field_alias: contractAliasSchema.describe(
71955
- "Alias of the field on the linked entity to display"
71956
- ),
71957
- order_by: lookupOrderBySchema.optional().describe("Ordered lookup. Its `field_key` names a field alias on the linked entity.")
71958
- });
71959
- var contractAutonumberFieldSchema = contractFieldBaseSchema.extend({
71960
- type: zod_default.literal("autonumber"),
71961
- ...contractAutonumberConfigSchema.shape
71962
- });
71963
- var contractFieldSchema = zod_default.discriminatedUnion("type", [
71964
- contractTextFieldSchema,
71965
- contractNumberFieldSchema,
71966
- contractDateFieldSchema,
71967
- contractBooleanFieldSchema,
71968
- contractSelectFieldSchema,
71969
- contractSelectMemberFieldSchema,
71970
- contractSelectRecordLinkFieldSchema,
71971
- contractFilesFieldSchema,
71972
- contractFormulaFieldSchema,
71973
- contractRollupFieldSchema,
71974
- contractLookupFieldSchema,
71975
- contractAutonumberFieldSchema
71976
- ]);
71977
- var contractEntitySchema = zod_default.object({
71978
- alias: contractAliasSchema.describe("Stable entity alias, unique within the contract"),
71979
- label: zod_default.string().min(1).describe("Display label used as the table name at scaffold time"),
71980
- description: zod_default.string().optional(),
71981
- fields: zod_default.array(contractFieldSchema).min(1)
71982
- });
71983
- var contractRoleSchema = zod_default.object({
71984
- alias: contractAliasSchema.describe("Stable role alias, bound to a workspace group at install"),
71985
- label: zod_default.string().min(1)
71986
- });
71987
- var contractTemplateBaseSchema = zod_default.object({
71988
- alias: contractAliasSchema.describe("Stable template alias, unique within the contract"),
71989
- label: zod_default.string().min(1),
71990
- content_sha256: zod_default.string().optional().describe(
71991
- "sha256 (64-char lowercase hex) of the template content \u2014 inline: the utf-8 content string; file-backed: the bytes_ref bytes. The modified-detection reference. Optional in the schema so contracts published before template sha still parse; REQUIRED at publish (validatePackageContract)."
71992
- )
71993
- });
71994
- var contractInlineTemplateSchema = (templateType) => contractTemplateBaseSchema.extend({
71995
- type: zod_default.literal(templateType),
71996
- content: zod_default.string().min(1).describe("Inline template content; placeholders reference field aliases")
71997
- });
71998
- var contractFileTemplateSchema = (templateType) => contractTemplateBaseSchema.extend({
71999
- type: zod_default.literal(templateType),
72000
- bytes_ref: zod_default.string().min(1).describe("Path of the backing file within the package bundle; markers reference field aliases")
72001
- });
72002
- var contractTemplateSchema = zod_default.discriminatedUnion("type", [
72003
- contractInlineTemplateSchema("html"),
72004
- contractInlineTemplateSchema("email"),
72005
- contractFileTemplateSchema("excel"),
72006
- contractFileTemplateSchema("word"),
72007
- contractFileTemplateSchema("pdf-form")
72008
- ]);
72009
- var contractFromTableNodeSchema = zod_default.object({
72010
- kind: zod_default.literal("from_table"),
72011
- from_entity: contractAliasSchema.describe("Entity alias this query reads from"),
72012
- filter: tableRecordFiltersSchema.optional(),
72013
- search: zod_default.string().optional(),
72014
- sort: tableRecordSortSchema.optional(),
72015
- limit: zod_default.number().optional()
72016
- });
72017
- var contractProjectNodeSchema = zod_default.object({
72018
- kind: zod_default.literal("project"),
72019
- from: zod_default.lazy(() => contractQueryNodeSchema),
72020
- columns: zod_default.array(queryProjectionColumnSchema).min(1)
72021
- });
72022
- var contractFilterNodeSchema = zod_default.object({
72023
- kind: zod_default.literal("filter"),
72024
- from: zod_default.lazy(() => contractQueryNodeSchema),
72025
- predicate: tableRecordFiltersSchema
72026
- });
72027
- var contractJoinNodeSchema = zod_default.object({
72028
- kind: zod_default.literal("join"),
72029
- left: zod_default.lazy(() => contractQueryNodeSchema),
72030
- right: zod_default.lazy(() => contractQueryNodeSchema),
72031
- on: queryJoinPredicateSchema,
72032
- type: zod_default.enum(["inner", "left"])
72033
- });
72034
- var contractUnionNodeSchema = zod_default.object({
72035
- kind: zod_default.literal("union"),
72036
- sources: zod_default.array(zod_default.lazy(() => contractQueryNodeSchema)).min(2)
72037
- });
72038
- var contractGroupNodeSchema = zod_default.object({
72039
- kind: zod_default.literal("group"),
72040
- from: zod_default.lazy(() => contractQueryNodeSchema),
72041
- by: zod_default.array(zod_default.string()),
72042
- aggregates: zod_default.array(queryAggregateColumnSchema).min(1)
72043
- });
72044
- var contractWindowNodeSchema = zod_default.object({
72045
- kind: zod_default.literal("window"),
72046
- from: zod_default.lazy(() => contractQueryNodeSchema),
72047
- partition_by: zod_default.array(zod_default.string()),
72048
- order_by: tableRecordSortSchema,
72049
- frame: queryWindowFrameSchema.optional(),
72050
- aggregates: zod_default.array(queryAggregateColumnSchema).optional(),
72051
- functions: zod_default.array(queryWindowFunctionColumnSchema).optional()
72052
- });
72053
- var contractSortNodeSchema = zod_default.object({
72054
- kind: zod_default.literal("sort"),
72055
- from: zod_default.lazy(() => contractQueryNodeSchema),
72056
- by: tableRecordSortSchema
72057
- });
72058
- var contractLimitNodeSchema = zod_default.object({
72059
- kind: zod_default.literal("limit"),
72060
- from: zod_default.lazy(() => contractQueryNodeSchema),
72061
- n: zod_default.number().int().positive(),
72062
- offset: zod_default.number().int().nonnegative().optional()
72063
- });
72064
- var contractUnpivotNodeSchema = zod_default.object({
72065
- kind: zod_default.literal("unpivot"),
72066
- from: zod_default.lazy(() => contractQueryNodeSchema),
72067
- passthrough: zod_default.array(queryUnpivotPassthroughColumnSchema),
72068
- row_columns: zod_default.array(queryUnpivotRowColumnSchema).min(1),
72069
- rows: zod_default.array(zod_default.record(zod_default.string(), querySourceSchema)).min(1)
72070
- });
72071
- var contractUnnestNodeSchema = zod_default.object({
72072
- kind: zod_default.literal("unnest"),
72073
- from: zod_default.lazy(() => contractQueryNodeSchema),
72074
- source: zod_default.string(),
72075
- output: zod_default.string(),
72076
- display_output: zod_default.string().optional(),
72077
- keep_empty: zod_default.boolean().optional()
72078
- });
72079
- var contractQueryNodeSchema = zod_default.lazy(
72080
- () => zod_default.discriminatedUnion("kind", [
72081
- contractFromTableNodeSchema,
72082
- contractProjectNodeSchema,
72083
- contractFilterNodeSchema,
72084
- contractJoinNodeSchema,
72085
- contractUnionNodeSchema,
72086
- contractGroupNodeSchema,
72087
- contractWindowNodeSchema,
72088
- contractSortNodeSchema,
72089
- contractLimitNodeSchema,
72090
- contractUnpivotNodeSchema,
72091
- contractUnnestNodeSchema
72092
- ])
72093
- );
72094
- var contractQuerySchema = zod_default.object({
72095
- alias: runtimeAliasSchema.describe(
72096
- "Stable query alias, unique within the contract \u2014 carried verbatim from the app (source invokes it at runtime)"
72097
- ),
72098
- params: zod_default.record(zod_default.string(), appWorkflowInputSchema).optional().describe("Typed param schema. Keys are param names referenced as {{params.<name>}} in the ast."),
72099
- ast: contractQueryNodeSchema
72100
- });
72101
- var contractLifecycleEventSchema = tableWorkflowEventSchema;
72102
- var contractWorkflowTriggerSchema = zod_default.discriminatedUnion("type", [
72103
- zod_default.object({ type: zod_default.literal("app") }),
72104
- zod_default.object({
72105
- type: zod_default.literal("entity_lifecycle"),
72106
- entity: contractAliasSchema.describe("Alias of the entity whose lifecycle fires this workflow"),
72107
- event: contractLifecycleEventSchema
72108
- })
72109
- ]);
72110
- var contractWorkflowSchema = zod_default.object({
72111
- alias: runtimeAliasSchema.describe(
72112
- "Stable workflow alias, unique within the contract \u2014 app-trigger aliases are carried verbatim from the app (source invokes them at runtime)"
72113
- ),
72114
- trigger: contractWorkflowTriggerSchema,
72115
- inputs: zod_default.record(zod_default.string(), appWorkflowInputSchema).optional().describe("Typed inputs. record_link `table_id` names an entity alias; member `group` a role alias."),
72116
- outputs: zod_default.record(zod_default.string(), appWorkflowOutputSchema).optional().describe("Typed outputs. record_link `table_id` names an entity alias."),
72117
- body: zod_default.string().min(1).describe("Alias-form JS-subset workflow source. Identifiers are resolved against the binding at materialize time.")
72118
- });
72119
- var contractAgentSchema = appAgentDeclarationSchema.extend({
72120
- alias: runtimeAliasSchema.describe(
72121
- "Stable agent alias, unique within the contract \u2014 carried verbatim from the app (source invokes it at runtime)"
72122
- ),
72123
- knowledge_expects: zod_default.array(zod_default.string().min(1)).optional().describe(
72124
- "Doc NAMES this agent must read that the package does NOT own \u2014 the installer's own docs. Resolved by name against the installing workspace: exactly one non-archived match binds, zero or several bind nothing and surface as an install warning, because doc names are not unique and picking one would be a guess. The agent installs either way."
72125
- ),
72126
- knowledge_aliases: zod_default.array(contractAliasSchema).optional().describe(
72127
- "Package knowledge docs this agent may read, by contract alias. Materialize resolves each against `binding.knowledge` to the installing workspace's own doc id and writes the agent's `knowledge_doc_ids`. Omit for an agent that reads no package knowledge \u2014 an agent whose declared set does not travel can read NOTHING, since a declared set bounds every read."
72128
- )
72129
- });
72130
- var contractConfigBaseSchema = zod_default.object({
72131
- alias: contractAliasSchema.describe("Stable config alias, unique within the contract"),
72132
- label: zod_default.string().min(1),
72133
- description: zod_default.string().optional()
72134
- });
72135
- var contractTextConfigSchema = contractConfigBaseSchema.extend({
72136
- type: zod_default.literal("text"),
72137
- default: zod_default.string()
72138
- });
72139
- var contractBooleanConfigSchema = contractConfigBaseSchema.extend({
72140
- type: zod_default.literal("boolean"),
72141
- default: zod_default.boolean()
72142
- });
72143
- var contractColorConfigSchema = contractConfigBaseSchema.extend({
72144
- type: zod_default.literal("color"),
72145
- default: optionColorSchema
72146
- });
72147
- var contractNumberConfigSchema = contractConfigBaseSchema.extend({
72148
- type: zod_default.literal("number"),
72149
- default: zod_default.number()
72150
- });
72151
- var contractSelectConfigSchema = contractConfigBaseSchema.extend({
72152
- type: zod_default.literal("select"),
72153
- options: zod_default.array(zod_default.object({ value: zod_default.string(), label: zod_default.string().min(1) })).min(1),
72154
- default: zod_default.string()
72155
- });
72156
- var contractConfigEntrySchema = zod_default.discriminatedUnion("type", [
72157
- contractTextConfigSchema,
72158
- contractBooleanConfigSchema,
72159
- contractColorConfigSchema,
72160
- contractNumberConfigSchema,
72161
- contractSelectConfigSchema
72162
- ]);
72163
- var packageKindSchema = zod_default.enum(["app", "content"]);
72164
- var contractKnowledgeEntrySchema = zod_default.object({
72165
- name: zod_default.string().min(1).describe(
72166
- "Display name \u2014 the runtime routing key an agent resolves the doc by; unique across the contract's knowledge"
72167
- ),
72168
- description: zod_default.string().describe("Doc description (may be empty)"),
72169
- // Optional so contracts published before tagging still parse; absent means
72170
- // untagged. A curated corpus is exactly the case where classification is
72171
- // authored deliberately, so install and upgrade have to carry it — otherwise
72172
- // every installed corpus lands unlabelled and the customer re-tags it by hand.
72173
- //
72174
- // ABSENT IS NOT EMPTY, and that distinction is load-bearing on the wire: a
72175
- // contract that says nothing about tags must leave the customer's own labels
72176
- // alone, or a routine content upgrade silently strips classification the
72177
- // workspace added. Every reader below branches on `undefined`, never on length.
72178
- tags: zod_default.array(zod_default.string()).optional().describe("Labels for the doc; omitted leaves existing labels alone"),
72179
- /**
72180
- * LEGACY, read-only, removed in a later release.
72181
- *
72182
- * Content packages published while knowledge docs had folders carry a `path`,
72183
- * and those contracts are stored verbatim in the workspaces that installed
72184
- * them. Dropping the field would make an installed contract fail to parse and
72185
- * would discard what the publisher declared, so it is still accepted and
72186
- * mapped to `tags` on install/upgrade (a path's segments were always labels;
72187
- * the hierarchy merely insisted on an order for them). Nothing EMITS it any
72188
- * more — `content_bundle` writes `tags` — so it disappears from a package the
72189
- * first time it is re-published.
72190
- */
72191
- path: zod_default.string().optional().describe("Deprecated: pre-tagging folder. Mapped to tags on install."),
72192
- content_ref: zod_default.string().min(1).describe("Path of the content file within the bundle \u2014 must be `knowledge/<alias>.md`"),
72193
- content_sha256: zod_default.string().describe("sha256 (64-char lowercase hex) of the content bytes \u2014 the modified-detection reference")
72194
- });
72195
- var contractKnowledgeSchema = zod_default.record(contractAliasSchema, contractKnowledgeEntrySchema);
72196
- var packageContractSchema = zod_default.object({
72197
- entities: zod_default.array(contractEntitySchema).default([]),
72198
- roles: zod_default.array(contractRoleSchema).default([]),
72199
- templates: zod_default.array(contractTemplateSchema).default([]),
72200
- queries: zod_default.array(contractQuerySchema).default([]),
72201
- workflows: zod_default.array(contractWorkflowSchema).default([]),
72202
- agents: zod_default.array(contractAgentSchema).default([]),
72203
- config: zod_default.array(contractConfigEntrySchema).default([]),
72204
- // Package-managed knowledge docs (alias → metadata + content sha). Defaults to
72205
- // {} so contracts published before knowledge packaging still parse.
72206
- knowledge: contractKnowledgeSchema.default({}),
72207
- // Doc NAMES the package's agents route to but the package does not own —
72208
- // install/health WARN (advisory) when a name has no doc in the workspace.
72209
- // The first instance of the general cross-package "expects" contract.
72210
- knowledge_expects: zod_default.array(zod_default.string()).default([])
72211
- });
72212
- var bindingMapSchema = zod_default.record(zod_default.string().min(1), zod_default.string().min(1));
72213
- var bindingSchema = zod_default.object({
72214
- entities: bindingMapSchema.default({}),
72215
- fields: bindingMapSchema.default({}),
72216
- options: bindingMapSchema.default({}),
72217
- templates: bindingMapSchema.default({}),
72218
- roles: bindingMapSchema.default({}),
72219
- // Artifact registry, not a schema binding: the package-owned table-workflow
72220
- // ROW id per entity_lifecycle workflow alias. Materialize matches/updates by
72221
- // this id (a display name is forgeable and renameable), upgrade prunes by
72222
- // it, and hashes look rows up through it. Excluded from BINDING_NAMESPACES:
72223
- // a deleted row is a modified-core finding (fingerprints), never binding
72224
- // drift, so validateBinding/applyDriftResolutions ignore it.
72225
- workflows: bindingMapSchema.default({}),
72226
- // The app's BUNDLED knowledge corpus: contract knowledge alias → the
72227
- // workspace's concrete `kdc_` id. One row, one pin — the app installation IS
72228
- // the anchor for its bundled docs (`package_content_installations` rows are
72229
- // standalone content packages only). Excluded from BINDING_NAMESPACES: a
72230
- // gone/edited doc is detected by the knowledge upgrade preview (live doc +
72231
- // content-sha reads), never by validateBinding's live-id sweep.
72232
- knowledge: bindingMapSchema.default({})
72233
- });
72234
- var BINDING_NAMESPACES = ["entities", "fields", "options", "templates", "roles"];
72235
- var contentBindingMapSchema = zod_default.record(zod_default.string().min(1), zod_default.string().min(1));
72236
- var packageContentBindingSchema = zod_default.object({
72237
- knowledge: contentBindingMapSchema.default({}),
72238
- templates: contentBindingMapSchema.default({})
72239
- });
72240
- var bindingDriftSchema = zod_default.object({
72241
- namespace: zod_default.enum(BINDING_NAMESPACES),
72242
- alias: zod_default.string(),
72243
- id: zod_default.string().describe("The stale concrete id the alias was bound to")
72244
- });
72245
- var driftResolutionSchema = zod_default.union([
72246
- zod_default.literal("recreate"),
72247
- zod_default.object({ bind_to: zod_default.string().min(1) })
72248
- ]);
72249
- var MODIFIED_ARTIFACT_KINDS = ["queries", "workflows", "agents", "template"];
72250
- var modifiedArtifactSchema = zod_default.object({
72251
- kind: zod_default.enum(MODIFIED_ARTIFACT_KINDS),
72252
- alias: zod_default.string(),
72253
- // Templates only: the OLD pinned contract carried no content_sha256, so the
72254
- // preview cannot attribute the divergence from the target to a local edit vs.
72255
- // the older upstream content — a one-time consent, converging once a
72256
- // sha-carrying version is pinned. Surfaces can say "can't verify local edits
72257
- // (older package version)".
72258
- baseline_unknown: zod_default.boolean().optional()
72259
- });
72260
- var packageArtifactHashesSchema = zod_default.object({
72261
- queries: zod_default.record(zod_default.string(), zod_default.string()),
72262
- workflows: zod_default.record(zod_default.string(), zod_default.string()),
72263
- agents: zod_default.record(zod_default.string(), zod_default.string())
72264
- });
72265
- var modificationResolutionSchema = zod_default.union([zod_default.literal("revert"), zod_default.literal("keep")]);
72266
- var KNOWLEDGE_UPGRADE_CHANGES = ["added", "changed", "removed", "drifted"];
72267
- var knowledgeUpgradeEntrySchema = zod_default.object({
72268
- alias: zod_default.string(),
72269
- name: zod_default.string().describe("The doc's display name \u2014 the target contract's name, or the live name for a drifted doc"),
72270
- change: zod_default.enum(KNOWLEDGE_UPGRADE_CHANGES),
72271
- /** `changed`/`removed` only: the live doc's content diverged from the OLD pinned sha. */
72272
- modified: zod_default.boolean(),
72273
- /** The bound live doc id; null for `added`, or for a `drifted` doc that is gone. */
72274
- doc_id: zod_default.string().nullable()
72275
- });
72276
- function knowledgeEntryNeedsConsent(entry) {
72277
- if (entry.change === "drifted") return true;
72278
- if (entry.change === "changed" || entry.change === "removed") return entry.modified;
72279
- return false;
72280
- }
72281
- var knowledgeResolutionSchema = zod_default.enum(["apply", "keep", "archive", "recreate", "unbind"]);
72282
- var upgradeResolutionsSchema = zod_default.record(
72283
- zod_default.string(),
72284
- zod_default.union([driftResolutionSchema, modificationResolutionSchema, knowledgeResolutionSchema])
72285
- );
72286
- var knowledgeBindConsentSchema = zod_default.record(zod_default.string(), zod_default.string());
72287
- var knowledgeUpgradeResolutionsSchema = zod_default.object({
72288
- resolutions: zod_default.record(zod_default.string(), knowledgeResolutionSchema).default({}),
72289
- bind_to: knowledgeBindConsentSchema.default({})
72290
- });
72291
- var knowledgeBoundRefSchema = zod_default.object({
72292
- alias: zod_default.string(),
72293
- name: zod_default.string(),
72294
- /** The bound doc id; null when the bound doc is gone/archived (drift). */
72295
- doc_id: zod_default.string().nullable()
72296
- });
72297
- var appInstallationConfigValueSchema = zod_default.union([zod_default.string(), zod_default.number(), zod_default.boolean()]);
72298
- var appInstallationConfigSchema = zod_default.record(
72299
- contractAliasSchema,
72300
- appInstallationConfigValueSchema
72301
- );
72302
- var appInstallationProvenanceSchema = zod_default.enum(["install", "adopt"]);
72303
-
72304
70989
  // ../shared/src/agent_instructions.ts
72305
70990
  function agentFilePath(alias) {
72306
70991
  return `src/agents/${alias}.md`;
@@ -72712,6 +71397,16 @@ function runNpm(args, cwd) {
72712
71397
  });
72713
71398
  });
72714
71399
  }
71400
+ function npmInstallArgs(hasLockfile) {
71401
+ return [hasLockfile ? "ci" : "install", "--ignore-scripts"];
71402
+ }
71403
+ function runNpmInstall(cwd) {
71404
+ const hasLockfile = fs8.existsSync(path10.join(cwd, "package-lock.json"));
71405
+ console.error(
71406
+ hasLockfile ? "Installing npm dependencies (npm ci \u2014 the lockfile's exact tree, no install scripts)..." : "Installing npm dependencies (no lockfile yet \u2014 resolving ranges, no install scripts)..."
71407
+ );
71408
+ return runNpm(npmInstallArgs(hasLockfile), cwd);
71409
+ }
72715
71410
  function readAppWorkspaceId(projectDir) {
72716
71411
  try {
72717
71412
  const pkgPath2 = path10.join(projectDir, "package.json");
@@ -72924,13 +71619,6 @@ function writeAppFields(projectDir, tables) {
72924
71619
  fs8.writeFileSync(file2, generateAppFields(tables));
72925
71620
  return file2;
72926
71621
  }
72927
- function writeBindingAppFields(projectDir, binding) {
72928
- const dotLotics = path10.join(projectDir, ".lotics");
72929
- fs8.mkdirSync(dotLotics, { recursive: true });
72930
- const file2 = path10.join(dotLotics, "app_fields.ts");
72931
- fs8.writeFileSync(file2, generatePackageAppFields(binding));
72932
- return file2;
72933
- }
72934
71622
  async function writeGeneratedAppFields(client, projectDir, app, queries) {
72935
71623
  if (client.viewAsMemberId) {
72936
71624
  console.error(
@@ -72939,14 +71627,7 @@ async function writeGeneratedAppFields(client, projectDir, app, queries) {
72939
71627
  return;
72940
71628
  }
72941
71629
  try {
72942
- if (app.package_id) {
72943
- const binding = await client.appBinding(app.app_id);
72944
- const fieldsPath = writeBindingAppFields(projectDir, binding);
72945
- const count = Object.keys(binding.fields).length;
72946
- console.error(
72947
- `Wrote ${fieldsPath} (binding form \u2014 linked to package ${app.package_id}; ${count} field alias${count === 1 ? "" : "es"} resolved per-install)`
72948
- );
72949
- } else {
71630
+ {
72950
71631
  const tableIds = resolveCodegenTableIds(projectDir, queries);
72951
71632
  const tables = await client.getWorkspaceSchema(tableIds);
72952
71633
  const missing = tableIds.filter((id) => !tables.some((t) => t.id === id));
@@ -73068,19 +71749,14 @@ function ensureAppVitestSetup(projectDir) {
73068
71749
  const setupPath = path10.join(projectDir, VITEST_SETUP_FILENAME);
73069
71750
  if (!fs8.existsSync(setupPath)) {
73070
71751
  fs8.writeFileSync(setupPath, VITEST_SETUP_CONTENT);
73071
- console.error(`Wrote ${VITEST_SETUP_FILENAME} (stubs getAppBinding so \`npm test\` collects).`);
73072
- } else if (!fs8.readFileSync(setupPath, "utf-8").includes("getAppBinding")) {
73073
- console.error(
73074
- `\u26A0 ${VITEST_SETUP_FILENAME} exists but does not stub getAppBinding \u2014 \`npm test\` will fail to collect any test that imports the app graph (the binding-form .lotics/app_fields.ts awaits a network call). Add the stub to it:
73075
- ${VITEST_SETUP_CONTENT}`
73076
- );
71752
+ console.error(`Wrote ${VITEST_SETUP_FILENAME} (wired by vite.config.ts; empty until you fill it).`);
73077
71753
  }
73078
71754
  const viteConfigPath = path10.join(projectDir, "vite.config.ts");
73079
71755
  if (!fs8.existsSync(viteConfigPath)) return;
73080
71756
  const viteConfig = fs8.readFileSync(viteConfigPath, "utf-8");
73081
71757
  if (/setupFiles\s*:/.test(viteConfig) && viteConfig.includes(VITEST_SETUP_FILENAME)) return;
73082
71758
  console.error(
73083
- `\u26A0 vite.config.ts does not wire ${VITEST_SETUP_FILENAME} \u2014 \`npm test\` will fail to collect any test that imports the app graph (the binding-form .lotics/app_fields.ts awaits a network call). Add it to the \`test\` block:
71759
+ `\u26A0 vite.config.ts does not wire ${VITEST_SETUP_FILENAME}. Nothing is broken by that \u2014 it is the slot for global test setup (matchers, stubs, timezone pinning). Add it to the \`test\` block when you need one:
73084
71760
  setupFiles: ["./${VITEST_SETUP_FILENAME}"],`
73085
71761
  );
73086
71762
  }
@@ -73114,7 +71790,7 @@ async function appCodegen(args) {
73114
71790
  await writeGeneratedAppFields(
73115
71791
  args.client,
73116
71792
  projectDir,
73117
- { app_id: meta3.app_id, package_id: app.package_id },
71793
+ { app_id: meta3.app_id },
73118
71794
  meta3.queries ?? {}
73119
71795
  );
73120
71796
  } catch (err2) {
@@ -73233,8 +71909,7 @@ async function materializeScaffold(targetPath, files) {
73233
71909
  }
73234
71910
  console.error(`Scaffolded ${files.length} files into ${targetPath}`);
73235
71911
  writeAppDts(targetPath, {});
73236
- console.error("Installing npm dependencies...");
73237
- await runNpm(["install"], targetPath);
71912
+ await runNpmInstall(targetPath);
73238
71913
  writeAppDtsKitLinks(targetPath);
73239
71914
  }
73240
71915
  async function appCreate(client, args) {
@@ -73340,43 +72015,7 @@ function defaultPullTarget(appId, appName) {
73340
72015
  }
73341
72016
  return appDirName(appName);
73342
72017
  }
73343
- async function appPull(client, args) {
73344
- const app = await client.getApp(args.app_id);
73345
- if (!app.current_version_id && args.version === void 0) {
73346
- throw new Error(
73347
- `App ${app.id} has no published version yet. Deploy from another machine first, or use 'lotics app create' to scaffold a new app.`
73348
- );
73349
- }
73350
- const versionId = args.version ?? app.current_version_id;
73351
- if (!versionId) throw new Error(`App ${app.id} has no version to pull.`);
73352
- const version2 = await client.getAppVersion(app.id, versionId);
73353
- const sourceUrl = await client.getAppVersionSourceUrl(app.id, version2.id);
73354
- const targetPath = path10.resolve(args.targetPath ?? defaultPullTarget(app.id, app.name));
73355
- fs8.mkdirSync(targetPath, { recursive: true });
73356
- const prior = readPriorStamp(targetPath);
73357
- const tmpFile = path10.join(tmpdir(), `lotics-app-${app.id}-${Date.now()}.tar.gz`);
73358
- console.error(`Downloading source archive...`);
73359
- await downloadToFile(sourceUrl, tmpFile);
73360
- const keptLocal = [];
73361
- const stagingDir = fs8.mkdtempSync(path10.join(tmpdir(), `lotics-pull-${app.id}-`));
73362
- try {
73363
- await runTar(["-xzf", tmpFile, "-C", stagingDir], stagingDir);
73364
- console.error(`Extracting to ${targetPath}...`);
73365
- keptLocal.push(
73366
- ...copyTree(stagingDir, targetPath, {
73367
- overwrite: args.force === true,
73368
- skip: [WORKFLOWS_DIR, AGENTS_DIR].map((d) => d.split(path10.sep).join("/"))
73369
- })
73370
- );
73371
- } finally {
73372
- if (fs8.existsSync(tmpFile)) fs8.unlinkSync(tmpFile);
73373
- fs8.rmSync(stagingDir, { recursive: true, force: true });
73374
- }
73375
- const stamp = stampAfterPull({
73376
- prior,
73377
- pulled: { id: versionId, number: version2.version },
73378
- keptCount: keptLocal.length
73379
- });
72018
+ async function hydrateAppProject(client, targetPath, app, opts) {
73380
72019
  stampPulledManifest(targetPath, {
73381
72020
  app_id: app.id,
73382
72021
  workspace_id: app.workspace_id,
@@ -73384,8 +72023,8 @@ async function appPull(client, args) {
73384
72023
  // after pulling an OLD one would let the next deploy ship that old source as
73385
72024
  // if it were built on the newest — the version guard exists to refuse
73386
72025
  // exactly that, and it can only do so if this tells the truth.
73387
- current_version_id: stamp.id,
73388
- version_number: stamp.number,
72026
+ current_version_id: opts.stamp.id,
72027
+ version_number: opts.stamp.number,
73389
72028
  workflows: app.workflows ?? {},
73390
72029
  queries: app.queries ?? {},
73391
72030
  agents: app.agents ?? {}
@@ -73397,14 +72036,14 @@ async function appPull(client, args) {
73397
72036
  await writeGeneratedAppFields(
73398
72037
  client,
73399
72038
  targetPath,
73400
- { app_id: app.id, package_id: app.package_id },
72039
+ { app_id: app.id },
73401
72040
  app.queries ?? {}
73402
72041
  );
73403
72042
  const workflows = app.workflows ?? {};
73404
72043
  if (Object.keys(workflows).length > 0) {
73405
72044
  const written = await writeWorkflowFiles(client, targetPath, app.id, app.name, workflows, {
73406
- overwrite: args.force === true,
73407
- kept: keptLocal
72045
+ overwrite: opts.force === true,
72046
+ kept: opts.kept
73408
72047
  });
73409
72048
  if (written.length > 0) {
73410
72049
  console.error(
@@ -73415,8 +72054,8 @@ async function appPull(client, args) {
73415
72054
  const agents = app.agents ?? {};
73416
72055
  if (Object.keys(agents).length > 0) {
73417
72056
  const written = writeAgentFiles(targetPath, agents, {
73418
- overwrite: args.force === true,
73419
- kept: keptLocal
72057
+ overwrite: opts.force === true,
72058
+ kept: opts.kept
73420
72059
  });
73421
72060
  for (const alias of written) {
73422
72061
  const instructions = agents[alias]?.instructions;
@@ -73430,9 +72069,51 @@ async function appPull(client, args) {
73430
72069
  );
73431
72070
  }
73432
72071
  }
73433
- console.error(`Installing npm dependencies...`);
73434
- await runNpm(["install"], targetPath);
72072
+ await runNpmInstall(targetPath);
73435
72073
  writeAppDtsKitLinks(targetPath);
72074
+ }
72075
+ async function appPull(client, args) {
72076
+ const app = await client.getApp(args.app_id);
72077
+ if (!app.current_version_id && args.version === void 0) {
72078
+ throw new Error(
72079
+ `App ${app.id} has no published version yet. Deploy from another machine first, or use 'lotics app create' to scaffold a new app.`
72080
+ );
72081
+ }
72082
+ const versionId = args.version ?? app.current_version_id;
72083
+ if (!versionId) throw new Error(`App ${app.id} has no version to pull.`);
72084
+ const version2 = await client.getAppVersion(app.id, versionId);
72085
+ const sourceUrl = await client.getAppVersionSourceUrl(app.id, version2.id);
72086
+ const targetPath = path10.resolve(args.targetPath ?? defaultPullTarget(app.id, app.name));
72087
+ fs8.mkdirSync(targetPath, { recursive: true });
72088
+ const prior = readPriorStamp(targetPath);
72089
+ const tmpFile = path10.join(tmpdir(), `lotics-app-${app.id}-${Date.now()}.tar.gz`);
72090
+ console.error(`Downloading source archive...`);
72091
+ await downloadToFile(sourceUrl, tmpFile);
72092
+ const keptLocal = [];
72093
+ const stagingDir = fs8.mkdtempSync(path10.join(tmpdir(), `lotics-pull-${app.id}-`));
72094
+ try {
72095
+ await runTar(["-xzf", tmpFile, "-C", stagingDir], stagingDir);
72096
+ console.error(`Extracting to ${targetPath}...`);
72097
+ keptLocal.push(
72098
+ ...copyTree(stagingDir, targetPath, {
72099
+ overwrite: args.force === true,
72100
+ skip: [WORKFLOWS_DIR, AGENTS_DIR].map((d) => d.split(path10.sep).join("/"))
72101
+ })
72102
+ );
72103
+ } finally {
72104
+ if (fs8.existsSync(tmpFile)) fs8.unlinkSync(tmpFile);
72105
+ fs8.rmSync(stagingDir, { recursive: true, force: true });
72106
+ }
72107
+ const stamp = stampAfterPull({
72108
+ prior,
72109
+ pulled: { id: versionId, number: version2.version },
72110
+ keptCount: keptLocal.length
72111
+ });
72112
+ await hydrateAppProject(client, targetPath, app, {
72113
+ stamp: { id: stamp.id, number: stamp.number },
72114
+ ...args.force !== void 0 ? { force: args.force } : {},
72115
+ kept: keptLocal
72116
+ });
73436
72117
  reportKeptLocalFiles(keptLocal, app.id, {
73437
72118
  // `prior` is non-null whenever the stamp was held — `stampAfterPull` cannot
73438
72119
  // hold against nothing — so the fallback only covers the un-held branch,
@@ -73490,7 +72171,7 @@ async function appDeploy(client, args) {
73490
72171
  await writeGeneratedAppFields(
73491
72172
  client,
73492
72173
  projectDir,
73493
- { app_id: meta3.app_id, package_id: liveApp.package_id },
72174
+ { app_id: meta3.app_id },
73494
72175
  meta3.queries ?? {}
73495
72176
  );
73496
72177
  } catch (err2) {
@@ -73650,80 +72331,6 @@ async function readLiveQueries(client, appId) {
73650
72331
  process.exit(1);
73651
72332
  }
73652
72333
  }
73653
- async function installCommand(client, args) {
73654
- const res = await client.installPackage(args.packageId, {});
73655
- if (res.kind === "app") {
73656
- const { app } = res;
73657
- console.error(
73658
- `Installed "${app.name}" (${app.id})` + (app.package_version !== null ? ` at v${app.package_version}` : "") + `.
73659
- Open it from the workspace's app launcher.
73660
- To work on it locally: lotics app pull ${app.id}
73661
- To give it an address: lotics app subdomain <slug> (from inside that project)`
73662
- );
73663
- reportKnowledgeWarnings(res.knowledge_warnings);
73664
- return;
73665
- }
73666
- console.error(
73667
- `Installed content package (${res.installation.id}).
73668
- Its documents and templates are now in this workspace.`
73669
- );
73670
- reportKnowledgeWarnings(res.warnings);
73671
- }
73672
- function reportKnowledgeWarnings(warnings) {
73673
- const missing = warnings.missing_expected_docs;
73674
- if (missing.length === 0) return;
73675
- console.error(
73676
- `
73677
- \u26A0 ${missing.length} expected knowledge doc(s) are missing from this workspace:
73678
- ` + missing.map((name2) => ` \u2022 ${name2}`).join("\n") + `
73679
- An agent declaring one of these reads nothing from it \u2014 the run still completes,
73680
- answering from nowhere. Create them, then re-run the install.`
73681
- );
73682
- }
73683
- async function upgradeCommand(client, args) {
73684
- const projectDir = path10.resolve(args.projectDir ?? process.cwd());
73685
- const meta3 = readAppMeta(projectDir);
73686
- const plan = await client.previewPackageUpgrade(meta3.app_id, {});
73687
- if (plan.from_version === plan.to_version) {
73688
- console.error(`Already on v${plan.from_version} \u2014 nothing to take.`);
73689
- return;
73690
- }
73691
- const blockers = [
73692
- ...plan.diff.breaking.map(
73693
- (b) => ` \u2022 breaking: ${b.entity}.${b.alias} ${b.kind} ${b.from} \u2192 ${b.to}`
73694
- ),
73695
- ...plan.modified.map(
73696
- (m) => ` \u2022 locally modified: ${m.kind} "${m.alias}"` + (m.baseline_unknown === true ? " (no baseline recorded \u2014 cannot tell what changed)" : "")
73697
- ),
73698
- ...plan.drift.map((d) => ` \u2022 drifted: ${d.namespace} "${d.alias}"`),
73699
- // The FOURTH refusal source, and the one this originally missed. The server
73700
- // throws a BadRequestError for every entry `knowledgeEntryNeedsConsent`
73701
- // accepts, so leaving it out did not make those upgrades work — it swapped
73702
- // the carefully-framed refusal for a raw wire 400. Read the canonical
73703
- // predicate rather than re-deriving the rule: a hand-listed subset of a
73704
- // server-side decision is how three of four got covered in the first place.
73705
- ...plan.knowledge.filter(knowledgeEntryNeedsConsent).map(
73706
- (k) => ` \u2022 knowledge: "${k.alias}" (${k.change}${k.modified ? ", locally edited" : ""})`
73707
- )
73708
- ];
73709
- if (blockers.length > 0) {
73710
- console.error(
73711
- `v${plan.from_version} \u2192 v${plan.to_version} needs decisions this command will not make for you:
73712
- ` + blockers.join("\n") + `
73713
-
73714
- Each one resolves by choosing what to KEEP, and guessing would discard
73715
- work nobody asked to lose. Resolve them, or ask an operator to run the
73716
- upgrade with explicit resolutions.`
73717
- );
73718
- process.exit(1);
73719
- }
73720
- const applied = await client.upgradePackage(meta3.app_id, { version: plan.to_version });
73721
- console.error(
73722
- `Upgraded to v${applied.package_version ?? plan.to_version}.` + (plan.changelog ? `
73723
- ${plan.changelog}` : "") + `
73724
- Run \`lotics app pull\` to bring this checkout in step.`
73725
- );
73726
- }
73727
72334
  async function appCheck(client, args = {}) {
73728
72335
  const projectDir = path10.resolve(args.projectDir ?? process.cwd());
73729
72336
  const meta3 = readAppMeta(projectDir);
@@ -74669,6 +73276,10 @@ function parseArgs(argv) {
74669
73276
  printCreated: false,
74670
73277
  cleanup: false,
74671
73278
  prune: false,
73279
+ noSampleData: false,
73280
+ adopt: false,
73281
+ entity: [],
73282
+ limit: void 0,
74672
73283
  version: false,
74673
73284
  help: false
74674
73285
  };
@@ -74773,6 +73384,20 @@ function parseArgs(argv) {
74773
73384
  case "--cleanup":
74774
73385
  flags.cleanup = true;
74775
73386
  break;
73387
+ case "--no-sample-data":
73388
+ flags.noSampleData = true;
73389
+ break;
73390
+ case "--adopt":
73391
+ flags.adopt = true;
73392
+ break;
73393
+ // Comma-separated AND repeatable, like `--tags` above: an agent scripting
73394
+ // this reaches for whichever form it knows, and both accumulate.
73395
+ case "--entity":
73396
+ flags.entity = [...flags.entity, ...splitList(argv[++i2])];
73397
+ break;
73398
+ case "--limit":
73399
+ flags.limit = argv[++i2];
73400
+ break;
74776
73401
  case "--prune":
74777
73402
  flags.prune = true;
74778
73403
  break;
@@ -74816,6 +73441,207 @@ function parseArgs(argv) {
74816
73441
  return { command, subcommand, toolArgs, restArgs, flags, unknownFlag };
74817
73442
  }
74818
73443
 
73444
+ // src/starter_commands.ts
73445
+ import fs9 from "node:fs";
73446
+ import path11 from "node:path";
73447
+ import { tmpdir as tmpdir2 } from "node:os";
73448
+ async function starterList(client) {
73449
+ const starters = await client.listStarters();
73450
+ if (starters.length === 0) {
73451
+ console.error(
73452
+ "No starters available to this organization.\n A starter is copyable when Lotics has reviewed it, or when your own organization published it."
73453
+ );
73454
+ return;
73455
+ }
73456
+ const width = Math.max(...starters.map((s) => s.id.length));
73457
+ console.error(`${starters.length} starter${starters.length === 1 ? "" : "s"}:
73458
+ `);
73459
+ for (const s of starters) {
73460
+ const tags = [
73461
+ s.is_official ? "official" : null,
73462
+ s.owned_by_caller === true ? "yours" : null
73463
+ ].filter((t) => t !== null);
73464
+ console.log(
73465
+ ` ${s.id.padEnd(width)} ${s.name}${tags.length > 0 ? ` [${tags.join(", ")}]` : ""}`
73466
+ );
73467
+ if (s.description) console.log(` ${" ".repeat(width)} ${s.description}`);
73468
+ }
73469
+ console.error(`
73470
+ lotics starter init <starter_id> Copy one into this workspace`);
73471
+ }
73472
+ async function starterShow(client, starter_id) {
73473
+ const starter = await client.getPackage(starter_id);
73474
+ console.log(`${starter.name} (${starter.id})`);
73475
+ if (starter.description) console.log(starter.description);
73476
+ console.log(
73477
+ `
73478
+ version ${starter.latest_version}
73479
+ trust ${starter.is_official ? "official \u2014 reviewed by Lotics" : starter.owned_by_caller === true ? "your organization's own" : "not copyable from this organization"}`
73480
+ );
73481
+ if (starter.retired_at !== null) {
73482
+ console.log(`retired ${starter.retired_at} \u2014 can no longer be copied`);
73483
+ }
73484
+ }
73485
+ function reportKnowledgeWarnings(warnings) {
73486
+ const missing = warnings.missing_expected_docs;
73487
+ if (missing.length === 0) return;
73488
+ console.error(
73489
+ `
73490
+ \u26A0 ${missing.length} knowledge doc(s) this starter's agents expect are missing here:
73491
+ ` + missing.map((name2) => ` \u2022 ${name2}`).join("\n") + `
73492
+ An agent declaring one of these reads nothing from it \u2014 the run still completes,
73493
+ answering from nowhere. Create them with those names, or edit the agent.`
73494
+ );
73495
+ }
73496
+ async function starterInit(client, args) {
73497
+ const starter = await client.getPackage(args.starter_id);
73498
+ console.error(
73499
+ `Copying ${starter.name}${starter.is_official ? " (official)" : ""} into this workspace\u2026`
73500
+ );
73501
+ const result = await client.instantiateStarter(args.starter_id, {
73502
+ ...args.noSampleData === true ? { no_sample_data: true } : {},
73503
+ ...args.adopt === true ? { adopt: true } : {}
73504
+ });
73505
+ const entities = Object.keys(result.binding.entities ?? {}).length;
73506
+ const docs = Object.keys(result.binding.knowledge ?? {}).length;
73507
+ const templates = Object.keys(result.binding.templates ?? {}).length;
73508
+ const records = Object.values(result.sample_record_ids).reduce((n, ids) => n + ids.length, 0);
73509
+ console.error(
73510
+ ` Created ${entities} table${entities === 1 ? "" : "s"}, ${templates} template${templates === 1 ? "" : "s"}, ${docs} knowledge doc${docs === 1 ? "" : "s"}, ${records} sample record${records === 1 ? "" : "s"}.`
73511
+ );
73512
+ reportKnowledgeWarnings(result.knowledge_warnings);
73513
+ if (result.app_id === null || result.bundle_url === null) {
73514
+ console.error(`
73515
+ Done. The documents and knowledge are yours to edit \u2014 nothing links back.`);
73516
+ return;
73517
+ }
73518
+ const targetPath = path11.resolve(args.targetPath ?? appDirName(starter.name));
73519
+ if (fs9.existsSync(targetPath) && fs9.readdirSync(targetPath).length > 0) {
73520
+ throw new Error(
73521
+ `Target directory ${targetPath} is not empty. The app (${result.app_id}) was created \u2014 pass an empty path and re-run, or finish it with "lotics app pull ${result.app_id}".`
73522
+ );
73523
+ }
73524
+ fs9.mkdirSync(targetPath, { recursive: true });
73525
+ console.error(`Downloading source\u2026`);
73526
+ const bundleFile = path11.join(tmpdir2(), `lotics-starter-${args.starter_id}-${process.pid}.tar.gz`);
73527
+ const wrapperDir = fs9.mkdtempSync(path11.join(tmpdir2(), `lotics-starter-`));
73528
+ try {
73529
+ await downloadToFile(result.bundle_url, bundleFile);
73530
+ await runTar(["-xzf", bundleFile, "-C", wrapperDir], wrapperDir);
73531
+ const sourceArchive = path11.join(wrapperDir, "source.tar.gz");
73532
+ if (!fs9.existsSync(sourceArchive)) {
73533
+ throw new Error(
73534
+ `Starter bundle carried no source.tar.gz \u2014 the app (${result.app_id}) exists but has no code. Report this to the starter's publisher.`
73535
+ );
73536
+ }
73537
+ await runTar(["-xzf", sourceArchive, "-C", targetPath], targetPath);
73538
+ } finally {
73539
+ if (fs9.existsSync(bundleFile)) fs9.unlinkSync(bundleFile);
73540
+ fs9.rmSync(wrapperDir, { recursive: true, force: true });
73541
+ }
73542
+ for (const dir of ["knowledge", "fixtures"]) {
73543
+ fs9.rmSync(path11.join(targetPath, dir), { recursive: true, force: true });
73544
+ }
73545
+ const app = await client.getApp(result.app_id);
73546
+ const kept = [];
73547
+ await hydrateAppProject(client, targetPath, app, {
73548
+ // Nothing is deployed yet; the build below is what mints v1.
73549
+ stamp: { id: null, number: null },
73550
+ kept
73551
+ });
73552
+ if (starter.owned_by_caller !== true) {
73553
+ console.error(
73554
+ `
73555
+ Building ${starter.name} \u2014 this runs its build on your machine (its package scripts
73556
+ and vite config are the publisher's code, executed as you).${starter.is_official ? " Lotics reviewed this starter." : ""}`
73557
+ );
73558
+ } else {
73559
+ console.error(`Building and deploying\u2026`);
73560
+ }
73561
+ await runNpm(["run", "build"], targetPath);
73562
+ await appDeploy(client, {
73563
+ projectDir: targetPath,
73564
+ message: `Copied from starter ${starter.name}`
73565
+ });
73566
+ let signInUrl = null;
73567
+ try {
73568
+ const link = await client.login({
73569
+ return_link: true,
73570
+ redirect_path: `/apps/${result.app_id}`
73571
+ });
73572
+ signInUrl = link.url ?? null;
73573
+ } catch (error52) {
73574
+ console.error(
73575
+ `
73576
+ (no sign-in link: ${error52 instanceof Error ? error52.message : String(error52)})
73577
+ The copy is complete either way \u2014 open it with "lotics auth web".`
73578
+ );
73579
+ signInUrl = null;
73580
+ }
73581
+ console.error(
73582
+ `
73583
+ Done \u2014 ${starter.name} is live and yours.
73584
+ App: ${result.app_id}
73585
+ Project: ${targetPath}
73586
+
73587
+ Edit anything: the tables, the app source, the templates, the docs. There is no
73588
+ link back to the starter and nothing to upgrade \u2014 this is your app now.
73589
+ Ship a change: cd ${path11.relative(process.cwd(), targetPath) || "."} && lotics app deploy -m "<what changed>"`
73590
+ );
73591
+ if (records > 0) {
73592
+ console.error(
73593
+ `
73594
+ ${records} sample record${records === 1 ? "" : "s"} came with it. They are ordinary records \u2014
73595
+ delete them whenever you like, or re-run with --no-sample-data next time.`
73596
+ );
73597
+ }
73598
+ if (signInUrl !== null) {
73599
+ console.error(
73600
+ `
73601
+ Open it \u2014 one-time sign-in link, expires in 15 minutes:
73602
+ ${signInUrl}`
73603
+ );
73604
+ }
73605
+ }
73606
+ async function starterFixturesCapture(client, args) {
73607
+ const projectDir = path11.resolve(args.projectDir ?? process.cwd());
73608
+ const meta3 = readAppMeta(projectDir);
73609
+ const result = await client.captureStarterFixtures(meta3.app_id, {
73610
+ entities: args.entities,
73611
+ ...args.limit !== void 0 ? { limit: args.limit } : {}
73612
+ });
73613
+ const fixturesDir = path11.join(projectDir, "fixtures");
73614
+ fs9.mkdirSync(fixturesDir, { recursive: true });
73615
+ let totalRows = 0;
73616
+ for (const entry of result.captured) {
73617
+ const file2 = path11.join(projectDir, entry.content_ref);
73618
+ fs9.writeFileSync(file2, `${JSON.stringify(entry.file, null, 2)}
73619
+ `, "utf-8");
73620
+ totalRows += entry.file.rows.length;
73621
+ console.error(
73622
+ ` ${entry.content_ref} \u2014 ${entry.file.rows.length} row${entry.file.rows.length === 1 ? "" : "s"}`
73623
+ );
73624
+ for (const note of entry.notes) console.error(` \u26A0 ${note}`);
73625
+ }
73626
+ if (result.captured.length === 0) {
73627
+ console.error(
73628
+ `This app declares no tables, so there is nothing to capture.
73629
+ Entities available: ${result.available_entity_aliases.join(", ") || "(none)"}`
73630
+ );
73631
+ return;
73632
+ }
73633
+ console.error(
73634
+ `
73635
+ Captured ${totalRows} row${totalRows === 1 ? "" : "s"} across ${result.captured.length} entit${result.captured.length === 1 ? "y" : "ies"}.
73636
+
73637
+ READ WHAT IT WROTE before committing. These rows ship inside the starter and are
73638
+ created in every workspace that copies it \u2014 a real customer name, a real price or a
73639
+ real address captured here is published.
73640
+
73641
+ Entities available: ${result.available_entity_aliases.join(", ")}`
73642
+ );
73643
+ }
73644
+
74819
73645
  // src/inputs.ts
74820
73646
  async function ingestJsonArgs(opts) {
74821
73647
  let raw = opts.rawArg;
@@ -74875,11 +73701,11 @@ async function validateOrgWorkspacePin(client, orgId, profile) {
74875
73701
  }
74876
73702
 
74877
73703
  // src/xlsx.ts
74878
- import fs10 from "node:fs";
73704
+ import fs11 from "node:fs";
74879
73705
 
74880
73706
  // src/file_command_io.ts
74881
- import fs9 from "node:fs";
74882
- import path11 from "node:path";
73707
+ import fs10 from "node:fs";
73708
+ import path12 from "node:path";
74883
73709
  var CliError = class extends Error {
74884
73710
  constructor(message2) {
74885
73711
  super(message2);
@@ -74900,14 +73726,14 @@ function rejectExtraArgs(rest2, arity, usage) {
74900
73726
  fail2(`${usage} takes ${arity} argument${arity === 1 ? "" : "s"} after <file>, got ${rest2.length}. Unused: ${rest2.slice(arity).join(" ")}`);
74901
73727
  }
74902
73728
  function writeFileAtomic(filePath, bytes) {
74903
- const dir = path11.dirname(path11.resolve(filePath));
74904
- const tmp = path11.join(dir, `.${path11.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
74905
- fs9.writeFileSync(tmp, bytes);
73729
+ const dir = path12.dirname(path12.resolve(filePath));
73730
+ const tmp = path12.join(dir, `.${path12.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
73731
+ fs10.writeFileSync(tmp, bytes);
74906
73732
  try {
74907
- fs9.renameSync(tmp, filePath);
73733
+ fs10.renameSync(tmp, filePath);
74908
73734
  } catch (error52) {
74909
73735
  try {
74910
- fs9.unlinkSync(tmp);
73736
+ fs10.unlinkSync(tmp);
74911
73737
  } catch {
74912
73738
  }
74913
73739
  throw error52;
@@ -77704,16 +76530,16 @@ var MatcherView = class {
77704
76530
  * @returns {string|undefined}
77705
76531
  */
77706
76532
  getCurrentTag() {
77707
- const path13 = this._matcher.path;
77708
- return path13.length > 0 ? path13[path13.length - 1].tag : void 0;
76533
+ const path14 = this._matcher.path;
76534
+ return path14.length > 0 ? path14[path14.length - 1].tag : void 0;
77709
76535
  }
77710
76536
  /**
77711
76537
  * Get current namespace.
77712
76538
  * @returns {string|undefined}
77713
76539
  */
77714
76540
  getCurrentNamespace() {
77715
- const path13 = this._matcher.path;
77716
- return path13.length > 0 ? path13[path13.length - 1].namespace : void 0;
76541
+ const path14 = this._matcher.path;
76542
+ return path14.length > 0 ? path14[path14.length - 1].namespace : void 0;
77717
76543
  }
77718
76544
  /**
77719
76545
  * Get current node's attribute value.
@@ -77721,9 +76547,9 @@ var MatcherView = class {
77721
76547
  * @returns {*}
77722
76548
  */
77723
76549
  getAttrValue(attrName) {
77724
- const path13 = this._matcher.path;
77725
- if (path13.length === 0) return void 0;
77726
- return path13[path13.length - 1].values?.[attrName];
76550
+ const path14 = this._matcher.path;
76551
+ if (path14.length === 0) return void 0;
76552
+ return path14[path14.length - 1].values?.[attrName];
77727
76553
  }
77728
76554
  /**
77729
76555
  * Check if current node has an attribute.
@@ -77731,9 +76557,9 @@ var MatcherView = class {
77731
76557
  * @returns {boolean}
77732
76558
  */
77733
76559
  hasAttr(attrName) {
77734
- const path13 = this._matcher.path;
77735
- if (path13.length === 0) return false;
77736
- const current = path13[path13.length - 1];
76560
+ const path14 = this._matcher.path;
76561
+ if (path14.length === 0) return false;
76562
+ const current = path14[path14.length - 1];
77737
76563
  return current.values !== void 0 && attrName in current.values;
77738
76564
  }
77739
76565
  /**
@@ -77759,18 +76585,18 @@ var MatcherView = class {
77759
76585
  * @returns {number}
77760
76586
  */
77761
76587
  getPosition() {
77762
- const path13 = this._matcher.path;
77763
- if (path13.length === 0) return -1;
77764
- return path13[path13.length - 1].position ?? 0;
76588
+ const path14 = this._matcher.path;
76589
+ if (path14.length === 0) return -1;
76590
+ return path14[path14.length - 1].position ?? 0;
77765
76591
  }
77766
76592
  /**
77767
76593
  * Get current node's repeat counter (occurrence count of this tag name).
77768
76594
  * @returns {number}
77769
76595
  */
77770
76596
  getCounter() {
77771
- const path13 = this._matcher.path;
77772
- if (path13.length === 0) return -1;
77773
- return path13[path13.length - 1].counter ?? 0;
76597
+ const path14 = this._matcher.path;
76598
+ if (path14.length === 0) return -1;
76599
+ return path14[path14.length - 1].counter ?? 0;
77774
76600
  }
77775
76601
  /**
77776
76602
  * Get current node's sibling index (alias for getPosition).
@@ -80651,14 +79477,14 @@ function isOle2(bytes) {
80651
79477
  }
80652
79478
  function readCfbStreams(bytes) {
80653
79479
  const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
80654
- const u162 = (o) => dv.getUint16(o, true);
80655
- const u32 = (o) => dv.getUint32(o, true);
80656
- const sectorSize = 1 << u162(30);
80657
- const miniSectorSize = 1 << u162(32);
80658
- const firstDirSector = u32(48);
80659
- const miniCutoff = u32(56);
80660
- const firstMiniFatSector = u32(60);
80661
- const firstDifatSector = u32(68);
79480
+ const u163 = (o) => dv.getUint16(o, true);
79481
+ const u322 = (o) => dv.getUint32(o, true);
79482
+ const sectorSize = 1 << u163(30);
79483
+ const miniSectorSize = 1 << u163(32);
79484
+ const firstDirSector = u322(48);
79485
+ const miniCutoff = u322(56);
79486
+ const firstMiniFatSector = u322(60);
79487
+ const firstDifatSector = u322(68);
80662
79488
  if (sectorSize < 512 || sectorSize > 1 << 20) {
80663
79489
  throw new Error("Unsupported OLE2 file: invalid sector size");
80664
79490
  }
@@ -80666,7 +79492,7 @@ function readCfbStreams(bytes) {
80666
79492
  const maxSectors = Math.ceil(bytes.length / sectorSize) + 1;
80667
79493
  const difat = [];
80668
79494
  for (let i2 = 0; i2 < 109; i2++) {
80669
- const v = u32(76 + i2 * 4);
79495
+ const v = u322(76 + i2 * 4);
80670
79496
  if (v !== FREESECT) difat.push(v);
80671
79497
  }
80672
79498
  let ds = firstDifatSector;
@@ -80676,10 +79502,10 @@ function readCfbStreams(bytes) {
80676
79502
  seenDifat.add(ds);
80677
79503
  const base = sectorOffset(ds);
80678
79504
  for (let i2 = 0; i2 < entriesPerSector - 1; i2++) {
80679
- const v = u32(base + i2 * 4);
79505
+ const v = u322(base + i2 * 4);
80680
79506
  if (v !== FREESECT) difat.push(v);
80681
79507
  }
80682
- ds = u32(base + (entriesPerSector - 1) * 4);
79508
+ ds = u322(base + (entriesPerSector - 1) * 4);
80683
79509
  }
80684
79510
  const fat = [];
80685
79511
  for (const fatSector of difat) {
@@ -80687,7 +79513,7 @@ function readCfbStreams(bytes) {
80687
79513
  if (fatSector >= maxSectors) continue;
80688
79514
  const base = sectorOffset(fatSector);
80689
79515
  for (let i2 = 0; i2 < entriesPerSector && fat.length < maxSectors; i2++) {
80690
- fat.push(u32(base + i2 * 4));
79516
+ fat.push(u322(base + i2 * 4));
80691
79517
  }
80692
79518
  }
80693
79519
  const readChain = (src, start, size2, ss, offOf, chain2) => {
@@ -83428,10 +82254,10 @@ function resolveRelativePath(basePath, relativePath) {
83428
82254
  }
83429
82255
  return resolved.join("/");
83430
82256
  }
83431
- function findZipEntry(zipEntries, path13) {
83432
- if (zipEntries[path13]) return zipEntries[path13];
83433
- if (zipEntries[`xl/${path13}`]) return zipEntries[`xl/${path13}`];
83434
- const noSlash = path13.replace(/^\//, "");
82257
+ function findZipEntry(zipEntries, path14) {
82258
+ if (zipEntries[path14]) return zipEntries[path14];
82259
+ if (zipEntries[`xl/${path14}`]) return zipEntries[`xl/${path14}`];
82260
+ const noSlash = path14.replace(/^\//, "");
83435
82261
  if (zipEntries[noSlash]) return zipEntries[noSlash];
83436
82262
  return void 0;
83437
82263
  }
@@ -84547,6 +83373,221 @@ function ensureVmlArray(val) {
84547
83373
  return Array.isArray(val) ? val : [val];
84548
83374
  }
84549
83375
 
83376
+ // ../xlsx/src/biff8_styles.ts
83377
+ var DEFAULT_PALETTE = [
83378
+ "#000000",
83379
+ "#FFFFFF",
83380
+ "#FF0000",
83381
+ "#00FF00",
83382
+ "#0000FF",
83383
+ "#FFFF00",
83384
+ "#FF00FF",
83385
+ "#00FFFF",
83386
+ "#000000",
83387
+ "#FFFFFF",
83388
+ "#FF0000",
83389
+ "#00FF00",
83390
+ "#0000FF",
83391
+ "#FFFF00",
83392
+ "#FF00FF",
83393
+ "#00FFFF",
83394
+ "#800000",
83395
+ "#008000",
83396
+ "#000080",
83397
+ "#808000",
83398
+ "#800080",
83399
+ "#008080",
83400
+ "#C0C0C0",
83401
+ "#808080",
83402
+ "#9999FF",
83403
+ "#993366",
83404
+ "#FFFFCC",
83405
+ "#CCFFFF",
83406
+ "#660066",
83407
+ "#FF8080",
83408
+ "#0066CC",
83409
+ "#CCCCFF",
83410
+ "#000080",
83411
+ "#FF00FF",
83412
+ "#FFFF00",
83413
+ "#00FFFF",
83414
+ "#800080",
83415
+ "#800000",
83416
+ "#008080",
83417
+ "#0000FF",
83418
+ "#00CCFF",
83419
+ "#CCFFFF",
83420
+ "#CCFFCC",
83421
+ "#FFFF99",
83422
+ "#99CCFF",
83423
+ "#FF99CC",
83424
+ "#CC99FF",
83425
+ "#FFCC99",
83426
+ "#3366FF",
83427
+ "#33CCCC",
83428
+ "#99CC00",
83429
+ "#FFCC00",
83430
+ "#FF9900",
83431
+ "#FF6600",
83432
+ "#666699",
83433
+ "#969696",
83434
+ "#003366",
83435
+ "#339966",
83436
+ "#003300",
83437
+ "#333300",
83438
+ "#993300",
83439
+ "#993366",
83440
+ "#333399",
83441
+ "#333333"
83442
+ ];
83443
+ var AUTOMATIC = /* @__PURE__ */ new Set([64, 65, 32767]);
83444
+ var u162 = (b, o) => b[o] | b[o + 1] << 8;
83445
+ var u32 = (b, o) => (u162(b, o) | u162(b, o + 2) << 16) >>> 0;
83446
+ function parsePalette(body) {
83447
+ const palette = [...DEFAULT_PALETTE];
83448
+ const count = u162(body, 0);
83449
+ for (let i2 = 0; i2 < count && 2 + i2 * 4 + 3 < body.length; i2++) {
83450
+ const o = 2 + i2 * 4;
83451
+ const hex3 = (n) => n.toString(16).padStart(2, "0").toUpperCase();
83452
+ palette[8 + i2] = `#${hex3(body[o])}${hex3(body[o + 1])}${hex3(body[o + 2])}`;
83453
+ }
83454
+ return palette;
83455
+ }
83456
+ function defaultPalette() {
83457
+ return [...DEFAULT_PALETTE];
83458
+ }
83459
+ function parseFont2(body) {
83460
+ const grbit = u162(body, 2);
83461
+ const uls = body[10];
83462
+ const sss = u162(body, 8);
83463
+ let name2 = "";
83464
+ if (body.length > 15) {
83465
+ const cch = body[14];
83466
+ const high = (body[15] & 1) !== 0;
83467
+ for (let i2 = 0; i2 < cch; i2++) {
83468
+ const o = 16 + (high ? i2 * 2 : i2);
83469
+ if (o >= body.length) break;
83470
+ name2 += String.fromCharCode(high ? body[o] | body[o + 1] << 8 : body[o]);
83471
+ }
83472
+ }
83473
+ return {
83474
+ size: u162(body, 0) / 20,
83475
+ bold: u162(body, 6) >= 600,
83476
+ italic: (grbit & 2) !== 0,
83477
+ strike: (grbit & 8) !== 0,
83478
+ underline: uls === 1 || uls === 33 ? "single" : uls === 2 || uls === 34 ? "double" : void 0,
83479
+ vertAlign: sss === 1 ? "superscript" : sss === 2 ? "subscript" : void 0,
83480
+ colorIndex: u162(body, 4),
83481
+ name: name2
83482
+ };
83483
+ }
83484
+ function parseXf2(body) {
83485
+ const alignByte = body[6] ?? 0;
83486
+ const indentByte = body[8] ?? 0;
83487
+ const b1 = u32(body, 10);
83488
+ const b22 = u32(body, 14);
83489
+ const fill = u162(body, 18);
83490
+ const HORIZ = [
83491
+ void 0,
83492
+ "left",
83493
+ "center",
83494
+ "right",
83495
+ void 0,
83496
+ void 0,
83497
+ "center"
83498
+ ];
83499
+ const VERT = ["top", "middle", "bottom", "middle", "middle"];
83500
+ const rot = body[7] ?? 0;
83501
+ return {
83502
+ fontIndex: u162(body, 0),
83503
+ horizontal: HORIZ[alignByte & 7],
83504
+ vertical: VERT[alignByte >> 4 & 7],
83505
+ wrap: (alignByte & 8) !== 0,
83506
+ shrink: (indentByte & 16) !== 0,
83507
+ indent: indentByte & 15,
83508
+ // 0–90 means degrees; 91–180 means −1…−90; 255 is stacked/vertical text.
83509
+ rotation: rot === 255 ? 255 : rot <= 90 ? rot : -(rot - 90),
83510
+ borders: {
83511
+ left: b1 & 15,
83512
+ right: b1 >> 4 & 15,
83513
+ top: b1 >> 8 & 15,
83514
+ bottom: b1 >> 12 & 15,
83515
+ leftColor: b1 >> 16 & 127,
83516
+ rightColor: b1 >> 23 & 127,
83517
+ topColor: b22 & 127,
83518
+ bottomColor: b22 >> 7 & 127
83519
+ },
83520
+ fillPattern: b22 >>> 26 & 63,
83521
+ fillFore: fill & 127,
83522
+ fillBack: fill >> 7 & 127
83523
+ };
83524
+ }
83525
+ var BORDER_STYLES = [
83526
+ "none",
83527
+ "thin",
83528
+ "medium",
83529
+ "dashed",
83530
+ "dotted",
83531
+ "thick",
83532
+ "double",
83533
+ "hair",
83534
+ "mediumDashed",
83535
+ "dashDot",
83536
+ "mediumDashDot",
83537
+ "dashDotDot",
83538
+ "mediumDashDotDot",
83539
+ "slantDashDot"
83540
+ ];
83541
+ var BORDER_WIDTH = { thick: 3, medium: 2, mediumDashed: 2, mediumDashDot: 2, mediumDashDotDot: 2, double: 3, hair: 1 };
83542
+ function colorOf(index, palette) {
83543
+ if (AUTOMATIC.has(index)) return void 0;
83544
+ return palette[index];
83545
+ }
83546
+ function borderOf(style, colorIndex, palette) {
83547
+ if (style === 0) return void 0;
83548
+ const name2 = BORDER_STYLES[style] ?? "thin";
83549
+ return { width: BORDER_WIDTH[name2] ?? 1, style: name2, color: colorOf(colorIndex, palette) ?? "#000000" };
83550
+ }
83551
+ function toCellStyle(xf, fonts, palette) {
83552
+ const style = {};
83553
+ const font = fonts[xf.fontIndex];
83554
+ if (font) {
83555
+ if (font.bold) style.fontBold = true;
83556
+ if (font.italic) style.fontItalic = true;
83557
+ if (font.strike) style.fontStrike = true;
83558
+ if (font.underline) style.fontUnderline = font.underline;
83559
+ if (font.vertAlign) style.fontVertAlign = font.vertAlign;
83560
+ if (font.size > 0) style.fontSize = font.size;
83561
+ if (font.name) style.fontName = font.name;
83562
+ const color = colorOf(font.colorIndex, palette);
83563
+ if (color) style.fontColor = color;
83564
+ }
83565
+ if (xf.horizontal) style.horizontalAlign = xf.horizontal;
83566
+ if (xf.vertical) style.verticalAlign = xf.vertical;
83567
+ if (xf.wrap) style.wrapText = true;
83568
+ if (xf.shrink) style.shrinkToFit = true;
83569
+ if (xf.indent > 0) style.indent = xf.indent;
83570
+ if (xf.rotation === 255) style.textRotation = "vertical";
83571
+ else if (xf.rotation !== 0) style.textRotation = xf.rotation;
83572
+ const left = borderOf(xf.borders.left, xf.borders.leftColor, palette);
83573
+ const right = borderOf(xf.borders.right, xf.borders.rightColor, palette);
83574
+ const top = borderOf(xf.borders.top, xf.borders.topColor, palette);
83575
+ const bottom = borderOf(xf.borders.bottom, xf.borders.bottomColor, palette);
83576
+ if (left) style.borderLeft = left;
83577
+ if (right) style.borderRight = right;
83578
+ if (top) style.borderTop = top;
83579
+ if (bottom) style.borderBottom = bottom;
83580
+ if (xf.fillPattern === 1) {
83581
+ const bg = colorOf(xf.fillFore, palette);
83582
+ if (bg) style.backgroundColor = bg;
83583
+ } else if (xf.fillPattern > 1) {
83584
+ const bg = colorOf(xf.fillBack, palette);
83585
+ if (bg) style.backgroundColor = bg;
83586
+ style.patternType = "gray125";
83587
+ }
83588
+ return style;
83589
+ }
83590
+
84550
83591
  // ../xlsx/src/biff8_reader.ts
84551
83592
  var DEFAULT_MAX_ROWS = 1e4;
84552
83593
  var REC = {
@@ -84568,7 +83609,12 @@ var REC = {
84568
83609
  MULBLANK: 190,
84569
83610
  LABELSST: 253,
84570
83611
  SST: 252,
84571
- BOF: 2057
83612
+ BOF: 2057,
83613
+ DEFCOLWIDTH: 85,
83614
+ COLINFO: 125,
83615
+ FONT: 49,
83616
+ PALETTE: 146,
83617
+ ROW: 520
84572
83618
  };
84573
83619
  function* iterRecords(stream, from, to) {
84574
83620
  const dv = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
@@ -84586,6 +83632,9 @@ function parseGlobals(stream) {
84586
83632
  const sstChunks = [];
84587
83633
  const formats = /* @__PURE__ */ new Map();
84588
83634
  const xfFormatIds = [];
83635
+ const xfRecords = [];
83636
+ const fonts = [];
83637
+ let palette = null;
84589
83638
  const boundsheets = [];
84590
83639
  let date1904 = false;
84591
83640
  let sawSst = false;
@@ -84629,8 +83678,17 @@ function parseGlobals(stream) {
84629
83678
  }
84630
83679
  case REC.XF: {
84631
83680
  xfFormatIds.push(readU16(r.body, 2));
83681
+ xfRecords.push(r.body.slice());
83682
+ break;
83683
+ }
83684
+ case REC.FONT: {
83685
+ fonts.push(parseFont2(r.body));
83686
+ if (fonts.length === 4) fonts.push(fonts[3]);
84632
83687
  break;
84633
83688
  }
83689
+ case REC.PALETTE:
83690
+ palette = parsePalette(r.body);
83691
+ break;
84634
83692
  case REC.BOUNDSHEET: {
84635
83693
  const pos = dv.getUint32(r.offset + 4, true);
84636
83694
  boundsheets.push({ name: readUnicodeShort(r.body, 6, 1), pos });
@@ -84642,7 +83700,9 @@ function parseGlobals(stream) {
84642
83700
  }
84643
83701
  const sst = parseSst(sstChunks, sstUnique);
84644
83702
  const xfFormats = xfFormatIds.map((id) => formats.get(id) ?? builtinFormat(id));
84645
- return { sst, date1904, xfFormats, boundsheets };
83703
+ const pal = palette ?? defaultPalette();
83704
+ const xfStyles = xfRecords.map((body) => toCellStyle(parseXf2(body), fonts, pal));
83705
+ return { sst, date1904, xfFormats, xfStyles, boundsheets };
84646
83706
  }
84647
83707
  function parseSst(chunks, count) {
84648
83708
  const out = [];
@@ -84727,26 +83787,55 @@ function parseSheet2(stream, start, name2, g, maxRows) {
84727
83787
  break;
84728
83788
  }
84729
83789
  }
83790
+ const colDefs = /* @__PURE__ */ new Map();
83791
+ const rowHeights = /* @__PURE__ */ new Map();
83792
+ const hiddenRows = /* @__PURE__ */ new Set();
84730
83793
  for (const r of iterRecords(stream, start, end)) {
84731
83794
  switch (r.type) {
83795
+ case REC.DEFCOLWIDTH: {
83796
+ sheet.defaultColWidth = readU16(r.body, 0);
83797
+ break;
83798
+ }
83799
+ case REC.COLINFO: {
83800
+ const first3 = readU16(r.body, 0), last3 = readU16(r.body, 2);
83801
+ const width = readU16(r.body, 4) / 256;
83802
+ const grbit = readU16(r.body, 8);
83803
+ const hidden = (grbit & 1) !== 0;
83804
+ const outline = grbit >> 8 & 7;
83805
+ for (let c = first3; c <= last3 && c <= 255; c++) {
83806
+ colDefs.set(c, { index: c + 1, width, hidden, customWidth: true });
83807
+ if (outline > 0) sheet.colOutlineLevels.set(c + 1, outline);
83808
+ }
83809
+ break;
83810
+ }
83811
+ case REC.ROW: {
83812
+ const row = readU16(r.body, 0);
83813
+ const grbit = readU16(r.body, 12);
83814
+ const height = (readU16(r.body, 6) & 32767) / 20;
83815
+ if (height > 0) rowHeights.set(row, height);
83816
+ if ((grbit & 32) !== 0) hiddenRows.add(row);
83817
+ const outline = grbit & 7;
83818
+ if (outline > 0) sheet.rowOutlineLevels.set(row + 1, outline);
83819
+ break;
83820
+ }
84732
83821
  case REC.LABELSST: {
84733
- const row = readU16(r.body, 0), col = readU16(r.body, 2), isst = readU32(r.body, 6);
84734
- put(row, col, textCell(col, g.sst[isst] ?? ""));
83822
+ const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4), isst = readU32(r.body, 6);
83823
+ put(row, col, textCell(col, g.sst[isst] ?? "", g.xfStyles[xf]));
84735
83824
  break;
84736
83825
  }
84737
83826
  case REC.LABEL: {
84738
- const row = readU16(r.body, 0), col = readU16(r.body, 2);
84739
- put(row, col, textCell(col, readUnicodeShort(r.body, 6, 2)));
83827
+ const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
83828
+ put(row, col, textCell(col, readUnicodeShort(r.body, 6, 2), g.xfStyles[xf]));
84740
83829
  break;
84741
83830
  }
84742
83831
  case REC.NUMBER: {
84743
83832
  const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
84744
- put(row, col, numberCell(col, readF64(r.body, 6), g.xfFormats[xf]));
83833
+ put(row, col, numberCell(col, readF64(r.body, 6), g.xfFormats[xf], g.xfStyles[xf]));
84745
83834
  break;
84746
83835
  }
84747
83836
  case REC.RK: {
84748
83837
  const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
84749
- put(row, col, numberCell(col, decodeRk(readU32(r.body, 6)), g.xfFormats[xf]));
83838
+ put(row, col, numberCell(col, decodeRk(readU32(r.body, 6)), g.xfFormats[xf], g.xfStyles[xf]));
84750
83839
  break;
84751
83840
  }
84752
83841
  case REC.MULRK: {
@@ -84755,13 +83844,13 @@ function parseSheet2(stream, start, name2, g, maxRows) {
84755
83844
  for (let i2 = 0; i2 < n; i2++) {
84756
83845
  const xf = readU16(r.body, 4 + i2 * 6);
84757
83846
  const rk = readU32(r.body, 6 + i2 * 6);
84758
- put(row, first3 + i2, numberCell(first3 + i2, decodeRk(rk), g.xfFormats[xf]));
83847
+ put(row, first3 + i2, numberCell(first3 + i2, decodeRk(rk), g.xfFormats[xf], g.xfStyles[xf]));
84759
83848
  }
84760
83849
  break;
84761
83850
  }
84762
83851
  case REC.FORMULA: {
84763
83852
  const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
84764
- const cell = formulaCell(col, r.body, g.xfFormats[xf]);
83853
+ const cell = formulaCell(col, r.body, g.xfFormats[xf], g.xfStyles[xf]);
84765
83854
  if (cell) put(row, col, cell);
84766
83855
  break;
84767
83856
  }
@@ -84775,17 +83864,23 @@ function parseSheet2(stream, start, name2, g, maxRows) {
84775
83864
  const r = grid.get(ri);
84776
83865
  if (!r) continue;
84777
83866
  const cells = [...r.values()].sort((a, b) => a.column - b.column);
84778
- rows.push({ index: ri + 1, height: sheet.defaultRowHeight, cells, hidden: false });
83867
+ rows.push({
83868
+ index: ri + 1,
83869
+ height: rowHeights.get(ri) ?? sheet.defaultRowHeight,
83870
+ cells,
83871
+ hidden: hiddenRows.has(ri)
83872
+ });
84779
83873
  }
84780
83874
  sheet.rows = rows;
83875
+ sheet.columns = [...colDefs.values()].sort((a, b) => a.index - b.index);
84781
83876
  sheet.totalRowCount = maxRow + 1;
84782
83877
  sheet.truncated = truncated;
84783
83878
  return sheet;
84784
83879
  }
84785
- function textCell(column, text) {
84786
- return { column: column + 1, value: text, typedValue: text, content: { type: "plain", text }, style: {} };
83880
+ function textCell(column, text, style = {}) {
83881
+ return { column: column + 1, value: text, typedValue: text, content: { type: "plain", text }, style };
84787
83882
  }
84788
- function numberCell(column, num3, numFmt) {
83883
+ function numberCell(column, num3, numFmt, style = {}) {
84789
83884
  const value2 = Number.isFinite(num3) ? String(num3) : "";
84790
83885
  return {
84791
83886
  column: column + 1,
@@ -84794,19 +83889,19 @@ function numberCell(column, num3, numFmt) {
84794
83889
  typedValue: num3,
84795
83890
  numFmtCode: numFmt && numFmt !== "General" ? numFmt : void 0,
84796
83891
  content: { type: "plain", text: value2 },
84797
- style: {}
83892
+ style
84798
83893
  };
84799
83894
  }
84800
- function formulaCell(column, body, numFmt) {
83895
+ function formulaCell(column, body, numFmt, style = {}) {
84801
83896
  if (readU16(body, 12) === 65535) {
84802
83897
  const kind = body[6];
84803
83898
  if (kind === 1) {
84804
83899
  const b = body[8] !== 0;
84805
- return { column: column + 1, value: b ? "TRUE" : "FALSE", typedValue: b, content: { type: "plain", text: b ? "TRUE" : "FALSE" }, style: {} };
83900
+ return { column: column + 1, value: b ? "TRUE" : "FALSE", typedValue: b, content: { type: "plain", text: b ? "TRUE" : "FALSE" }, style };
84806
83901
  }
84807
83902
  return null;
84808
83903
  }
84809
- return numberCell(column, readF64(body, 6), numFmt);
83904
+ return numberCell(column, readF64(body, 6), numFmt, style);
84810
83905
  }
84811
83906
  function decodeRk(rk) {
84812
83907
  const div100 = (rk & 1) !== 0;
@@ -85063,9 +84158,9 @@ function parseExcelFromZip(zip, options) {
85063
84158
  }
85064
84159
  return result;
85065
84160
  }
85066
- function findEntry(zip, path13) {
85067
- if (zip[path13]) return zip[path13];
85068
- const lower2 = path13.toLowerCase();
84161
+ function findEntry(zip, path14) {
84162
+ if (zip[path14]) return zip[path14];
84163
+ const lower2 = path14.toLowerCase();
85069
84164
  for (const key of Object.keys(zip)) {
85070
84165
  if (key.toLowerCase() === lower2) return zip[key];
85071
84166
  }
@@ -85702,12 +84797,12 @@ function extractPivotRoundTripInfo(originalZip) {
85702
84797
  if (paths.length > 0) pivotTablesBySheetIndex.set(i2, paths);
85703
84798
  }
85704
84799
  const pivotXmlPaths = [];
85705
- for (const path13 of Object.keys(originalZip)) {
85706
- if (path13.startsWith("xl/pivotTables/") && path13.endsWith(".xml")) {
85707
- pivotXmlPaths.push(path13);
84800
+ for (const path14 of Object.keys(originalZip)) {
84801
+ if (path14.startsWith("xl/pivotTables/") && path14.endsWith(".xml")) {
84802
+ pivotXmlPaths.push(path14);
85708
84803
  }
85709
- if (path13.startsWith("xl/pivotCache/") && path13.endsWith(".xml")) {
85710
- pivotXmlPaths.push(path13);
84804
+ if (path14.startsWith("xl/pivotCache/") && path14.endsWith(".xml")) {
84805
+ pivotXmlPaths.push(path14);
85711
84806
  }
85712
84807
  }
85713
84808
  return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths };
@@ -85715,15 +84810,15 @@ function extractPivotRoundTripInfo(originalZip) {
85715
84810
  function decode3(bytes) {
85716
84811
  return new TextDecoder().decode(bytes);
85717
84812
  }
85718
- function pivotContentTypeFor(path13) {
85719
- if (path13.startsWith("xl/pivotTables/") && path13.endsWith(".xml")) {
85720
- return `<Override PartName="/${path13}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
84813
+ function pivotContentTypeFor(path14) {
84814
+ if (path14.startsWith("xl/pivotTables/") && path14.endsWith(".xml")) {
84815
+ return `<Override PartName="/${path14}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
85721
84816
  }
85722
- if (path13.includes("/pivotCacheDefinition") && path13.endsWith(".xml")) {
85723
- return `<Override PartName="/${path13}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
84817
+ if (path14.includes("/pivotCacheDefinition") && path14.endsWith(".xml")) {
84818
+ return `<Override PartName="/${path14}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
85724
84819
  }
85725
- if (path13.includes("/pivotCacheRecords") && path13.endsWith(".xml")) {
85726
- return `<Override PartName="/${path13}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
84820
+ if (path14.includes("/pivotCacheRecords") && path14.endsWith(".xml")) {
84821
+ return `<Override PartName="/${path14}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
85727
84822
  }
85728
84823
  return void 0;
85729
84824
  }
@@ -85796,16 +84891,16 @@ function exportWorkbook(workbook, originalZip) {
85796
84891
  regeneratedPaths.add(`xl/worksheets/sheet${i2 + 1}.xml`);
85797
84892
  regeneratedPaths.add(`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`);
85798
84893
  }
85799
- for (const path13 of Object.keys(originalZip)) {
85800
- if (path13.startsWith("xl/drawings/") || path13.startsWith("xl/charts/") || path13.startsWith("xl/tables/") || path13.startsWith("xl/media/")) {
85801
- regeneratedPaths.add(path13);
84894
+ for (const path14 of Object.keys(originalZip)) {
84895
+ if (path14.startsWith("xl/drawings/") || path14.startsWith("xl/charts/") || path14.startsWith("xl/tables/") || path14.startsWith("xl/media/")) {
84896
+ regeneratedPaths.add(path14);
85802
84897
  }
85803
84898
  }
85804
- for (const [path13, data2] of Object.entries(originalZip)) {
85805
- if (regeneratedPaths.has(path13)) continue;
85806
- const ext = path13.slice(path13.lastIndexOf(".") + 1).toLowerCase();
84899
+ for (const [path14, data2] of Object.entries(originalZip)) {
84900
+ if (regeneratedPaths.has(path14)) continue;
84901
+ const ext = path14.slice(path14.lastIndexOf(".") + 1).toLowerCase();
85807
84902
  if (!DECLARED_EXTENSIONS.includes(ext)) continue;
85808
- entries2[path13] = data2;
84903
+ entries2[path14] = data2;
85809
84904
  }
85810
84905
  }
85811
84906
  const sharedStrings = buildSharedStrings(workbook);
@@ -85821,8 +84916,8 @@ function exportWorkbook(workbook, originalZip) {
85821
84916
  buildWorkbookRels(workbook, pivotInfo)
85822
84917
  );
85823
84918
  const extraContentTypes = [];
85824
- for (const path13 of pivotInfo.pivotXmlPaths) {
85825
- const ct = pivotContentTypeFor(path13);
84919
+ for (const path14 of pivotInfo.pivotXmlPaths) {
84920
+ const ct = pivotContentTypeFor(path14);
85826
84921
  if (ct) extraContentTypes.push(ct);
85827
84922
  }
85828
84923
  let globalChartIndex = 1;
@@ -95008,14 +94103,14 @@ var DependencyGraph = class {
95008
94103
  stack.push({ cell: p, path: [cell, p] });
95009
94104
  }
95010
94105
  while (stack.length > 0) {
95011
- const { cell: current, path: path13 } = stack.pop();
95012
- if (current === cell || originCoarse.has(current)) return path13;
94106
+ const { cell: current, path: path14 } = stack.pop();
94107
+ if (current === cell || originCoarse.has(current)) return path14;
95013
94108
  if (visited.has(current)) continue;
95014
94109
  visited.add(current);
95015
94110
  const nextPrec = this.precedents.get(current);
95016
94111
  if (!nextPrec) continue;
95017
94112
  for (const p of nextPrec) {
95018
- stack.push({ cell: p, path: [...path13, p] });
94113
+ stack.push({ cell: p, path: [...path14, p] });
95019
94114
  }
95020
94115
  }
95021
94116
  return null;
@@ -96461,8 +95556,8 @@ var SIMPLE_SHEET_KEYS = /* @__PURE__ */ new Set(["name", "cells", "merges", "fre
96461
95556
  var MAX_COLUMN = 16384;
96462
95557
  var MAX_ROW = 1048576;
96463
95558
  function loadFile(filePath) {
96464
- if (!fs10.existsSync(filePath)) fail2(`File not found: ${filePath}`);
96465
- const buffer = fs10.readFileSync(filePath);
95559
+ if (!fs11.existsSync(filePath)) fail2(`File not found: ${filePath}`);
95560
+ const buffer = fs11.readFileSync(filePath);
96466
95561
  const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
96467
95562
  const originalZip = unzipXlsx(arrayBuffer);
96468
95563
  const parsed = parseExcelBuffer(arrayBuffer);
@@ -96512,7 +95607,7 @@ function lazyEngine(workbook) {
96512
95607
  };
96513
95608
  }
96514
95609
  function readToJson(filePath, filter3, opts) {
96515
- const buffer = fs10.readFileSync(filePath);
95610
+ const buffer = fs11.readFileSync(filePath);
96516
95611
  const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
96517
95612
  const parsed = parseExcelBuffer(arrayBuffer);
96518
95613
  let sheets = parsed.sheets;
@@ -97025,7 +96120,7 @@ async function runXlsxCommand(subcommand, toolArgs, restArgs) {
97025
96120
  }
97026
96121
 
97027
96122
  // src/docx.ts
97028
- import fs11 from "node:fs";
96123
+ import fs12 from "node:fs";
97029
96124
 
97030
96125
  // ../ooxml/src/doc/errors.ts
97031
96126
  var DocParseError = class extends Error {
@@ -101854,8 +100949,8 @@ async function docModelToDocx(model) {
101854
100949
  // ../ooxml/src/opc.ts
101855
100950
  var import_jszip = __toESM(require_lib4(), 1);
101856
100951
  function dropFolderEntries(zip) {
101857
- for (const [path13, entry] of Object.entries(zip.files)) {
101858
- if (entry.dir) delete zip.files[path13];
100952
+ for (const [path14, entry] of Object.entries(zip.files)) {
100953
+ if (entry.dir) delete zip.files[path14];
101859
100954
  }
101860
100955
  }
101861
100956
 
@@ -102110,11 +101205,11 @@ async function parseDocx(buffer) {
102110
101205
  const zip = await import_jszip3.default.loadAsync(buffer);
102111
101206
  const parts = /* @__PURE__ */ new Map();
102112
101207
  const filePromises = [];
102113
- zip.forEach((path13, file2) => {
101208
+ zip.forEach((path14, file2) => {
102114
101209
  if (file2.dir) return;
102115
101210
  filePromises.push(
102116
101211
  file2.async("uint8array").then((bytes) => {
102117
- parts.set(path13, bytes);
101212
+ parts.set(path14, bytes);
102118
101213
  })
102119
101214
  );
102120
101215
  });
@@ -102346,9 +101441,9 @@ var DEFAULT_PARTS = [
102346
101441
  ["word/theme/theme1.xml", () => encoder.encode(THEME_XML)]
102347
101442
  ];
102348
101443
  function fillDefaultParts(parts) {
102349
- for (const [path13, makeBytes] of DEFAULT_PARTS) {
102350
- if (!parts.has(path13)) {
102351
- parts.set(path13, makeBytes());
101444
+ for (const [path14, makeBytes] of DEFAULT_PARTS) {
101445
+ if (!parts.has(path14)) {
101446
+ parts.set(path14, makeBytes());
102352
101447
  }
102353
101448
  }
102354
101449
  return parts;
@@ -102358,9 +101453,9 @@ function fillDefaultParts(parts) {
102358
101453
  async function serializeDocx(doc) {
102359
101454
  const zip = new import_jszip4.default();
102360
101455
  const parts = fillDefaultParts(new Map(doc.parts));
102361
- for (const [path13, bytes] of parts) {
102362
- if (path13 === "word/document.xml") continue;
102363
- zip.file(path13, bytes);
101456
+ for (const [path14, bytes] of parts) {
101457
+ if (path14 === "word/document.xml") continue;
101458
+ zip.file(path14, bytes);
102364
101459
  }
102365
101460
  const documentXml = serializeDocumentXml(doc);
102366
101461
  zip.file("word/document.xml", documentXml);
@@ -102447,8 +101542,8 @@ var DEFAULT_DOC_ATTRS = {
102447
101542
  "@_xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
102448
101543
  };
102449
101544
  async function loadFile2(filePath) {
102450
- if (!fs11.existsSync(filePath)) fail2(`File not found: ${filePath}`);
102451
- const bytes = fs11.readFileSync(filePath);
101545
+ if (!fs12.existsSync(filePath)) fail2(`File not found: ${filePath}`);
101546
+ const bytes = fs12.readFileSync(filePath);
102452
101547
  if (isLegacyDoc(bytes)) {
102453
101548
  const upgraded = await saveDocxToBuffer(await loadDocxFromBuffer(bytes));
102454
101549
  return parseDocx(new Uint8Array(upgraded));
@@ -102933,7 +102028,7 @@ async function runDocxCommand(subcommand, toolArgs, restArgs) {
102933
102028
  }
102934
102029
 
102935
102030
  // src/knowledge.ts
102936
- import fs12 from "node:fs";
102031
+ import fs13 from "node:fs";
102937
102032
 
102938
102033
  // ../shared/src/knowledge_tags.ts
102939
102034
  function isHiddenDoc(doc) {
@@ -102942,8 +102037,8 @@ function isHiddenDoc(doc) {
102942
102037
 
102943
102038
  // src/knowledge.ts
102944
102039
  function readBodyFile(filePath) {
102945
- if (!fs12.existsSync(filePath)) fail2(`File not found: ${filePath}`);
102946
- return fs12.readFileSync(filePath, "utf-8");
102040
+ if (!fs13.existsSync(filePath)) fail2(`File not found: ${filePath}`);
102041
+ return fs13.readFileSync(filePath, "utf-8");
102947
102042
  }
102948
102043
  function resolveBody(flags, required2) {
102949
102044
  if (flags.from !== void 0 && flags.content !== void 0) {
@@ -103152,7 +102247,7 @@ async function runKnowledgeCommand(client, subcommand, toolArgs, flags, restArgs
103152
102247
  import { spawn as spawn3 } from "node:child_process";
103153
102248
  import { createServer } from "node:http";
103154
102249
  import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdtempSync, rmSync, readdirSync } from "node:fs";
103155
- import { tmpdir as tmpdir2 } from "node:os";
102250
+ import { tmpdir as tmpdir3 } from "node:os";
103156
102251
  import { join as join2, dirname, resolve, extname, basename } from "node:path";
103157
102252
  import { fileURLToPath as fileURLToPath3 } from "node:url";
103158
102253
  import { setTimeout as sleep } from "node:timers/promises";
@@ -103251,7 +102346,7 @@ async function runPreviewCommand(filePath, flags) {
103251
102346
  });
103252
102347
  await new Promise((r) => server.listen(0, "127.0.0.1", () => r()));
103253
102348
  const httpPort = server.address().port;
103254
- const udd = mkdtempSync(join2(tmpdir2(), "lotics-render-"));
102349
+ const udd = mkdtempSync(join2(tmpdir3(), "lotics-render-"));
103255
102350
  const child = spawn3(chrome, [
103256
102351
  "--headless=new",
103257
102352
  "--disable-gpu",
@@ -103491,8 +102586,8 @@ function prompt(question) {
103491
102586
  });
103492
102587
  });
103493
102588
  }
103494
- async function publicPost(path13, body) {
103495
- const response = await fetch(`${API_BASE_URL}${path13}`, {
102589
+ async function publicPost(path14, body) {
102590
+ const response = await fetch(`${API_BASE_URL}${path14}`, {
103496
102591
  method: "POST",
103497
102592
  headers: { "Content-Type": "application/json" },
103498
102593
  body: JSON.stringify(body)
@@ -103660,13 +102755,13 @@ async function resolveWorkspace(client, ctx) {
103660
102755
  function resolveUploadPaths(rawPaths) {
103661
102756
  const result = [];
103662
102757
  for (const p of rawPaths) {
103663
- const resolved = path12.resolve(p);
103664
- const stat = fs13.statSync(resolved);
102758
+ const resolved = path13.resolve(p);
102759
+ const stat = fs14.statSync(resolved);
103665
102760
  if (stat.isDirectory()) {
103666
- const entries2 = fs13.readdirSync(resolved, { withFileTypes: true });
102761
+ const entries2 = fs14.readdirSync(resolved, { withFileTypes: true });
103667
102762
  for (const entry of entries2) {
103668
102763
  if (entry.isFile()) {
103669
- result.push(path12.join(resolved, entry.name));
102764
+ result.push(path13.join(resolved, entry.name));
103670
102765
  }
103671
102766
  }
103672
102767
  } else {
@@ -103715,23 +102810,69 @@ async function main() {
103715
102810
  console.log(VERSION);
103716
102811
  return;
103717
102812
  }
103718
- if (command === "install") {
103719
- if (!subcommand) {
103720
- console.error("Usage: lotics install <package_id>");
103721
- console.error(" Materializes a published package into the current workspace.");
103722
- process.exit(1);
102813
+ if (command === "starter") {
102814
+ if (subcommand === "list") {
102815
+ const { client: client2, ctx: ctx2 } = requireClient(flags);
102816
+ await resolveWorkspace(client2, ctx2);
102817
+ await starterList(client2);
102818
+ return;
103723
102819
  }
103724
- const { client: client2, ctx: ctx2 } = requireClient(flags);
103725
- await resolveWorkspace(client2, ctx2);
103726
- await installCommand(client2, { packageId: subcommand });
103727
- return;
103728
- }
103729
- if (command === "upgrade") {
103730
- const { client: client2, ctx: ctx2 } = requireClient(flags);
103731
- applyAppManifestWorkspace(ctx2, command, subcommand, void 0, flags);
103732
- await resolveWorkspace(client2, ctx2);
103733
- await upgradeCommand(client2, {});
103734
- return;
102820
+ if (subcommand === "show") {
102821
+ if (!toolArgs) {
102822
+ console.error("Usage: lotics starter show <starter_id>");
102823
+ process.exit(1);
102824
+ }
102825
+ const { client: client2, ctx: ctx2 } = requireClient(flags);
102826
+ await resolveWorkspace(client2, ctx2);
102827
+ await starterShow(client2, toolArgs);
102828
+ return;
102829
+ }
102830
+ if (subcommand === "init") {
102831
+ if (!toolArgs) {
102832
+ console.error("Usage: lotics starter init <starter_id> [path] [--no-sample-data] [--adopt]");
102833
+ console.error(" Copies a starter into this workspace: schema, templates, knowledge");
102834
+ console.error(" docs, sample records and an editable app project. Builds and deploys");
102835
+ console.error(" locally, so it needs node and a few minutes.");
102836
+ process.exit(1);
102837
+ }
102838
+ const { client: client2, ctx: ctx2 } = requireClient(flags);
102839
+ await resolveWorkspace(client2, ctx2);
102840
+ await starterInit(client2, {
102841
+ starter_id: toolArgs,
102842
+ ...restArgs[0] !== void 0 ? { targetPath: restArgs[0] } : {},
102843
+ ...flags.noSampleData === true ? { noSampleData: true } : {},
102844
+ ...flags.adopt === true ? { adopt: true } : {}
102845
+ });
102846
+ return;
102847
+ }
102848
+ if (subcommand === "fixtures") {
102849
+ if (toolArgs !== "capture") {
102850
+ console.error("Usage: lotics starter fixtures capture [--entity <alias> ...] [--limit <n>]");
102851
+ console.error(" Writes fixtures/<entity>.json into this app project from live records.");
102852
+ console.error(" Repeat --entity to capture a linked set in one call: a link only");
102853
+ console.error(" resolves within ONE capture, so separate calls lose the edge.");
102854
+ process.exit(1);
102855
+ }
102856
+ let limit;
102857
+ if (flags.limit !== void 0) {
102858
+ limit = Number(flags.limit);
102859
+ if (!Number.isInteger(limit) || limit < 1) {
102860
+ console.error(`Invalid --limit "${flags.limit}" \u2014 expected a positive integer.`);
102861
+ process.exit(1);
102862
+ }
102863
+ }
102864
+ const { client: client2, ctx: ctx2 } = requireClient(flags);
102865
+ await resolveWorkspace(client2, ctx2);
102866
+ await starterFixturesCapture(client2, {
102867
+ entities: flags.entity,
102868
+ ...limit !== void 0 ? { limit } : {}
102869
+ });
102870
+ return;
102871
+ }
102872
+ console.error(
102873
+ "Usage: lotics starter list | show <starter_id> | init <starter_id> [path] | fixtures capture"
102874
+ );
102875
+ process.exit(1);
103735
102876
  }
103736
102877
  if (command === "docs") {
103737
102878
  docsCommand({ area: subcommand });
@@ -103741,11 +102882,11 @@ async function main() {
103741
102882
  let input = subcommand ?? "";
103742
102883
  if (input.startsWith("@")) {
103743
102884
  const file2 = input.slice(1);
103744
- if (!fs13.existsSync(file2)) {
102885
+ if (!fs14.existsSync(file2)) {
103745
102886
  console.error(`No such file: ${file2}`);
103746
102887
  process.exit(1);
103747
102888
  }
103748
- input = fs13.readFileSync(file2, "utf-8");
102889
+ input = fs14.readFileSync(file2, "utf-8");
103749
102890
  } else if (input === "-") {
103750
102891
  input = await readStdin();
103751
102892
  }
@@ -103872,13 +103013,13 @@ async function main() {
103872
103013
  if (command === "preview") {
103873
103014
  if (subcommand && isStoredFileId(subcommand)) {
103874
103015
  const { client: client2 } = requireClient(flags);
103875
- const tmpDir = fs13.mkdtempSync(path12.join(os4.tmpdir(), "lotics-preview-"));
103016
+ const tmpDir = fs14.mkdtempSync(path13.join(os4.tmpdir(), "lotics-preview-"));
103876
103017
  try {
103877
103018
  const { path: localPath, filename } = await client2.downloadFileById(subcommand, tmpDir);
103878
103019
  const output = flags.output ?? defaultPreviewOutputPath(filename, process.cwd());
103879
103020
  await runPreviewCommand(localPath, { output });
103880
103021
  } finally {
103881
- fs13.rmSync(tmpDir, { recursive: true, force: true });
103022
+ fs14.rmSync(tmpDir, { recursive: true, force: true });
103882
103023
  }
103883
103024
  return;
103884
103025
  }
@@ -104426,7 +103567,7 @@ ${JSON.stringify(info.input_schema, null, 2)}`);
104426
103567
  const ingested = await ingestJsonArgs({
104427
103568
  rawArg: toolArgs,
104428
103569
  stdinIsTTY: process.stdin.isTTY ?? false,
104429
- readFile: (p) => fs13.readFileSync(p, "utf-8"),
103570
+ readFile: (p) => fs14.readFileSync(p, "utf-8"),
104430
103571
  readStdin
104431
103572
  });
104432
103573
  if (ingested.kind === "error") {