@lotics/cli 0.60.1 → 0.62.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
@@ -12243,12 +12243,12 @@ var require_tokens = __commonJS({
12243
12243
  });
12244
12244
  }
12245
12245
  exports2.assignCategoriesMapProp = assignCategoriesMapProp;
12246
- function singleAssignCategoriesToksMap(path7, nextNode) {
12247
- utils_1.forEach(path7, function(pathNode) {
12246
+ function singleAssignCategoriesToksMap(path8, nextNode) {
12247
+ utils_1.forEach(path8, function(pathNode) {
12248
12248
  nextNode.categoryMatchesMap[pathNode.tokenTypeIdx] = true;
12249
12249
  });
12250
12250
  utils_1.forEach(nextNode.CATEGORIES, function(nextCategory) {
12251
- var newPath = path7.concat(nextNode);
12251
+ var newPath = path8.concat(nextNode);
12252
12252
  if (!utils_1.contains(newPath, nextCategory)) {
12253
12253
  singleAssignCategoriesToksMap(newPath, nextCategory);
12254
12254
  }
@@ -14011,10 +14011,10 @@ var require_interpreter = __commonJS({
14011
14011
  /** @class */
14012
14012
  (function(_super) {
14013
14013
  __extends(AbstractNextPossibleTokensWalker2, _super);
14014
- function AbstractNextPossibleTokensWalker2(topProd, path7) {
14014
+ function AbstractNextPossibleTokensWalker2(topProd, path8) {
14015
14015
  var _this = _super.call(this) || this;
14016
14016
  _this.topProd = topProd;
14017
- _this.path = path7;
14017
+ _this.path = path8;
14018
14018
  _this.possibleTokTypes = [];
14019
14019
  _this.nextProductionName = "";
14020
14020
  _this.nextProductionOccurrence = 0;
@@ -14068,9 +14068,9 @@ var require_interpreter = __commonJS({
14068
14068
  /** @class */
14069
14069
  (function(_super) {
14070
14070
  __extends(NextAfterTokenWalker2, _super);
14071
- function NextAfterTokenWalker2(topProd, path7) {
14072
- var _this = _super.call(this, topProd, path7) || this;
14073
- _this.path = path7;
14071
+ function NextAfterTokenWalker2(topProd, path8) {
14072
+ var _this = _super.call(this, topProd, path8) || this;
14073
+ _this.path = path8;
14074
14074
  _this.nextTerminalName = "";
14075
14075
  _this.nextTerminalOccurrence = 0;
14076
14076
  _this.nextTerminalName = _this.path.lastTok.name;
@@ -14767,10 +14767,10 @@ var require_lookahead = __commonJS({
14767
14767
  }
14768
14768
  return result;
14769
14769
  }
14770
- function pathToHashKeys(path7) {
14770
+ function pathToHashKeys(path8) {
14771
14771
  var keys2 = [""];
14772
- for (var i2 = 0; i2 < path7.length; i2++) {
14773
- var tokType = path7[i2];
14772
+ for (var i2 = 0; i2 < path8.length; i2++) {
14773
+ var tokType = path8[i2];
14774
14774
  var longerKeys = [];
14775
14775
  for (var j = 0; j < keys2.length; j++) {
14776
14776
  var currShorterKey = keys2[j];
@@ -15082,9 +15082,9 @@ var require_checks = __commonJS({
15082
15082
  return errors;
15083
15083
  }
15084
15084
  exports2.validateRuleIsOverridden = validateRuleIsOverridden;
15085
- function validateNoLeftRecursion(topRule, currRule, errMsgProvider, path7) {
15086
- if (path7 === void 0) {
15087
- path7 = [];
15085
+ function validateNoLeftRecursion(topRule, currRule, errMsgProvider, path8) {
15086
+ if (path8 === void 0) {
15087
+ path8 = [];
15088
15088
  }
15089
15089
  var errors = [];
15090
15090
  var nextNonTerminals = getFirstNoneTerminal(currRule.definition);
@@ -15097,15 +15097,15 @@ var require_checks = __commonJS({
15097
15097
  errors.push({
15098
15098
  message: errMsgProvider.buildLeftRecursionError({
15099
15099
  topLevelRule: topRule,
15100
- leftRecursionPath: path7
15100
+ leftRecursionPath: path8
15101
15101
  }),
15102
15102
  type: parser_1.ParserDefinitionErrorType.LEFT_RECURSION,
15103
15103
  ruleName
15104
15104
  });
15105
15105
  }
15106
- var validNextSteps = utils.difference(nextNonTerminals, path7.concat([topRule]));
15106
+ var validNextSteps = utils.difference(nextNonTerminals, path8.concat([topRule]));
15107
15107
  var errorsFromNextSteps = utils.map(validNextSteps, function(currRefRule) {
15108
- var newPath = utils.cloneArr(path7);
15108
+ var newPath = utils.cloneArr(path8);
15109
15109
  newPath.push(currRefRule);
15110
15110
  return validateNoLeftRecursion(topRule, currRefRule, errMsgProvider, newPath);
15111
15111
  });
@@ -22714,8 +22714,8 @@ var require_utils4 = __commonJS({
22714
22714
  var result = transform[inputType][outputType](input);
22715
22715
  return result;
22716
22716
  };
22717
- exports2.resolve = function(path7) {
22718
- var parts = path7.split("/");
22717
+ exports2.resolve = function(path8) {
22718
+ var parts = path8.split("/");
22719
22719
  var result = [];
22720
22720
  for (var index = 0; index < parts.length; index++) {
22721
22721
  var part = parts[index];
@@ -28568,18 +28568,18 @@ var require_object = __commonJS({
28568
28568
  var object = new ZipObject(name, zipObjectContent, o);
28569
28569
  this.files[name] = object;
28570
28570
  };
28571
- var parentFolder = function(path7) {
28572
- if (path7.slice(-1) === "/") {
28573
- path7 = path7.substring(0, path7.length - 1);
28571
+ var parentFolder = function(path8) {
28572
+ if (path8.slice(-1) === "/") {
28573
+ path8 = path8.substring(0, path8.length - 1);
28574
28574
  }
28575
- var lastSlash = path7.lastIndexOf("/");
28576
- return lastSlash > 0 ? path7.substring(0, lastSlash) : "";
28575
+ var lastSlash = path8.lastIndexOf("/");
28576
+ return lastSlash > 0 ? path8.substring(0, lastSlash) : "";
28577
28577
  };
28578
- var forceTrailingSlash = function(path7) {
28579
- if (path7.slice(-1) !== "/") {
28580
- path7 += "/";
28578
+ var forceTrailingSlash = function(path8) {
28579
+ if (path8.slice(-1) !== "/") {
28580
+ path8 += "/";
28581
28581
  }
28582
- return path7;
28582
+ return path8;
28583
28583
  };
28584
28584
  var folderAdd = function(name, createFolders) {
28585
28585
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults2.createFolders;
@@ -29581,8 +29581,8 @@ var require_lib3 = __commonJS({
29581
29581
  // src/cli.ts
29582
29582
  import dns from "node:dns";
29583
29583
  import net2 from "node:net";
29584
- import fs7 from "node:fs";
29585
- import path6 from "node:path";
29584
+ import fs8 from "node:fs";
29585
+ import path7 from "node:path";
29586
29586
  import readline from "node:readline";
29587
29587
 
29588
29588
  // src/client.ts
@@ -29680,8 +29680,8 @@ var LoticsClient = class {
29680
29680
  }
29681
29681
  return headers;
29682
29682
  }
29683
- async request(method, path7, body) {
29684
- const url = `${this.baseUrl}${path7}`;
29683
+ async request(method, path8, body) {
29684
+ const url = `${this.baseUrl}${path8}`;
29685
29685
  const headers = this.buildHeaders();
29686
29686
  const init = { method, headers };
29687
29687
  if (body !== void 0) {
@@ -30342,8 +30342,8 @@ var pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
30342
30342
  var VERSION = pkg.version;
30343
30343
 
30344
30344
  // src/app_commands.ts
30345
- import fs3 from "node:fs";
30346
- import path4 from "node:path";
30345
+ import fs4 from "node:fs";
30346
+ import path5 from "node:path";
30347
30347
  import { spawn as spawn2 } from "node:child_process";
30348
30348
  import { tmpdir } from "node:os";
30349
30349
 
@@ -30403,7 +30403,9 @@ function buildStarterTemplate(args) {
30403
30403
  "@vitejs/plugin-react": "^4.3.0",
30404
30404
  jsdom: "^25.0.0",
30405
30405
  oxlint: "^0.13.0",
30406
- typescript: "^5.6.0",
30406
+ // Track the platform's TS major so `lotics app workflow check` (which runs
30407
+ // the app's OWN typescript) gives the same verdict the server does at set-time.
30408
+ typescript: "~6.0.3",
30407
30409
  vite: "^5.4.0",
30408
30410
  vitest: "^2.1.0"
30409
30411
  },
@@ -30447,45 +30449,17 @@ function buildStarterTemplate(args) {
30447
30449
  // base, which IS read. (GAP-38.)
30448
30450
  include: ["src", ".lotics/**/*"],
30449
30451
  // src/workflows/<alias>.ts bodies run on the server (workflow globals:
30450
- // trigger / runtime / tool calls). They ARE locally typecheckable
30451
- // each is wrapped in the server's `__workflow` envelope and references
30452
- // its per-alias `.lotics/workflows/<alias>.globals.d.ts` but under a
30453
- // DEDICATED config that mirrors the server's compile options (es2022
30454
- // lib, NO DOM). The main `npm run typecheck` excludes them so it stays
30455
- // green and DOM-lib-free for bodies; check a body with
30456
- // `tsc -p tsconfig.workflows.json`. The server is the single verifier
30457
- // on `lotics app workflow set`.
30458
- exclude: ["node_modules", "src/workflows"]
30459
- },
30460
- null,
30461
- 2
30462
- ) + "\n"
30463
- },
30464
- {
30465
- // Dedicated config for the editable workflow bodies (GAP-59). Mirrors the
30466
- // SERVER's set-time typecheck options (strict, lib es2022 with NO DOM,
30467
- // target ES2022, skipLibCheck) so a local `tsc -p tsconfig.workflows.json`
30468
- // gives the same verdict the server would on `lotics app workflow set`.
30469
- // Each body file is a module (the CLI writes a bookkeeping `export {};`),
30470
- // so the per-file `__workflow` wrapper doesn't collide across bodies.
30471
- path: "tsconfig.workflows.json",
30472
- content: JSON.stringify(
30473
- {
30474
- compilerOptions: {
30475
- target: "ES2022",
30476
- lib: ["ES2022"],
30477
- module: "ESNext",
30478
- moduleResolution: "Bundler",
30479
- strict: true,
30480
- skipLibCheck: true,
30481
- noEmit: true,
30482
- types: []
30483
- },
30484
- // The bodies + their per-alias ambient globals. `.lotics/workflows`
30485
- // uses the explicit `**/*` glob for the same dot-dir walk reason the
30486
- // main config does (TS's include walk skips bare dot-dirs).
30487
- include: ["src/workflows", ".lotics/workflows/**/*"],
30488
- exclude: ["node_modules"]
30452
+ // trigger / runtime / tool calls), and each pulls its own per-alias
30453
+ // ambient globals under `.lotics/workflows/`. BOTH are excluded from
30454
+ // the main typecheck: the bodies would apply the app's DOM lib (the
30455
+ // server doesn't), and the per-alias `.globals.d.ts` files each declare
30456
+ // their OWN ambient `trigger` loading several into one program
30457
+ // collides those declarations and reports false errors. Type-check the
30458
+ // bodies with `lotics app workflow check` instead it builds ONE
30459
+ // isolated program per alias (mirroring the server's set-time verify),
30460
+ // so the ambient `trigger` is unambiguous. The server stays the single
30461
+ // verifier on `lotics app workflow set`.
30462
+ exclude: ["node_modules", "src/workflows", ".lotics/workflows"]
30489
30463
  },
30490
30464
  null,
30491
30465
  2
@@ -30846,6 +30820,7 @@ Editable JS-subset bodies of this app's workflows live here, one file per alias:
30846
30820
  \`\`\`bash
30847
30821
  lotics app workflow pull # write/refresh every src/workflows/<alias>.ts from the server
30848
30822
  # edit src/workflows/<alias>.ts
30823
+ lotics app workflow check <alias> # typecheck the body locally (same verdict as \`set\`)
30849
30824
  lotics app workflow set <alias> # push it back through set_app_workflow (the server verifies)
30850
30825
  \`\`\`
30851
30826
 
@@ -30857,15 +30832,17 @@ A workflow body is a **JS-subset expression** that runs server-side using workfl
30857
30832
  globals (\`trigger\`, \`runtime\`, tool calls) and ends with \`return({ data })\`. Each
30858
30833
  pulled file wraps the body in the server's \`__workflow\` envelope and references its
30859
30834
  per-alias ambient globals at \`.lotics/workflows/<alias>.globals.d.ts\`, so it **is**
30860
- locally typecheckable \u2014 under the dedicated config that mirrors the server's compile
30861
- options:
30835
+ locally typecheckable:
30862
30836
 
30863
30837
  \`\`\`bash
30864
- tsc -p tsconfig.workflows.json # same verdict the server gives on \`set\`
30838
+ lotics app workflow check # check every body; [alias] to check one
30865
30839
  \`\`\`
30866
30840
 
30867
- The main \`npm run typecheck\` excludes \`src/workflows\` (it would apply the app's
30868
- DOM lib, which the server doesn't), so the bodies have their own config. The
30841
+ \`check\` builds ONE isolated program per alias (the app's own \`typescript\`, the
30842
+ server's compile options \u2014 strict, lib es2022 with no DOM), so each body's ambient
30843
+ \`trigger\` is unambiguous and the verdict mirrors set-time verify. The main
30844
+ \`npm run typecheck\` excludes \`src/workflows\` + \`.lotics/workflows\` (the bodies would
30845
+ apply the app's DOM lib, and the per-alias globals collide on \`trigger\`). The
30869
30846
  verification that matters still runs on the **server** when you \`set\` \u2014 the same
30870
30847
  guarantee as authoring via \`set_app_workflow\` directly. Edit only the body BETWEEN
30871
30848
  the wrapper lines; the wrapper, the \`/// <reference>\`, and the \`export {};\` marker
@@ -32119,6 +32096,98 @@ export type AppOptions = typeof OPT;
32119
32096
  `;
32120
32097
  }
32121
32098
 
32099
+ // src/app_workflow_check.ts
32100
+ import fs3 from "node:fs";
32101
+ import path4 from "node:path";
32102
+ import { createRequire } from "node:module";
32103
+ function workflowCheckCompilerOptions(tsApi) {
32104
+ return {
32105
+ target: tsApi.ScriptTarget.ES2022,
32106
+ module: tsApi.ModuleKind.ESNext,
32107
+ lib: ["lib.es2022.d.ts"],
32108
+ strict: true,
32109
+ noImplicitAny: true,
32110
+ strictNullChecks: true,
32111
+ noImplicitReturns: false,
32112
+ noEmit: true,
32113
+ allowJs: false,
32114
+ isolatedModules: false,
32115
+ skipLibCheck: true,
32116
+ moduleResolution: tsApi.ModuleResolutionKind.NodeNext,
32117
+ types: [],
32118
+ declaration: false
32119
+ };
32120
+ }
32121
+ function bodyLineOffset(wrappedSource) {
32122
+ const lines = wrappedSource.split("\n");
32123
+ for (let i2 = 0; i2 < lines.length; i2++) {
32124
+ if (/^\s*async\s+function\s+__workflow\s*\(/.test(lines[i2])) return i2 + 1;
32125
+ }
32126
+ return 0;
32127
+ }
32128
+ async function loadProjectTypescript(projectDir) {
32129
+ const requireFromProject = createRequire(path4.join(projectDir, "package.json"));
32130
+ let resolved;
32131
+ try {
32132
+ resolved = requireFromProject.resolve("typescript");
32133
+ } catch {
32134
+ throw new Error(
32135
+ `Could not resolve 'typescript' from ${projectDir}. 'lotics app workflow check' type-checks bodies with the app's own compiler \u2014 run 'npm install' (the scaffold ships typescript as a devDependency).`
32136
+ );
32137
+ }
32138
+ const mod = await import(pathToImportUrl(resolved));
32139
+ return mod.default ?? mod;
32140
+ }
32141
+ function pathToImportUrl(p) {
32142
+ const resolved = path4.resolve(p);
32143
+ const prefixed = resolved.startsWith("/") ? resolved : `/${resolved}`;
32144
+ return `file://${prefixed.split(path4.sep).join("/")}`;
32145
+ }
32146
+ function checkOneWorkflowBody(tsApi, input) {
32147
+ const wrapped = fs3.readFileSync(input.bodyPath, "utf-8");
32148
+ const offset = bodyLineOffset(wrapped);
32149
+ const program = tsApi.createProgram({
32150
+ rootNames: [input.globalsPath, input.bodyPath],
32151
+ options: workflowCheckCompilerOptions(tsApi)
32152
+ });
32153
+ const bodyFile = program.getSourceFile(input.bodyPath);
32154
+ if (!bodyFile) {
32155
+ return [
32156
+ {
32157
+ line: 1,
32158
+ col: 1,
32159
+ code: "INTERNAL",
32160
+ message: `workflow check: body file was not loaded (${input.bodyPath})`
32161
+ }
32162
+ ];
32163
+ }
32164
+ const issues = [];
32165
+ for (const d of tsApi.getPreEmitDiagnostics(program)) {
32166
+ if (d.file !== bodyFile) continue;
32167
+ let line = 1;
32168
+ let col = 1;
32169
+ if (typeof d.start === "number") {
32170
+ const lc2 = bodyFile.getLineAndCharacterOfPosition(d.start);
32171
+ line = Math.max(1, lc2.line + 1 - offset);
32172
+ col = lc2.character + 1;
32173
+ }
32174
+ issues.push({
32175
+ line,
32176
+ col,
32177
+ code: `TS${d.code}`,
32178
+ message: tsApi.flattenDiagnosticMessageText(d.messageText, "\n")
32179
+ });
32180
+ }
32181
+ return issues;
32182
+ }
32183
+ function checkWorkflowBodies(tsApi, aliases) {
32184
+ return aliases.map(({ alias, input }) => ({
32185
+ alias,
32186
+ bodyPath: input.bodyPath,
32187
+ issues: checkOneWorkflowBody(tsApi, input)
32188
+ }));
32189
+ }
32190
+
32122
32191
  // src/app_commands.ts
32123
32192
  async function fetchLatestNpmVersion(packageName) {
32124
32193
  try {
@@ -32136,15 +32205,17 @@ async function fetchLatestNpmVersion(packageName) {
32136
32205
  return null;
32137
32206
  }
32138
32207
  }
32139
- var WORKFLOWS_DIR = path4.join("src", "workflows");
32140
- var WORKFLOW_GLOBALS_DIR = path4.join(".lotics", "workflows");
32208
+ var WORKFLOWS_DIR = path5.join("src", "workflows");
32209
+ var WORKFLOW_GLOBALS_DIR = path5.join(".lotics", "workflows");
32210
+ var WORKFLOW_TSCONFIG_EXCLUDES = ["src/workflows", ".lotics/workflows"];
32141
32211
  var FALLBACK_ENVELOPE_PREFIX = "async function __workflow(): Promise<__WorkflowReturn | void> {\n";
32142
32212
  var FALLBACK_ENVELOPE_SUFFIX = "\n}";
32143
32213
  function workflowFileHeader(alias) {
32144
- const refPath = path4.join("..", "..", WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`).split(path4.sep).join("/");
32214
+ const refPath = path5.join("..", "..", WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`).split(path5.sep).join("/");
32145
32215
  return `/// <reference path="${refPath}" />
32146
32216
  // Auto-pulled workflow body for "${alias}". Edit the BODY between the wrapper
32147
- // lines below, then push with:
32217
+ // lines below, then check + push with:
32218
+ // lotics app workflow check ${alias}
32148
32219
  // lotics app workflow set ${alias}
32149
32220
  // The push goes through set_app_workflow, where the SERVER verifies the body.
32150
32221
  // The __workflow wrapper + the reference above are CLI bookkeeping (stripped on
@@ -32154,25 +32225,25 @@ export {};
32154
32225
  `;
32155
32226
  }
32156
32227
  function workflowFilePath(projectDir, alias) {
32157
- return path4.join(projectDir, WORKFLOWS_DIR, `${alias}.ts`);
32228
+ return path5.join(projectDir, WORKFLOWS_DIR, `${alias}.ts`);
32158
32229
  }
32159
32230
  function workflowGlobalsPath(projectDir, alias) {
32160
- return path4.join(projectDir, WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`);
32231
+ return path5.join(projectDir, WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`);
32161
32232
  }
32162
32233
  function writeWorkflowGlobals(projectDir, alias, dts) {
32163
- const dir = path4.join(projectDir, WORKFLOW_GLOBALS_DIR);
32164
- fs3.mkdirSync(dir, { recursive: true });
32234
+ const dir = path5.join(projectDir, WORKFLOW_GLOBALS_DIR);
32235
+ fs4.mkdirSync(dir, { recursive: true });
32165
32236
  const file = workflowGlobalsPath(projectDir, alias);
32166
- fs3.writeFileSync(file, `${dts.replace(/\s+$/, "")}
32237
+ fs4.writeFileSync(file, `${dts.replace(/\s+$/, "")}
32167
32238
  `);
32168
32239
  return file;
32169
32240
  }
32170
32241
  function writeWorkflowFile(projectDir, alias, source, envelope = { prefix: FALLBACK_ENVELOPE_PREFIX, suffix: FALLBACK_ENVELOPE_SUFFIX }) {
32171
- const dir = path4.join(projectDir, WORKFLOWS_DIR);
32172
- fs3.mkdirSync(dir, { recursive: true });
32242
+ const dir = path5.join(projectDir, WORKFLOWS_DIR);
32243
+ fs4.mkdirSync(dir, { recursive: true });
32173
32244
  const file = workflowFilePath(projectDir, alias);
32174
32245
  const body = source.replace(/\s+$/, "");
32175
- fs3.writeFileSync(file, `${workflowFileHeader(alias)}
32246
+ fs4.writeFileSync(file, `${workflowFileHeader(alias)}
32176
32247
  ${envelope.prefix}${body}${envelope.suffix}
32177
32248
  `);
32178
32249
  return file;
@@ -32253,11 +32324,11 @@ function runNpm(args, cwd) {
32253
32324
  });
32254
32325
  }
32255
32326
  function readAppMeta(projectDir) {
32256
- const pkgPath2 = path4.join(projectDir, "package.json");
32257
- if (!fs3.existsSync(pkgPath2)) {
32327
+ const pkgPath2 = path5.join(projectDir, "package.json");
32328
+ if (!fs4.existsSync(pkgPath2)) {
32258
32329
  throw new Error(`No package.json found at ${projectDir}. Run 'lotics app create' first.`);
32259
32330
  }
32260
- const pkg2 = JSON.parse(fs3.readFileSync(pkgPath2, "utf-8"));
32331
+ const pkg2 = JSON.parse(fs4.readFileSync(pkgPath2, "utf-8"));
32261
32332
  if (!pkg2.lotics?.app_id || !pkg2.lotics.workspace_id) {
32262
32333
  throw new Error(
32263
32334
  `package.json is missing the 'lotics' field with app_id and workspace_id. Was this folder created with 'lotics app create'?`
@@ -32275,24 +32346,52 @@ function readAppMeta(projectDir) {
32275
32346
  };
32276
32347
  }
32277
32348
  function writeAppMeta(projectDir, meta) {
32278
- const pkgPath2 = path4.join(projectDir, "package.json");
32279
- const pkg2 = JSON.parse(fs3.readFileSync(pkgPath2, "utf-8"));
32349
+ const pkgPath2 = path5.join(projectDir, "package.json");
32350
+ const pkg2 = JSON.parse(fs4.readFileSync(pkgPath2, "utf-8"));
32280
32351
  pkg2.lotics = meta;
32281
- fs3.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
32352
+ fs4.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
32353
+ }
32354
+ function ensureWorkflowTsconfigExcludes(projectDir) {
32355
+ const tsconfigPath = path5.join(projectDir, "tsconfig.json");
32356
+ if (!fs4.existsSync(tsconfigPath)) {
32357
+ console.error(
32358
+ `\u26A0 No tsconfig.json at ${projectDir} \u2014 could not ensure ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")} are excluded. Add them to your tsconfig's "exclude" so npm run typecheck skips the workflow bodies.`
32359
+ );
32360
+ return;
32361
+ }
32362
+ let parsed;
32363
+ try {
32364
+ parsed = JSON.parse(fs4.readFileSync(tsconfigPath, "utf-8"));
32365
+ } catch (err2) {
32366
+ console.error(
32367
+ `\u26A0 Could not parse tsconfig.json (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 add ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")} to its "exclude" manually so npm run typecheck skips the workflow bodies.`
32368
+ );
32369
+ return;
32370
+ }
32371
+ if (!parsed || typeof parsed !== "object") return;
32372
+ const current = Array.isArray(parsed.exclude) ? parsed.exclude : [];
32373
+ const currentStrings = current.filter((e) => typeof e === "string");
32374
+ const toAdd = WORKFLOW_TSCONFIG_EXCLUDES.filter((g) => !currentStrings.includes(g));
32375
+ if (toAdd.length === 0) return;
32376
+ parsed.exclude = [...currentStrings, ...toAdd];
32377
+ fs4.writeFileSync(tsconfigPath, JSON.stringify(parsed, null, 2) + "\n");
32378
+ console.error(
32379
+ `Patched tsconfig.json: added ${toAdd.join(", ")} to "exclude" so npm run typecheck skips the workflow bodies (check them with: lotics app workflow check).`
32380
+ );
32282
32381
  }
32283
32382
  function writeAppDts(projectDir, manifest) {
32284
- const dotLotics = path4.join(projectDir, ".lotics");
32285
- fs3.mkdirSync(dotLotics, { recursive: true });
32383
+ const dotLotics = path5.join(projectDir, ".lotics");
32384
+ fs4.mkdirSync(dotLotics, { recursive: true });
32286
32385
  const written = [
32287
- [path4.join(dotLotics, "app_workflows.d.ts"), generateAppWorkflowsDts(manifest.workflows)],
32288
- [path4.join(dotLotics, "app_queries.d.ts"), generateAppQueriesDts(manifest.queries)],
32289
- [path4.join(dotLotics, "app_agents.d.ts"), generateAppAgentsDts(manifest.agents)]
32386
+ [path5.join(dotLotics, "app_workflows.d.ts"), generateAppWorkflowsDts(manifest.workflows)],
32387
+ [path5.join(dotLotics, "app_queries.d.ts"), generateAppQueriesDts(manifest.queries)],
32388
+ [path5.join(dotLotics, "app_agents.d.ts"), generateAppAgentsDts(manifest.agents)]
32290
32389
  ];
32291
- for (const [file, content] of written) fs3.writeFileSync(file, content);
32390
+ for (const [file, content] of written) fs4.writeFileSync(file, content);
32292
32391
  return written.map(([file]) => file);
32293
32392
  }
32294
32393
  function readCodegenTablesAllowlist(projectDir) {
32295
- const pkg2 = JSON.parse(fs3.readFileSync(path4.join(projectDir, "package.json"), "utf-8"));
32394
+ const pkg2 = JSON.parse(fs4.readFileSync(path5.join(projectDir, "package.json"), "utf-8"));
32296
32395
  const tables = pkg2.lotics?.codegen?.tables;
32297
32396
  return Array.isArray(tables) ? tables.filter((t) => typeof t === "string") : [];
32298
32397
  }
@@ -32305,14 +32404,14 @@ function resolveCodegenTableIds(projectDir, queries) {
32305
32404
  return [...ids];
32306
32405
  }
32307
32406
  function writeAppFields(projectDir, tables) {
32308
- const dotLotics = path4.join(projectDir, ".lotics");
32309
- fs3.mkdirSync(dotLotics, { recursive: true });
32310
- const file = path4.join(dotLotics, "app_fields.ts");
32311
- fs3.writeFileSync(file, generateAppFields(tables));
32407
+ const dotLotics = path5.join(projectDir, ".lotics");
32408
+ fs4.mkdirSync(dotLotics, { recursive: true });
32409
+ const file = path5.join(dotLotics, "app_fields.ts");
32410
+ fs4.writeFileSync(file, generateAppFields(tables));
32312
32411
  return file;
32313
32412
  }
32314
32413
  async function appCodegen(args) {
32315
- const projectDir = path4.resolve(args.projectDir ?? process.cwd());
32414
+ const projectDir = path5.resolve(args.projectDir ?? process.cwd());
32316
32415
  const meta = readAppMeta(projectDir);
32317
32416
  const dtsPaths = writeAppDts(projectDir, {
32318
32417
  workflows: meta.workflows,
@@ -32337,16 +32436,17 @@ async function appCodegen(args) {
32337
32436
  );
32338
32437
  }
32339
32438
  await refreshWorkflowGlobals(args.client, projectDir, meta.app_id, Object.keys(meta.workflows ?? {}));
32439
+ if (Object.keys(meta.workflows ?? {}).length > 0) ensureWorkflowTsconfigExcludes(projectDir);
32340
32440
  }
32341
32441
  async function refreshWorkflowGlobals(client, projectDir, app_id, aliases) {
32342
32442
  for (const alias of aliases) {
32343
32443
  const file = workflowFilePath(projectDir, alias);
32344
- if (!fs3.existsSync(file)) continue;
32345
- const body = stripWorkflowHeader(fs3.readFileSync(file, "utf-8"));
32444
+ if (!fs4.existsSync(file)) continue;
32445
+ const body = stripWorkflowHeader(fs4.readFileSync(file, "utf-8"));
32346
32446
  if (body.trim() === "") continue;
32347
32447
  const envelope = await fetchWorkflowGlobals(client, projectDir, app_id, alias);
32348
32448
  writeWorkflowFile(projectDir, alias, body, envelope);
32349
- console.error(`Refreshed ${path4.relative(projectDir, file)} + its workflow types`);
32449
+ console.error(`Refreshed ${path5.relative(projectDir, file)} + its workflow types`);
32350
32450
  }
32351
32451
  }
32352
32452
  function stampPulledManifest(projectDir, args) {
@@ -32367,21 +32467,21 @@ async function downloadToFile(url, destPath) {
32367
32467
  throw new Error(`Failed to download ${url}: ${response.status}`);
32368
32468
  }
32369
32469
  const buffer = Buffer.from(await response.arrayBuffer());
32370
- fs3.writeFileSync(destPath, buffer);
32470
+ fs4.writeFileSync(destPath, buffer);
32371
32471
  }
32372
32472
  function appDirName(name) {
32373
32473
  const cleaned = name.replace(/[/\\]+/g, "-").replace(/[<>:"|?*]/g, "").replace(/\s+/g, " ").trim().replace(/^[.\s-]+|[.\s-]+$/g, "");
32374
32474
  return cleaned || "app";
32375
32475
  }
32376
32476
  async function appCreate(client, args) {
32377
- const targetPath = path4.resolve(args.targetPath ?? appDirName(args.name));
32378
- if (fs3.existsSync(targetPath)) {
32379
- const entries = fs3.readdirSync(targetPath);
32477
+ const targetPath = path5.resolve(args.targetPath ?? appDirName(args.name));
32478
+ if (fs4.existsSync(targetPath)) {
32479
+ const entries = fs4.readdirSync(targetPath);
32380
32480
  if (entries.length > 0) {
32381
32481
  throw new Error(`Target directory ${targetPath} is not empty.`);
32382
32482
  }
32383
32483
  }
32384
- fs3.mkdirSync(targetPath, { recursive: true });
32484
+ fs4.mkdirSync(targetPath, { recursive: true });
32385
32485
  const app = await client.createApp({ name: args.name });
32386
32486
  console.error(`Created app: ${app.name} (${app.id})`);
32387
32487
  const [uiLatest, sdkLatest] = await Promise.all([
@@ -32396,9 +32496,9 @@ async function appCreate(client, args) {
32396
32496
  sdk_version: sdkLatest ? `^${sdkLatest}` : void 0
32397
32497
  });
32398
32498
  for (const file of files) {
32399
- const fullPath = path4.join(targetPath, file.path);
32400
- fs3.mkdirSync(path4.dirname(fullPath), { recursive: true });
32401
- fs3.writeFileSync(fullPath, file.content);
32499
+ const fullPath = path5.join(targetPath, file.path);
32500
+ fs4.mkdirSync(path5.dirname(fullPath), { recursive: true });
32501
+ fs4.writeFileSync(fullPath, file.content);
32402
32502
  }
32403
32503
  console.error(`Scaffolded ${files.length} files into ${targetPath}`);
32404
32504
  writeAppDts(targetPath, {});
@@ -32411,7 +32511,7 @@ async function appCreate(client, args) {
32411
32511
  });
32412
32512
  console.error(`
32413
32513
  Ready. Next steps:`);
32414
- console.error(` cd ${path4.relative(process.cwd(), targetPath) || "."}`);
32514
+ console.error(` cd ${path5.relative(process.cwd(), targetPath) || "."}`);
32415
32515
  console.error(` # edit src/App.tsx, then:`);
32416
32516
  console.error(` lotics app deploy`);
32417
32517
  }
@@ -32426,6 +32526,21 @@ async function appRename(client, args) {
32426
32526
  if (res.error) throw new Error(res.error);
32427
32527
  console.error(`App renamed: "${args.name}" (${meta.app_id})`);
32428
32528
  }
32529
+ function defaultPullTarget(appId, appName) {
32530
+ const cwdPkgPath = path5.join(process.cwd(), "package.json");
32531
+ if (fs4.existsSync(cwdPkgPath)) {
32532
+ let pkg2 = null;
32533
+ try {
32534
+ pkg2 = JSON.parse(fs4.readFileSync(cwdPkgPath, "utf-8"));
32535
+ } catch (err2) {
32536
+ console.error(
32537
+ `\u26A0 Could not parse ${cwdPkgPath} (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 pulling into a fresh ${appDirName(appName)}/ subdir.`
32538
+ );
32539
+ }
32540
+ if (pkg2?.lotics?.app_id === appId) return process.cwd();
32541
+ }
32542
+ return appDirName(appName);
32543
+ }
32429
32544
  async function appPull(client, args) {
32430
32545
  const app = await client.getApp(args.app_id);
32431
32546
  if (!app.current_version_id) {
@@ -32435,16 +32550,16 @@ async function appPull(client, args) {
32435
32550
  }
32436
32551
  const version = await client.getAppVersion(app.id, app.current_version_id);
32437
32552
  const sourceUrl = await client.getAppVersionSourceUrl(app.id, version.id);
32438
- const targetPath = path4.resolve(args.targetPath ?? appDirName(app.name));
32439
- fs3.mkdirSync(targetPath, { recursive: true });
32440
- const tmpFile = path4.join(tmpdir(), `lotics-app-${app.id}-${Date.now()}.tar.gz`);
32553
+ const targetPath = path5.resolve(args.targetPath ?? defaultPullTarget(app.id, app.name));
32554
+ fs4.mkdirSync(targetPath, { recursive: true });
32555
+ const tmpFile = path5.join(tmpdir(), `lotics-app-${app.id}-${Date.now()}.tar.gz`);
32441
32556
  console.error(`Downloading source archive...`);
32442
32557
  await downloadToFile(sourceUrl, tmpFile);
32443
32558
  try {
32444
32559
  console.error(`Extracting to ${targetPath}...`);
32445
32560
  await runTar(["-xzf", tmpFile, "-C", targetPath], targetPath);
32446
32561
  } finally {
32447
- if (fs3.existsSync(tmpFile)) fs3.unlinkSync(tmpFile);
32562
+ if (fs4.existsSync(tmpFile)) fs4.unlinkSync(tmpFile);
32448
32563
  }
32449
32564
  stampPulledManifest(targetPath, {
32450
32565
  app_id: app.id,
@@ -32463,12 +32578,13 @@ async function appPull(client, args) {
32463
32578
  `Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/ (${written.join(", ")})`
32464
32579
  );
32465
32580
  }
32581
+ ensureWorkflowTsconfigExcludes(targetPath);
32466
32582
  }
32467
32583
  console.error(`Installing npm dependencies...`);
32468
32584
  await runNpm(["install"], targetPath);
32469
32585
  console.error(`
32470
32586
  Ready. Next steps:`);
32471
- console.error(` cd ${path4.relative(process.cwd(), targetPath) || "."}`);
32587
+ console.error(` cd ${path5.relative(process.cwd(), targetPath) || "."}`);
32472
32588
  console.error(` # edit src/App.tsx`);
32473
32589
  console.error(` lotics app deploy`);
32474
32590
  }
@@ -32484,21 +32600,21 @@ function undeclaredCapabilities(sourceText, declared) {
32484
32600
  return used;
32485
32601
  }
32486
32602
  function readAppSourceText(projectDir) {
32487
- const srcDir = path4.join(projectDir, "src");
32488
- if (!fs3.existsSync(srcDir)) return "";
32603
+ const srcDir = path5.join(projectDir, "src");
32604
+ if (!fs4.existsSync(srcDir)) return "";
32489
32605
  const parts = [];
32490
32606
  const walk2 = (dir) => {
32491
- for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
32492
- const full = path4.join(dir, entry.name);
32607
+ for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
32608
+ const full = path5.join(dir, entry.name);
32493
32609
  if (entry.isDirectory()) walk2(full);
32494
- else if (/\.(ts|tsx|js|jsx)$/.test(entry.name)) parts.push(fs3.readFileSync(full, "utf8"));
32610
+ else if (/\.(ts|tsx|js|jsx)$/.test(entry.name)) parts.push(fs4.readFileSync(full, "utf8"));
32495
32611
  }
32496
32612
  };
32497
32613
  walk2(srcDir);
32498
32614
  return parts.join("\n");
32499
32615
  }
32500
32616
  async function appDeploy(client, args) {
32501
- const projectDir = path4.resolve(args.projectDir ?? process.cwd());
32617
+ const projectDir = path5.resolve(args.projectDir ?? process.cwd());
32502
32618
  const meta = readAppMeta(projectDir);
32503
32619
  const undeclared = undeclaredCapabilities(readAppSourceText(projectDir), meta.capabilities);
32504
32620
  if (undeclared.length > 0) {
@@ -32512,14 +32628,14 @@ async function appDeploy(client, args) {
32512
32628
  writeAppDts(projectDir, { workflows: meta.workflows, queries: meta.queries, agents: meta.agents });
32513
32629
  console.error("Building...");
32514
32630
  await runNpm(["run", "build"], projectDir);
32515
- const distDir = path4.join(projectDir, "dist");
32516
- if (!fs3.existsSync(distDir)) {
32631
+ const distDir = path5.join(projectDir, "dist");
32632
+ if (!fs4.existsSync(distDir)) {
32517
32633
  throw new Error(
32518
32634
  `Build did not produce a dist/ directory in ${projectDir}. Check that 'npm run build' is configured correctly (Vite/etc. defaults to dist/).`
32519
32635
  );
32520
32636
  }
32521
- const tmpSource = path4.join(tmpdir(), `lotics-source-${Date.now()}.tar.gz`);
32522
- const tmpDist = path4.join(tmpdir(), `lotics-dist-${Date.now()}.tar.gz`);
32637
+ const tmpSource = path5.join(tmpdir(), `lotics-source-${Date.now()}.tar.gz`);
32638
+ const tmpDist = path5.join(tmpdir(), `lotics-dist-${Date.now()}.tar.gz`);
32523
32639
  try {
32524
32640
  console.error("Packaging source...");
32525
32641
  await runTar(
@@ -32541,8 +32657,8 @@ async function appDeploy(client, args) {
32541
32657
  try {
32542
32658
  const result = await client.deployAppVersion({
32543
32659
  app_id: meta.app_id,
32544
- source_archive: fs3.readFileSync(tmpSource),
32545
- dist_archive: fs3.readFileSync(tmpDist),
32660
+ source_archive: fs4.readFileSync(tmpSource),
32661
+ dist_archive: fs4.readFileSync(tmpDist),
32546
32662
  prev_version_id: meta.current_version_id,
32547
32663
  message: args.message,
32548
32664
  // Sync apps.queries from the manifest. Server validates each query
@@ -32576,8 +32692,8 @@ async function appDeploy(client, args) {
32576
32692
  throw err2;
32577
32693
  }
32578
32694
  } finally {
32579
- if (fs3.existsSync(tmpSource)) fs3.unlinkSync(tmpSource);
32580
- if (fs3.existsSync(tmpDist)) fs3.unlinkSync(tmpDist);
32695
+ if (fs4.existsSync(tmpSource)) fs4.unlinkSync(tmpSource);
32696
+ if (fs4.existsSync(tmpDist)) fs4.unlinkSync(tmpDist);
32581
32697
  }
32582
32698
  }
32583
32699
  async function warnIfUnbranded(client, appId) {
@@ -32598,7 +32714,7 @@ async function warnIfUnbranded(client, appId) {
32598
32714
  }
32599
32715
  }
32600
32716
  async function appDev(client, args) {
32601
- const projectDir = path4.resolve(args.projectDir ?? process.cwd());
32717
+ const projectDir = path5.resolve(args.projectDir ?? process.cwd());
32602
32718
  const meta = readAppMeta(projectDir);
32603
32719
  writeAppDts(projectDir, { workflows: meta.workflows, queries: meta.queries, agents: meta.agents });
32604
32720
  const app = await client.getApp(meta.app_id);
@@ -32737,15 +32853,15 @@ async function appWorkflowSet(client, args) {
32737
32853
  process.exit(1);
32738
32854
  }
32739
32855
  const file = workflowFilePath(projectDir, args.alias);
32740
- if (!fs3.existsSync(file)) {
32856
+ if (!fs4.existsSync(file)) {
32741
32857
  console.error(
32742
- `No workflow body at ${path4.relative(projectDir, file)}. Run 'lotics app pull ${meta.app_id}' to write src/workflows/${args.alias}.ts, then edit it.`
32858
+ `No workflow body at ${path5.relative(projectDir, file)}. Run 'lotics app pull ${meta.app_id}' to write src/workflows/${args.alias}.ts, then edit it.`
32743
32859
  );
32744
32860
  process.exit(1);
32745
32861
  }
32746
- const source = stripWorkflowHeader(fs3.readFileSync(file, "utf-8"));
32862
+ const source = stripWorkflowHeader(fs4.readFileSync(file, "utf-8"));
32747
32863
  if (source.trim() === "") {
32748
- console.error(`Workflow body ${path4.relative(projectDir, file)} is empty after stripping the header.`);
32864
+ console.error(`Workflow body ${path5.relative(projectDir, file)} is empty after stripping the header.`);
32749
32865
  process.exit(1);
32750
32866
  }
32751
32867
  const res = await client.setAppWorkflow(meta.app_id, args.alias, {
@@ -32777,22 +32893,97 @@ async function appWorkflowPull(client) {
32777
32893
  console.error(
32778
32894
  `Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/` + (written.length > 0 ? ` (${written.join(", ")})` : "")
32779
32895
  );
32896
+ ensureWorkflowTsconfigExcludes(projectDir);
32897
+ }
32898
+ async function appWorkflowCheck(args) {
32899
+ const projectDir = process.cwd();
32900
+ const meta = readAppMeta(projectDir);
32901
+ const bound = Object.keys(meta.workflows ?? {});
32902
+ let aliases;
32903
+ if (args.alias) {
32904
+ if (!bound.includes(args.alias)) {
32905
+ console.error(
32906
+ `No workflow "${args.alias}" in package.json#lotics.workflows. Bound aliases: ${bound.length > 0 ? bound.join(", ") : "(none)"}.`
32907
+ );
32908
+ process.exit(1);
32909
+ }
32910
+ aliases = [args.alias];
32911
+ } else {
32912
+ aliases = bound;
32913
+ }
32914
+ if (aliases.length === 0) {
32915
+ console.error(`App ${meta.app_id} has no bound workflows to check.`);
32916
+ return;
32917
+ }
32918
+ const toCheck = [];
32919
+ for (const alias of aliases) {
32920
+ const bodyPath = workflowFilePath(projectDir, alias);
32921
+ const globalsPath = workflowGlobalsPath(projectDir, alias);
32922
+ if (!fs4.existsSync(bodyPath)) {
32923
+ console.error(
32924
+ `\u26A0 Skipped "${alias}" \u2014 no body at ${path5.relative(projectDir, bodyPath)}. Run 'lotics app workflow pull' to write it.`
32925
+ );
32926
+ continue;
32927
+ }
32928
+ if (!fs4.existsSync(globalsPath)) {
32929
+ console.error(
32930
+ `Cannot check "${alias}" \u2014 missing types at ${path5.relative(projectDir, globalsPath)}. Run 'lotics app workflow pull' (or 'lotics app codegen') to fetch them.`
32931
+ );
32932
+ process.exit(1);
32933
+ }
32934
+ toCheck.push({ alias, input: { bodyPath, globalsPath } });
32935
+ }
32936
+ if (toCheck.length === 0) {
32937
+ console.error("No workflow bodies to check (every bound alias was skipped).");
32938
+ return;
32939
+ }
32940
+ const tsApi = await loadProjectTypescript(projectDir);
32941
+ const results = checkWorkflowBodies(tsApi, toCheck);
32942
+ printWorkflowCheckResults(projectDir, results);
32943
+ const failed = results.filter((r) => r.issues.length > 0);
32944
+ if (failed.length > 0) process.exit(1);
32945
+ }
32946
+ function printWorkflowCheckResults(projectDir, results) {
32947
+ let totalErrors = 0;
32948
+ for (const r of results) {
32949
+ const rel = path5.relative(projectDir, r.bodyPath);
32950
+ if (r.issues.length === 0) {
32951
+ console.error(`\u2713 ${r.alias} (${rel}) \u2014 no type errors`);
32952
+ continue;
32953
+ }
32954
+ totalErrors += r.issues.length;
32955
+ console.error(
32956
+ `\u2717 ${r.alias} (${rel}) \u2014 ${r.issues.length} error${r.issues.length === 1 ? "" : "s"}:`
32957
+ );
32958
+ for (const issue of r.issues) {
32959
+ const [first2, ...rest] = issue.message.split("\n");
32960
+ console.error(` ${rel}:${issue.line}:${issue.col} - ${issue.code}: ${first2}`);
32961
+ for (const line of rest) console.error(` ${line}`);
32962
+ }
32963
+ }
32964
+ const passed = results.length - results.filter((r) => r.issues.length > 0).length;
32965
+ console.error(
32966
+ totalErrors === 0 ? results.length === 1 ? `
32967
+ The workflow body type-checks clean.` : `
32968
+ All ${results.length} workflow bodies type-check clean.` : `
32969
+ ${totalErrors} error${totalErrors === 1 ? "" : "s"} across ${results.length - passed} of ${results.length} ${results.length === 1 ? "body" : "bodies"}.`
32970
+ );
32780
32971
  }
32781
32972
  function findUiSrcDir(start) {
32782
- let dir = path4.resolve(start);
32973
+ let dir = path5.resolve(start);
32783
32974
  for (; ; ) {
32784
- const candidate = path4.join(dir, "packages", "ui", "src");
32785
- if (fs3.existsSync(candidate) && fs3.statSync(candidate).isDirectory()) return candidate;
32786
- const parent = path4.dirname(dir);
32975
+ const candidate = path5.join(dir, "packages", "ui", "src");
32976
+ if (fs4.existsSync(candidate) && fs4.statSync(candidate).isDirectory()) return candidate;
32977
+ const parent = path5.dirname(dir);
32787
32978
  if (parent === dir) return null;
32788
32979
  dir = parent;
32789
32980
  }
32790
32981
  }
32791
32982
  var UI_ALIAS_FIND_SOURCE = String.raw`/^@lotics\/ui\/(.+)$/`;
32792
32983
  function appUiLink(args) {
32793
- const projectDir = path4.resolve(args.projectDir ?? process.cwd());
32794
- const viteConfigPath = path4.join(projectDir, "vite.config.ts");
32795
- if (!fs3.existsSync(viteConfigPath)) {
32984
+ const projectDir = path5.resolve(args.projectDir ?? process.cwd());
32985
+ const viteConfigPath = path5.join(projectDir, "vite.config.ts");
32986
+ if (!fs4.existsSync(viteConfigPath)) {
32796
32987
  throw new Error(
32797
32988
  `No vite.config.ts at ${projectDir}. Run inside a 'lotics app' project directory.`
32798
32989
  );
@@ -32803,13 +32994,13 @@ function appUiLink(args) {
32803
32994
  "Cannot find packages/ui/src by walking up from this directory \u2014 `lotics ui link` requires a monorepo checkout. External apps consume @lotics/ui from npm; bump the package version and widen the app's dependency range instead."
32804
32995
  );
32805
32996
  }
32806
- const hasComponent = fs3.existsSync(path4.join(uiSrc, `${args.component}.tsx`)) || fs3.existsSync(path4.join(uiSrc, `${args.component}.ts`)) || fs3.existsSync(path4.join(uiSrc, args.component));
32997
+ const hasComponent = fs4.existsSync(path5.join(uiSrc, `${args.component}.tsx`)) || fs4.existsSync(path5.join(uiSrc, `${args.component}.ts`)) || fs4.existsSync(path5.join(uiSrc, args.component));
32807
32998
  if (!hasComponent) {
32808
32999
  throw new Error(
32809
33000
  `No '@lotics/ui/${args.component}' under ${uiSrc} (expected ${args.component}.tsx/.ts). Check the component name.`
32810
33001
  );
32811
33002
  }
32812
- const source = fs3.readFileSync(viteConfigPath, "utf-8");
33003
+ const source = fs4.readFileSync(viteConfigPath, "utf-8");
32813
33004
  const aliasEntry = `{ find: ${UI_ALIAS_FIND_SOURCE}, replacement: ${JSON.stringify(`${uiSrc}/$1`)} },`;
32814
33005
  const alreadyLinked = source.includes(UI_ALIAS_FIND_SOURCE);
32815
33006
  if (args.remove) {
@@ -32818,7 +33009,7 @@ function appUiLink(args) {
32818
33009
  return;
32819
33010
  }
32820
33011
  const stripped = source.replace(new RegExp(`^\\s*\\{ find: ${escapeRegExp(UI_ALIAS_FIND_SOURCE)}.*$\\n?`, "m"), "");
32821
- fs3.writeFileSync(viteConfigPath, stripped);
33012
+ fs4.writeFileSync(viteConfigPath, stripped);
32822
33013
  console.error(`Removed the @lotics/ui dev-link alias from ${viteConfigPath}.`);
32823
33014
  console.error("Restart `lotics app dev` and rm -rf node_modules/.vite to clear cached modules.");
32824
33015
  return;
@@ -32836,7 +33027,7 @@ function appUiLink(args) {
32836
33027
  const insertAt = aliasMatch.index + aliasMatch[0].length;
32837
33028
  const updated = `${source.slice(0, insertAt)}
32838
33029
  ${aliasEntry}${source.slice(insertAt)}`;
32839
- fs3.writeFileSync(viteConfigPath, updated);
33030
+ fs4.writeFileSync(viteConfigPath, updated);
32840
33031
  console.error(`Dev-linked @lotics/ui \u2192 ${uiSrc} in ${viteConfigPath}.`);
32841
33032
  console.error("Restart `lotics app dev` and rm -rf node_modules/.vite to clear cached modules.");
32842
33033
  console.error("Finalize: PR the packages/ui change \u2192 publish \u2192 `lotics ui link <component> --remove` + bump the app's dep.");
@@ -32973,11 +33164,11 @@ async function ingestJsonArgs(opts) {
32973
33164
  }
32974
33165
 
32975
33166
  // src/xlsx.ts
32976
- import fs5 from "node:fs";
33167
+ import fs6 from "node:fs";
32977
33168
 
32978
33169
  // src/file_command_io.ts
32979
- import fs4 from "node:fs";
32980
- import path5 from "node:path";
33170
+ import fs5 from "node:fs";
33171
+ import path6 from "node:path";
32981
33172
  var CliError = class extends Error {
32982
33173
  constructor(message) {
32983
33174
  super(message);
@@ -32988,14 +33179,14 @@ function fail(message) {
32988
33179
  throw new CliError(message);
32989
33180
  }
32990
33181
  function writeFileAtomic(filePath, bytes) {
32991
- const dir = path5.dirname(path5.resolve(filePath));
32992
- const tmp = path5.join(dir, `.${path5.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
32993
- fs4.writeFileSync(tmp, bytes);
33182
+ const dir = path6.dirname(path6.resolve(filePath));
33183
+ const tmp = path6.join(dir, `.${path6.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
33184
+ fs5.writeFileSync(tmp, bytes);
32994
33185
  try {
32995
- fs4.renameSync(tmp, filePath);
33186
+ fs5.renameSync(tmp, filePath);
32996
33187
  } catch (error) {
32997
33188
  try {
32998
- fs4.unlinkSync(tmp);
33189
+ fs5.unlinkSync(tmp);
32999
33190
  } catch {
33000
33191
  }
33001
33192
  throw error;
@@ -35778,16 +35969,16 @@ var MatcherView = class {
35778
35969
  * @returns {string|undefined}
35779
35970
  */
35780
35971
  getCurrentTag() {
35781
- const path7 = this._matcher.path;
35782
- return path7.length > 0 ? path7[path7.length - 1].tag : void 0;
35972
+ const path8 = this._matcher.path;
35973
+ return path8.length > 0 ? path8[path8.length - 1].tag : void 0;
35783
35974
  }
35784
35975
  /**
35785
35976
  * Get current namespace.
35786
35977
  * @returns {string|undefined}
35787
35978
  */
35788
35979
  getCurrentNamespace() {
35789
- const path7 = this._matcher.path;
35790
- return path7.length > 0 ? path7[path7.length - 1].namespace : void 0;
35980
+ const path8 = this._matcher.path;
35981
+ return path8.length > 0 ? path8[path8.length - 1].namespace : void 0;
35791
35982
  }
35792
35983
  /**
35793
35984
  * Get current node's attribute value.
@@ -35795,9 +35986,9 @@ var MatcherView = class {
35795
35986
  * @returns {*}
35796
35987
  */
35797
35988
  getAttrValue(attrName) {
35798
- const path7 = this._matcher.path;
35799
- if (path7.length === 0) return void 0;
35800
- return path7[path7.length - 1].values?.[attrName];
35989
+ const path8 = this._matcher.path;
35990
+ if (path8.length === 0) return void 0;
35991
+ return path8[path8.length - 1].values?.[attrName];
35801
35992
  }
35802
35993
  /**
35803
35994
  * Check if current node has an attribute.
@@ -35805,9 +35996,9 @@ var MatcherView = class {
35805
35996
  * @returns {boolean}
35806
35997
  */
35807
35998
  hasAttr(attrName) {
35808
- const path7 = this._matcher.path;
35809
- if (path7.length === 0) return false;
35810
- const current = path7[path7.length - 1];
35999
+ const path8 = this._matcher.path;
36000
+ if (path8.length === 0) return false;
36001
+ const current = path8[path8.length - 1];
35811
36002
  return current.values !== void 0 && attrName in current.values;
35812
36003
  }
35813
36004
  /**
@@ -35815,18 +36006,18 @@ var MatcherView = class {
35815
36006
  * @returns {number}
35816
36007
  */
35817
36008
  getPosition() {
35818
- const path7 = this._matcher.path;
35819
- if (path7.length === 0) return -1;
35820
- return path7[path7.length - 1].position ?? 0;
36009
+ const path8 = this._matcher.path;
36010
+ if (path8.length === 0) return -1;
36011
+ return path8[path8.length - 1].position ?? 0;
35821
36012
  }
35822
36013
  /**
35823
36014
  * Get current node's repeat counter (occurrence count of this tag name).
35824
36015
  * @returns {number}
35825
36016
  */
35826
36017
  getCounter() {
35827
- const path7 = this._matcher.path;
35828
- if (path7.length === 0) return -1;
35829
- return path7[path7.length - 1].counter ?? 0;
36018
+ const path8 = this._matcher.path;
36019
+ if (path8.length === 0) return -1;
36020
+ return path8[path8.length - 1].counter ?? 0;
35830
36021
  }
35831
36022
  /**
35832
36023
  * Get current node's sibling index (alias for getPosition).
@@ -37681,8 +37872,8 @@ function isAttribute(name) {
37681
37872
  }
37682
37873
 
37683
37874
  // ../../node_modules/fflate/esm/index.mjs
37684
- import { createRequire } from "module";
37685
- var require2 = createRequire("/");
37875
+ import { createRequire as createRequire2 } from "module";
37876
+ var require2 = createRequire2("/");
37686
37877
  var Worker;
37687
37878
  try {
37688
37879
  Worker = require2("worker_threads").Worker;
@@ -41282,10 +41473,10 @@ function resolveRelativePath(basePath, relativePath) {
41282
41473
  }
41283
41474
  return resolved.join("/");
41284
41475
  }
41285
- function findZipEntry(zipEntries, path7) {
41286
- if (zipEntries[path7]) return zipEntries[path7];
41287
- if (zipEntries[`xl/${path7}`]) return zipEntries[`xl/${path7}`];
41288
- const noSlash = path7.replace(/^\//, "");
41476
+ function findZipEntry(zipEntries, path8) {
41477
+ if (zipEntries[path8]) return zipEntries[path8];
41478
+ if (zipEntries[`xl/${path8}`]) return zipEntries[`xl/${path8}`];
41479
+ const noSlash = path8.replace(/^\//, "");
41289
41480
  if (zipEntries[noSlash]) return zipEntries[noSlash];
41290
41481
  return void 0;
41291
41482
  }
@@ -42583,9 +42774,9 @@ function parseExcelFromZip(zip, options) {
42583
42774
  }
42584
42775
  return result;
42585
42776
  }
42586
- function findEntry(zip, path7) {
42587
- if (zip[path7]) return zip[path7];
42588
- const lower = path7.toLowerCase();
42777
+ function findEntry(zip, path8) {
42778
+ if (zip[path8]) return zip[path8];
42779
+ const lower = path8.toLowerCase();
42589
42780
  for (const key of Object.keys(zip)) {
42590
42781
  if (key.toLowerCase() === lower) return zip[key];
42591
42782
  }
@@ -43196,12 +43387,12 @@ function extractPivotRoundTripInfo(originalZip) {
43196
43387
  if (paths.length > 0) pivotTablesBySheetIndex.set(i2, paths);
43197
43388
  }
43198
43389
  const pivotXmlPaths = [];
43199
- for (const path7 of Object.keys(originalZip)) {
43200
- if (path7.startsWith("xl/pivotTables/") && path7.endsWith(".xml")) {
43201
- pivotXmlPaths.push(path7);
43390
+ for (const path8 of Object.keys(originalZip)) {
43391
+ if (path8.startsWith("xl/pivotTables/") && path8.endsWith(".xml")) {
43392
+ pivotXmlPaths.push(path8);
43202
43393
  }
43203
- if (path7.startsWith("xl/pivotCache/") && path7.endsWith(".xml")) {
43204
- pivotXmlPaths.push(path7);
43394
+ if (path8.startsWith("xl/pivotCache/") && path8.endsWith(".xml")) {
43395
+ pivotXmlPaths.push(path8);
43205
43396
  }
43206
43397
  }
43207
43398
  return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths };
@@ -43209,15 +43400,15 @@ function extractPivotRoundTripInfo(originalZip) {
43209
43400
  function decode(bytes) {
43210
43401
  return new TextDecoder().decode(bytes);
43211
43402
  }
43212
- function pivotContentTypeFor(path7) {
43213
- if (path7.startsWith("xl/pivotTables/") && path7.endsWith(".xml")) {
43214
- return `<Override PartName="/${path7}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
43403
+ function pivotContentTypeFor(path8) {
43404
+ if (path8.startsWith("xl/pivotTables/") && path8.endsWith(".xml")) {
43405
+ return `<Override PartName="/${path8}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
43215
43406
  }
43216
- if (path7.includes("/pivotCacheDefinition") && path7.endsWith(".xml")) {
43217
- return `<Override PartName="/${path7}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
43407
+ if (path8.includes("/pivotCacheDefinition") && path8.endsWith(".xml")) {
43408
+ return `<Override PartName="/${path8}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
43218
43409
  }
43219
- if (path7.includes("/pivotCacheRecords") && path7.endsWith(".xml")) {
43220
- return `<Override PartName="/${path7}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
43410
+ if (path8.includes("/pivotCacheRecords") && path8.endsWith(".xml")) {
43411
+ return `<Override PartName="/${path8}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
43221
43412
  }
43222
43413
  return void 0;
43223
43414
  }
@@ -43289,13 +43480,13 @@ function exportWorkbook(workbook, originalZip) {
43289
43480
  regeneratedPaths.add(`xl/worksheets/sheet${i2 + 1}.xml`);
43290
43481
  regeneratedPaths.add(`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`);
43291
43482
  }
43292
- for (const path7 of Object.keys(originalZip)) {
43293
- if (path7.startsWith("xl/drawings/") || path7.startsWith("xl/charts/") || path7.startsWith("xl/tables/") || path7.startsWith("xl/media/")) {
43294
- regeneratedPaths.add(path7);
43483
+ for (const path8 of Object.keys(originalZip)) {
43484
+ if (path8.startsWith("xl/drawings/") || path8.startsWith("xl/charts/") || path8.startsWith("xl/tables/") || path8.startsWith("xl/media/")) {
43485
+ regeneratedPaths.add(path8);
43295
43486
  }
43296
43487
  }
43297
- for (const [path7, data] of Object.entries(originalZip)) {
43298
- if (!regeneratedPaths.has(path7)) entries[path7] = data;
43488
+ for (const [path8, data] of Object.entries(originalZip)) {
43489
+ if (!regeneratedPaths.has(path8)) entries[path8] = data;
43299
43490
  }
43300
43491
  }
43301
43492
  const sharedStrings = buildSharedStrings(workbook);
@@ -43310,8 +43501,8 @@ function exportWorkbook(workbook, originalZip) {
43310
43501
  buildWorkbookRels(workbook, pivotInfo)
43311
43502
  );
43312
43503
  const extraContentTypes = [];
43313
- for (const path7 of pivotInfo.pivotXmlPaths) {
43314
- const ct = pivotContentTypeFor(path7);
43504
+ for (const path8 of pivotInfo.pivotXmlPaths) {
43505
+ const ct = pivotContentTypeFor(path8);
43315
43506
  if (ct) extraContentTypes.push(ct);
43316
43507
  }
43317
43508
  let globalChartIndex = 1;
@@ -45072,14 +45263,14 @@ var DependencyGraph = class {
45072
45263
  stack.push({ cell: p, path: [cell, p] });
45073
45264
  }
45074
45265
  while (stack.length > 0) {
45075
- const { cell: current, path: path7 } = stack.pop();
45076
- if (current === cell) return path7;
45266
+ const { cell: current, path: path8 } = stack.pop();
45267
+ if (current === cell) return path8;
45077
45268
  if (visited.has(current)) continue;
45078
45269
  visited.add(current);
45079
45270
  const nextPrec = this.precedents.get(current);
45080
45271
  if (!nextPrec) continue;
45081
45272
  for (const p of nextPrec) {
45082
- stack.push({ cell: p, path: [...path7, p] });
45273
+ stack.push({ cell: p, path: [...path8, p] });
45083
45274
  }
45084
45275
  }
45085
45276
  return null;
@@ -46070,8 +46261,8 @@ function adjustMergedCellsForColDelete(sheet, atCol, count) {
46070
46261
 
46071
46262
  // src/xlsx.ts
46072
46263
  function loadFile(filePath) {
46073
- if (!fs5.existsSync(filePath)) fail(`File not found: ${filePath}`);
46074
- const buffer = fs5.readFileSync(filePath);
46264
+ if (!fs6.existsSync(filePath)) fail(`File not found: ${filePath}`);
46265
+ const buffer = fs6.readFileSync(filePath);
46075
46266
  const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
46076
46267
  const originalZip = unzipXlsx(arrayBuffer);
46077
46268
  const parsed = parseExcelBuffer(arrayBuffer);
@@ -46121,7 +46312,7 @@ function lazyEngine(workbook) {
46121
46312
  };
46122
46313
  }
46123
46314
  function readToJson(filePath) {
46124
- const buffer = fs5.readFileSync(filePath);
46315
+ const buffer = fs6.readFileSync(filePath);
46125
46316
  const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
46126
46317
  const parsed = parseExcelBuffer(arrayBuffer);
46127
46318
  return {
@@ -46511,7 +46702,7 @@ async function runXlsxCommand(subcommand, toolArgs, restArgs) {
46511
46702
  }
46512
46703
 
46513
46704
  // src/docx.ts
46514
- import fs6 from "node:fs";
46705
+ import fs7 from "node:fs";
46515
46706
 
46516
46707
  // ../docx/src/parse/parser.ts
46517
46708
  var import_jszip = __toESM(require_lib3(), 1);
@@ -48282,11 +48473,11 @@ async function parseDocx(buffer) {
48282
48473
  const zip = await import_jszip.default.loadAsync(buffer);
48283
48474
  const parts = /* @__PURE__ */ new Map();
48284
48475
  const filePromises = [];
48285
- zip.forEach((path7, file) => {
48476
+ zip.forEach((path8, file) => {
48286
48477
  if (file.dir) return;
48287
48478
  filePromises.push(
48288
48479
  file.async("uint8array").then((bytes) => {
48289
- parts.set(path7, bytes);
48480
+ parts.set(path8, bytes);
48290
48481
  })
48291
48482
  );
48292
48483
  });
@@ -48515,9 +48706,9 @@ var DEFAULT_PARTS = [
48515
48706
  ["word/theme/theme1.xml", () => encoder.encode(THEME_XML)]
48516
48707
  ];
48517
48708
  function fillDefaultParts(parts) {
48518
- for (const [path7, makeBytes] of DEFAULT_PARTS) {
48519
- if (!parts.has(path7)) {
48520
- parts.set(path7, makeBytes());
48709
+ for (const [path8, makeBytes] of DEFAULT_PARTS) {
48710
+ if (!parts.has(path8)) {
48711
+ parts.set(path8, makeBytes());
48521
48712
  }
48522
48713
  }
48523
48714
  return parts;
@@ -48527,9 +48718,9 @@ function fillDefaultParts(parts) {
48527
48718
  async function serializeDocx(doc) {
48528
48719
  const zip = new import_jszip2.default();
48529
48720
  const parts = fillDefaultParts(new Map(doc.parts));
48530
- for (const [path7, bytes] of parts) {
48531
- if (path7 === "word/document.xml") continue;
48532
- zip.file(path7, bytes);
48721
+ for (const [path8, bytes] of parts) {
48722
+ if (path8 === "word/document.xml") continue;
48723
+ zip.file(path8, bytes);
48533
48724
  }
48534
48725
  const documentXml = serializeDocumentXml(doc);
48535
48726
  zip.file("word/document.xml", documentXml);
@@ -48615,8 +48806,8 @@ var DEFAULT_DOC_ATTRS = {
48615
48806
  "@_xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
48616
48807
  };
48617
48808
  async function loadFile2(filePath) {
48618
- if (!fs6.existsSync(filePath)) fail(`File not found: ${filePath}`);
48619
- const bytes = fs6.readFileSync(filePath);
48809
+ if (!fs7.existsSync(filePath)) fail(`File not found: ${filePath}`);
48810
+ const bytes = fs7.readFileSync(filePath);
48620
48811
  return parseDocx(new Uint8Array(bytes));
48621
48812
  }
48622
48813
  async function writeDoc(filePath, doc) {
@@ -48973,6 +49164,8 @@ COMMANDS
48973
49164
  lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body
48974
49165
  through set_app_workflow (server verifies)
48975
49166
  lotics app workflow pull Rewrite src/workflows/*.ts from the server
49167
+ lotics app workflow check [alias] Typecheck src/workflows bodies locally (one
49168
+ isolated program per alias; the app's own tsc)
48976
49169
  lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address
48977
49170
  lotics app rename "<new name>" Rename the app's display name (launcher title)
48978
49171
  lotics app dev [path] Run the app locally with HMR (RPC forwarded to prod)
@@ -49080,8 +49273,8 @@ function prompt(question) {
49080
49273
  });
49081
49274
  });
49082
49275
  }
49083
- async function publicPost(path7, body) {
49084
- const response = await fetch(`${API_BASE_URL}${path7}`, {
49276
+ async function publicPost(path8, body) {
49277
+ const response = await fetch(`${API_BASE_URL}${path8}`, {
49085
49278
  method: "POST",
49086
49279
  headers: { "Content-Type": "application/json" },
49087
49280
  body: JSON.stringify(body)
@@ -49227,13 +49420,13 @@ async function resolveWorkspace(client, ctx) {
49227
49420
  function resolveUploadPaths(rawPaths) {
49228
49421
  const result = [];
49229
49422
  for (const p of rawPaths) {
49230
- const resolved = path6.resolve(p);
49231
- const stat = fs7.statSync(resolved);
49423
+ const resolved = path7.resolve(p);
49424
+ const stat = fs8.statSync(resolved);
49232
49425
  if (stat.isDirectory()) {
49233
- const entries = fs7.readdirSync(resolved, { withFileTypes: true });
49426
+ const entries = fs8.readdirSync(resolved, { withFileTypes: true });
49234
49427
  for (const entry of entries) {
49235
49428
  if (entry.isFile()) {
49236
- result.push(path6.join(resolved, entry.name));
49429
+ result.push(path7.join(resolved, entry.name));
49237
49430
  }
49238
49431
  }
49239
49432
  } else {
@@ -49352,6 +49545,10 @@ async function main() {
49352
49545
  console.error("Usage: lotics ui link <component> [--remove]");
49353
49546
  process.exit(1);
49354
49547
  }
49548
+ if (command === "app" && subcommand === "workflow" && toolArgs === "check") {
49549
+ await appWorkflowCheck({ alias: restArgs[0] });
49550
+ return;
49551
+ }
49355
49552
  if (command === "app" && subcommand === "codegen") {
49356
49553
  const projectDir = toolArgs;
49357
49554
  const ctx2 = resolveContext(flags);
@@ -49436,6 +49633,7 @@ async function main() {
49436
49633
  console.error(" lotics app workflow run <alias> '<json>' Execute a bound app workflow end-to-end");
49437
49634
  console.error(" lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body");
49438
49635
  console.error(" lotics app workflow pull Rewrite src/workflows/*.ts from the server");
49636
+ console.error(" lotics app workflow check [alias] Typecheck src/workflows bodies locally");
49439
49637
  console.error(" lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address");
49440
49638
  console.error(` lotics app rename "<new name>" Rename the app's display name (launcher title)`);
49441
49639
  console.error(" lotics app dev [path] Run the app locally with HMR + RPC forwarding");
@@ -49584,6 +49782,7 @@ Available workspaces:`);
49584
49782
  console.error(" lotics app workflow run <alias> '<json>' Execute a bound app workflow");
49585
49783
  console.error(" lotics app workflow set <alias> Push src/workflows/<alias>.ts");
49586
49784
  console.error(" lotics app workflow pull Rewrite src/workflows/*.ts from the server");
49785
+ console.error(" lotics app workflow check [alias] Typecheck src/workflows bodies locally");
49587
49786
  process.exit(1);
49588
49787
  };
49589
49788
  if (action === "run") {
@@ -49599,7 +49798,7 @@ Available workspaces:`);
49599
49798
  const ingested = await ingestJsonArgs({
49600
49799
  rawArg: restArgs[1],
49601
49800
  stdinIsTTY: process.stdin.isTTY ?? false,
49602
- readFile: (p) => fs7.readFileSync(p, "utf-8"),
49801
+ readFile: (p) => fs8.readFileSync(p, "utf-8"),
49603
49802
  readStdin
49604
49803
  });
49605
49804
  if (ingested.kind === "error") {
@@ -49731,7 +49930,7 @@ ${JSON.stringify(info.input_schema, null, 2)}`);
49731
49930
  const ingested = await ingestJsonArgs({
49732
49931
  rawArg: toolArgs,
49733
49932
  stdinIsTTY: process.stdin.isTTY ?? false,
49734
- readFile: (p) => fs7.readFileSync(p, "utf-8"),
49933
+ readFile: (p) => fs8.readFileSync(p, "utf-8"),
49735
49934
  readStdin
49736
49935
  });
49737
49936
  if (ingested.kind === "error") {