@lotics/cli 0.60.1 → 0.62.1
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/README.md +3 -2
- package/dist/app_commands.d.ts +41 -0
- package/dist/app_commands.js +199 -10
- package/dist/app_commands.test.js +69 -1
- package/dist/app_workflow_check.d.ts +77 -0
- package/dist/app_workflow_check.js +169 -0
- package/dist/app_workflow_check.test.d.ts +1 -0
- package/dist/app_workflow_check.test.js +166 -0
- package/dist/cli.js +13 -1
- package/dist/src/cli.js +435 -233
- package/dist/starter_template.js +25 -41
- package/dist/starter_template.test.js +14 -10
- package/package.json +2 -1
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(
|
|
12247
|
-
utils_1.forEach(
|
|
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 =
|
|
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,
|
|
14014
|
+
function AbstractNextPossibleTokensWalker2(topProd, path8) {
|
|
14015
14015
|
var _this = _super.call(this) || this;
|
|
14016
14016
|
_this.topProd = topProd;
|
|
14017
|
-
_this.path =
|
|
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,
|
|
14072
|
-
var _this = _super.call(this, topProd,
|
|
14073
|
-
_this.path =
|
|
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(
|
|
14770
|
+
function pathToHashKeys(path8) {
|
|
14771
14771
|
var keys2 = [""];
|
|
14772
|
-
for (var i2 = 0; i2 <
|
|
14773
|
-
var tokType =
|
|
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,
|
|
15086
|
-
if (
|
|
15087
|
-
|
|
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:
|
|
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,
|
|
15106
|
+
var validNextSteps = utils.difference(nextNonTerminals, path8.concat([topRule]));
|
|
15107
15107
|
var errorsFromNextSteps = utils.map(validNextSteps, function(currRefRule) {
|
|
15108
|
-
var newPath = utils.cloneArr(
|
|
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(
|
|
22718
|
-
var parts =
|
|
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(
|
|
28572
|
-
if (
|
|
28573
|
-
|
|
28571
|
+
var parentFolder = function(path8) {
|
|
28572
|
+
if (path8.slice(-1) === "/") {
|
|
28573
|
+
path8 = path8.substring(0, path8.length - 1);
|
|
28574
28574
|
}
|
|
28575
|
-
var lastSlash =
|
|
28576
|
-
return lastSlash > 0 ?
|
|
28575
|
+
var lastSlash = path8.lastIndexOf("/");
|
|
28576
|
+
return lastSlash > 0 ? path8.substring(0, lastSlash) : "";
|
|
28577
28577
|
};
|
|
28578
|
-
var forceTrailingSlash = function(
|
|
28579
|
-
if (
|
|
28580
|
-
|
|
28578
|
+
var forceTrailingSlash = function(path8) {
|
|
28579
|
+
if (path8.slice(-1) !== "/") {
|
|
28580
|
+
path8 += "/";
|
|
28581
28581
|
}
|
|
28582
|
-
return
|
|
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
|
|
29585
|
-
import
|
|
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,
|
|
29684
|
-
const url = `${this.baseUrl}${
|
|
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
|
|
30346
|
-
import
|
|
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
|
-
|
|
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)
|
|
30451
|
-
//
|
|
30452
|
-
//
|
|
30453
|
-
//
|
|
30454
|
-
//
|
|
30455
|
-
//
|
|
30456
|
-
// `
|
|
30457
|
-
//
|
|
30458
|
-
|
|
30459
|
-
|
|
30460
|
-
|
|
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
|
|
30861
|
-
options:
|
|
30835
|
+
locally typecheckable:
|
|
30862
30836
|
|
|
30863
30837
|
\`\`\`bash
|
|
30864
|
-
|
|
30838
|
+
lotics app workflow check # check every body; [alias] to check one
|
|
30865
30839
|
\`\`\`
|
|
30866
30840
|
|
|
30867
|
-
|
|
30868
|
-
|
|
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
|
|
@@ -30905,6 +30882,9 @@ declare module "lucide-react-native/dist/esm/icons/*" {
|
|
|
30905
30882
|
const classes: { [key: string]: string };
|
|
30906
30883
|
export default classes;
|
|
30907
30884
|
}
|
|
30885
|
+
|
|
30886
|
+
// Plain side-effect CSS imports (@lotics/ui ships .tsx with import "./x.css").
|
|
30887
|
+
declare module "*.css";
|
|
30908
30888
|
`
|
|
30909
30889
|
},
|
|
30910
30890
|
{
|
|
@@ -32119,6 +32099,98 @@ export type AppOptions = typeof OPT;
|
|
|
32119
32099
|
`;
|
|
32120
32100
|
}
|
|
32121
32101
|
|
|
32102
|
+
// src/app_workflow_check.ts
|
|
32103
|
+
import fs3 from "node:fs";
|
|
32104
|
+
import path4 from "node:path";
|
|
32105
|
+
import { createRequire } from "node:module";
|
|
32106
|
+
function workflowCheckCompilerOptions(tsApi) {
|
|
32107
|
+
return {
|
|
32108
|
+
target: tsApi.ScriptTarget.ES2022,
|
|
32109
|
+
module: tsApi.ModuleKind.ESNext,
|
|
32110
|
+
lib: ["lib.es2022.d.ts"],
|
|
32111
|
+
strict: true,
|
|
32112
|
+
noImplicitAny: true,
|
|
32113
|
+
strictNullChecks: true,
|
|
32114
|
+
noImplicitReturns: false,
|
|
32115
|
+
noEmit: true,
|
|
32116
|
+
allowJs: false,
|
|
32117
|
+
isolatedModules: false,
|
|
32118
|
+
skipLibCheck: true,
|
|
32119
|
+
moduleResolution: tsApi.ModuleResolutionKind.NodeNext,
|
|
32120
|
+
types: [],
|
|
32121
|
+
declaration: false
|
|
32122
|
+
};
|
|
32123
|
+
}
|
|
32124
|
+
function bodyLineOffset(wrappedSource) {
|
|
32125
|
+
const lines = wrappedSource.split("\n");
|
|
32126
|
+
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
32127
|
+
if (/^\s*async\s+function\s+__workflow\s*\(/.test(lines[i2])) return i2 + 1;
|
|
32128
|
+
}
|
|
32129
|
+
return 0;
|
|
32130
|
+
}
|
|
32131
|
+
async function loadProjectTypescript(projectDir) {
|
|
32132
|
+
const requireFromProject = createRequire(path4.join(projectDir, "package.json"));
|
|
32133
|
+
let resolved;
|
|
32134
|
+
try {
|
|
32135
|
+
resolved = requireFromProject.resolve("typescript");
|
|
32136
|
+
} catch {
|
|
32137
|
+
throw new Error(
|
|
32138
|
+
`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).`
|
|
32139
|
+
);
|
|
32140
|
+
}
|
|
32141
|
+
const mod = await import(pathToImportUrl(resolved));
|
|
32142
|
+
return mod.default ?? mod;
|
|
32143
|
+
}
|
|
32144
|
+
function pathToImportUrl(p) {
|
|
32145
|
+
const resolved = path4.resolve(p);
|
|
32146
|
+
const prefixed = resolved.startsWith("/") ? resolved : `/${resolved}`;
|
|
32147
|
+
return `file://${prefixed.split(path4.sep).join("/")}`;
|
|
32148
|
+
}
|
|
32149
|
+
function checkOneWorkflowBody(tsApi, input) {
|
|
32150
|
+
const wrapped = fs3.readFileSync(input.bodyPath, "utf-8");
|
|
32151
|
+
const offset = bodyLineOffset(wrapped);
|
|
32152
|
+
const program = tsApi.createProgram({
|
|
32153
|
+
rootNames: [input.globalsPath, input.bodyPath],
|
|
32154
|
+
options: workflowCheckCompilerOptions(tsApi)
|
|
32155
|
+
});
|
|
32156
|
+
const bodyFile = program.getSourceFile(input.bodyPath);
|
|
32157
|
+
if (!bodyFile) {
|
|
32158
|
+
return [
|
|
32159
|
+
{
|
|
32160
|
+
line: 1,
|
|
32161
|
+
col: 1,
|
|
32162
|
+
code: "INTERNAL",
|
|
32163
|
+
message: `workflow check: body file was not loaded (${input.bodyPath})`
|
|
32164
|
+
}
|
|
32165
|
+
];
|
|
32166
|
+
}
|
|
32167
|
+
const issues = [];
|
|
32168
|
+
for (const d of tsApi.getPreEmitDiagnostics(program)) {
|
|
32169
|
+
if (d.file !== bodyFile) continue;
|
|
32170
|
+
let line = 1;
|
|
32171
|
+
let col = 1;
|
|
32172
|
+
if (typeof d.start === "number") {
|
|
32173
|
+
const lc2 = bodyFile.getLineAndCharacterOfPosition(d.start);
|
|
32174
|
+
line = Math.max(1, lc2.line + 1 - offset);
|
|
32175
|
+
col = lc2.character + 1;
|
|
32176
|
+
}
|
|
32177
|
+
issues.push({
|
|
32178
|
+
line,
|
|
32179
|
+
col,
|
|
32180
|
+
code: `TS${d.code}`,
|
|
32181
|
+
message: tsApi.flattenDiagnosticMessageText(d.messageText, "\n")
|
|
32182
|
+
});
|
|
32183
|
+
}
|
|
32184
|
+
return issues;
|
|
32185
|
+
}
|
|
32186
|
+
function checkWorkflowBodies(tsApi, aliases) {
|
|
32187
|
+
return aliases.map(({ alias, input }) => ({
|
|
32188
|
+
alias,
|
|
32189
|
+
bodyPath: input.bodyPath,
|
|
32190
|
+
issues: checkOneWorkflowBody(tsApi, input)
|
|
32191
|
+
}));
|
|
32192
|
+
}
|
|
32193
|
+
|
|
32122
32194
|
// src/app_commands.ts
|
|
32123
32195
|
async function fetchLatestNpmVersion(packageName) {
|
|
32124
32196
|
try {
|
|
@@ -32136,15 +32208,17 @@ async function fetchLatestNpmVersion(packageName) {
|
|
|
32136
32208
|
return null;
|
|
32137
32209
|
}
|
|
32138
32210
|
}
|
|
32139
|
-
var WORKFLOWS_DIR =
|
|
32140
|
-
var WORKFLOW_GLOBALS_DIR =
|
|
32211
|
+
var WORKFLOWS_DIR = path5.join("src", "workflows");
|
|
32212
|
+
var WORKFLOW_GLOBALS_DIR = path5.join(".lotics", "workflows");
|
|
32213
|
+
var WORKFLOW_TSCONFIG_EXCLUDES = ["src/workflows", ".lotics/workflows"];
|
|
32141
32214
|
var FALLBACK_ENVELOPE_PREFIX = "async function __workflow(): Promise<__WorkflowReturn | void> {\n";
|
|
32142
32215
|
var FALLBACK_ENVELOPE_SUFFIX = "\n}";
|
|
32143
32216
|
function workflowFileHeader(alias) {
|
|
32144
|
-
const refPath =
|
|
32217
|
+
const refPath = path5.join("..", "..", WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`).split(path5.sep).join("/");
|
|
32145
32218
|
return `/// <reference path="${refPath}" />
|
|
32146
32219
|
// Auto-pulled workflow body for "${alias}". Edit the BODY between the wrapper
|
|
32147
|
-
// lines below, then push with:
|
|
32220
|
+
// lines below, then check + push with:
|
|
32221
|
+
// lotics app workflow check ${alias}
|
|
32148
32222
|
// lotics app workflow set ${alias}
|
|
32149
32223
|
// The push goes through set_app_workflow, where the SERVER verifies the body.
|
|
32150
32224
|
// The __workflow wrapper + the reference above are CLI bookkeeping (stripped on
|
|
@@ -32154,25 +32228,25 @@ export {};
|
|
|
32154
32228
|
`;
|
|
32155
32229
|
}
|
|
32156
32230
|
function workflowFilePath(projectDir, alias) {
|
|
32157
|
-
return
|
|
32231
|
+
return path5.join(projectDir, WORKFLOWS_DIR, `${alias}.ts`);
|
|
32158
32232
|
}
|
|
32159
32233
|
function workflowGlobalsPath(projectDir, alias) {
|
|
32160
|
-
return
|
|
32234
|
+
return path5.join(projectDir, WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`);
|
|
32161
32235
|
}
|
|
32162
32236
|
function writeWorkflowGlobals(projectDir, alias, dts) {
|
|
32163
|
-
const dir =
|
|
32164
|
-
|
|
32237
|
+
const dir = path5.join(projectDir, WORKFLOW_GLOBALS_DIR);
|
|
32238
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
32165
32239
|
const file = workflowGlobalsPath(projectDir, alias);
|
|
32166
|
-
|
|
32240
|
+
fs4.writeFileSync(file, `${dts.replace(/\s+$/, "")}
|
|
32167
32241
|
`);
|
|
32168
32242
|
return file;
|
|
32169
32243
|
}
|
|
32170
32244
|
function writeWorkflowFile(projectDir, alias, source, envelope = { prefix: FALLBACK_ENVELOPE_PREFIX, suffix: FALLBACK_ENVELOPE_SUFFIX }) {
|
|
32171
|
-
const dir =
|
|
32172
|
-
|
|
32245
|
+
const dir = path5.join(projectDir, WORKFLOWS_DIR);
|
|
32246
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
32173
32247
|
const file = workflowFilePath(projectDir, alias);
|
|
32174
32248
|
const body = source.replace(/\s+$/, "");
|
|
32175
|
-
|
|
32249
|
+
fs4.writeFileSync(file, `${workflowFileHeader(alias)}
|
|
32176
32250
|
${envelope.prefix}${body}${envelope.suffix}
|
|
32177
32251
|
`);
|
|
32178
32252
|
return file;
|
|
@@ -32253,11 +32327,11 @@ function runNpm(args, cwd) {
|
|
|
32253
32327
|
});
|
|
32254
32328
|
}
|
|
32255
32329
|
function readAppMeta(projectDir) {
|
|
32256
|
-
const pkgPath2 =
|
|
32257
|
-
if (!
|
|
32330
|
+
const pkgPath2 = path5.join(projectDir, "package.json");
|
|
32331
|
+
if (!fs4.existsSync(pkgPath2)) {
|
|
32258
32332
|
throw new Error(`No package.json found at ${projectDir}. Run 'lotics app create' first.`);
|
|
32259
32333
|
}
|
|
32260
|
-
const pkg2 = JSON.parse(
|
|
32334
|
+
const pkg2 = JSON.parse(fs4.readFileSync(pkgPath2, "utf-8"));
|
|
32261
32335
|
if (!pkg2.lotics?.app_id || !pkg2.lotics.workspace_id) {
|
|
32262
32336
|
throw new Error(
|
|
32263
32337
|
`package.json is missing the 'lotics' field with app_id and workspace_id. Was this folder created with 'lotics app create'?`
|
|
@@ -32275,24 +32349,52 @@ function readAppMeta(projectDir) {
|
|
|
32275
32349
|
};
|
|
32276
32350
|
}
|
|
32277
32351
|
function writeAppMeta(projectDir, meta) {
|
|
32278
|
-
const pkgPath2 =
|
|
32279
|
-
const pkg2 = JSON.parse(
|
|
32352
|
+
const pkgPath2 = path5.join(projectDir, "package.json");
|
|
32353
|
+
const pkg2 = JSON.parse(fs4.readFileSync(pkgPath2, "utf-8"));
|
|
32280
32354
|
pkg2.lotics = meta;
|
|
32281
|
-
|
|
32355
|
+
fs4.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
32356
|
+
}
|
|
32357
|
+
function ensureWorkflowTsconfigExcludes(projectDir) {
|
|
32358
|
+
const tsconfigPath = path5.join(projectDir, "tsconfig.json");
|
|
32359
|
+
if (!fs4.existsSync(tsconfigPath)) {
|
|
32360
|
+
console.error(
|
|
32361
|
+
`\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.`
|
|
32362
|
+
);
|
|
32363
|
+
return;
|
|
32364
|
+
}
|
|
32365
|
+
let parsed;
|
|
32366
|
+
try {
|
|
32367
|
+
parsed = JSON.parse(fs4.readFileSync(tsconfigPath, "utf-8"));
|
|
32368
|
+
} catch (err2) {
|
|
32369
|
+
console.error(
|
|
32370
|
+
`\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.`
|
|
32371
|
+
);
|
|
32372
|
+
return;
|
|
32373
|
+
}
|
|
32374
|
+
if (!parsed || typeof parsed !== "object") return;
|
|
32375
|
+
const current = Array.isArray(parsed.exclude) ? parsed.exclude : [];
|
|
32376
|
+
const currentStrings = current.filter((e) => typeof e === "string");
|
|
32377
|
+
const toAdd = WORKFLOW_TSCONFIG_EXCLUDES.filter((g) => !currentStrings.includes(g));
|
|
32378
|
+
if (toAdd.length === 0) return;
|
|
32379
|
+
parsed.exclude = [...currentStrings, ...toAdd];
|
|
32380
|
+
fs4.writeFileSync(tsconfigPath, JSON.stringify(parsed, null, 2) + "\n");
|
|
32381
|
+
console.error(
|
|
32382
|
+
`Patched tsconfig.json: added ${toAdd.join(", ")} to "exclude" so npm run typecheck skips the workflow bodies (check them with: lotics app workflow check).`
|
|
32383
|
+
);
|
|
32282
32384
|
}
|
|
32283
32385
|
function writeAppDts(projectDir, manifest) {
|
|
32284
|
-
const dotLotics =
|
|
32285
|
-
|
|
32386
|
+
const dotLotics = path5.join(projectDir, ".lotics");
|
|
32387
|
+
fs4.mkdirSync(dotLotics, { recursive: true });
|
|
32286
32388
|
const written = [
|
|
32287
|
-
[
|
|
32288
|
-
[
|
|
32289
|
-
[
|
|
32389
|
+
[path5.join(dotLotics, "app_workflows.d.ts"), generateAppWorkflowsDts(manifest.workflows)],
|
|
32390
|
+
[path5.join(dotLotics, "app_queries.d.ts"), generateAppQueriesDts(manifest.queries)],
|
|
32391
|
+
[path5.join(dotLotics, "app_agents.d.ts"), generateAppAgentsDts(manifest.agents)]
|
|
32290
32392
|
];
|
|
32291
|
-
for (const [file, content] of written)
|
|
32393
|
+
for (const [file, content] of written) fs4.writeFileSync(file, content);
|
|
32292
32394
|
return written.map(([file]) => file);
|
|
32293
32395
|
}
|
|
32294
32396
|
function readCodegenTablesAllowlist(projectDir) {
|
|
32295
|
-
const pkg2 = JSON.parse(
|
|
32397
|
+
const pkg2 = JSON.parse(fs4.readFileSync(path5.join(projectDir, "package.json"), "utf-8"));
|
|
32296
32398
|
const tables = pkg2.lotics?.codegen?.tables;
|
|
32297
32399
|
return Array.isArray(tables) ? tables.filter((t) => typeof t === "string") : [];
|
|
32298
32400
|
}
|
|
@@ -32305,14 +32407,14 @@ function resolveCodegenTableIds(projectDir, queries) {
|
|
|
32305
32407
|
return [...ids];
|
|
32306
32408
|
}
|
|
32307
32409
|
function writeAppFields(projectDir, tables) {
|
|
32308
|
-
const dotLotics =
|
|
32309
|
-
|
|
32310
|
-
const file =
|
|
32311
|
-
|
|
32410
|
+
const dotLotics = path5.join(projectDir, ".lotics");
|
|
32411
|
+
fs4.mkdirSync(dotLotics, { recursive: true });
|
|
32412
|
+
const file = path5.join(dotLotics, "app_fields.ts");
|
|
32413
|
+
fs4.writeFileSync(file, generateAppFields(tables));
|
|
32312
32414
|
return file;
|
|
32313
32415
|
}
|
|
32314
32416
|
async function appCodegen(args) {
|
|
32315
|
-
const projectDir =
|
|
32417
|
+
const projectDir = path5.resolve(args.projectDir ?? process.cwd());
|
|
32316
32418
|
const meta = readAppMeta(projectDir);
|
|
32317
32419
|
const dtsPaths = writeAppDts(projectDir, {
|
|
32318
32420
|
workflows: meta.workflows,
|
|
@@ -32337,16 +32439,17 @@ async function appCodegen(args) {
|
|
|
32337
32439
|
);
|
|
32338
32440
|
}
|
|
32339
32441
|
await refreshWorkflowGlobals(args.client, projectDir, meta.app_id, Object.keys(meta.workflows ?? {}));
|
|
32442
|
+
if (Object.keys(meta.workflows ?? {}).length > 0) ensureWorkflowTsconfigExcludes(projectDir);
|
|
32340
32443
|
}
|
|
32341
32444
|
async function refreshWorkflowGlobals(client, projectDir, app_id, aliases) {
|
|
32342
32445
|
for (const alias of aliases) {
|
|
32343
32446
|
const file = workflowFilePath(projectDir, alias);
|
|
32344
|
-
if (!
|
|
32345
|
-
const body = stripWorkflowHeader(
|
|
32447
|
+
if (!fs4.existsSync(file)) continue;
|
|
32448
|
+
const body = stripWorkflowHeader(fs4.readFileSync(file, "utf-8"));
|
|
32346
32449
|
if (body.trim() === "") continue;
|
|
32347
32450
|
const envelope = await fetchWorkflowGlobals(client, projectDir, app_id, alias);
|
|
32348
32451
|
writeWorkflowFile(projectDir, alias, body, envelope);
|
|
32349
|
-
console.error(`Refreshed ${
|
|
32452
|
+
console.error(`Refreshed ${path5.relative(projectDir, file)} + its workflow types`);
|
|
32350
32453
|
}
|
|
32351
32454
|
}
|
|
32352
32455
|
function stampPulledManifest(projectDir, args) {
|
|
@@ -32367,21 +32470,21 @@ async function downloadToFile(url, destPath) {
|
|
|
32367
32470
|
throw new Error(`Failed to download ${url}: ${response.status}`);
|
|
32368
32471
|
}
|
|
32369
32472
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
32370
|
-
|
|
32473
|
+
fs4.writeFileSync(destPath, buffer);
|
|
32371
32474
|
}
|
|
32372
32475
|
function appDirName(name) {
|
|
32373
32476
|
const cleaned = name.replace(/[/\\]+/g, "-").replace(/[<>:"|?*]/g, "").replace(/\s+/g, " ").trim().replace(/^[.\s-]+|[.\s-]+$/g, "");
|
|
32374
32477
|
return cleaned || "app";
|
|
32375
32478
|
}
|
|
32376
32479
|
async function appCreate(client, args) {
|
|
32377
|
-
const targetPath =
|
|
32378
|
-
if (
|
|
32379
|
-
const entries =
|
|
32480
|
+
const targetPath = path5.resolve(args.targetPath ?? appDirName(args.name));
|
|
32481
|
+
if (fs4.existsSync(targetPath)) {
|
|
32482
|
+
const entries = fs4.readdirSync(targetPath);
|
|
32380
32483
|
if (entries.length > 0) {
|
|
32381
32484
|
throw new Error(`Target directory ${targetPath} is not empty.`);
|
|
32382
32485
|
}
|
|
32383
32486
|
}
|
|
32384
|
-
|
|
32487
|
+
fs4.mkdirSync(targetPath, { recursive: true });
|
|
32385
32488
|
const app = await client.createApp({ name: args.name });
|
|
32386
32489
|
console.error(`Created app: ${app.name} (${app.id})`);
|
|
32387
32490
|
const [uiLatest, sdkLatest] = await Promise.all([
|
|
@@ -32396,9 +32499,9 @@ async function appCreate(client, args) {
|
|
|
32396
32499
|
sdk_version: sdkLatest ? `^${sdkLatest}` : void 0
|
|
32397
32500
|
});
|
|
32398
32501
|
for (const file of files) {
|
|
32399
|
-
const fullPath =
|
|
32400
|
-
|
|
32401
|
-
|
|
32502
|
+
const fullPath = path5.join(targetPath, file.path);
|
|
32503
|
+
fs4.mkdirSync(path5.dirname(fullPath), { recursive: true });
|
|
32504
|
+
fs4.writeFileSync(fullPath, file.content);
|
|
32402
32505
|
}
|
|
32403
32506
|
console.error(`Scaffolded ${files.length} files into ${targetPath}`);
|
|
32404
32507
|
writeAppDts(targetPath, {});
|
|
@@ -32411,7 +32514,7 @@ async function appCreate(client, args) {
|
|
|
32411
32514
|
});
|
|
32412
32515
|
console.error(`
|
|
32413
32516
|
Ready. Next steps:`);
|
|
32414
|
-
console.error(` cd ${
|
|
32517
|
+
console.error(` cd ${path5.relative(process.cwd(), targetPath) || "."}`);
|
|
32415
32518
|
console.error(` # edit src/App.tsx, then:`);
|
|
32416
32519
|
console.error(` lotics app deploy`);
|
|
32417
32520
|
}
|
|
@@ -32426,6 +32529,21 @@ async function appRename(client, args) {
|
|
|
32426
32529
|
if (res.error) throw new Error(res.error);
|
|
32427
32530
|
console.error(`App renamed: "${args.name}" (${meta.app_id})`);
|
|
32428
32531
|
}
|
|
32532
|
+
function defaultPullTarget(appId, appName) {
|
|
32533
|
+
const cwdPkgPath = path5.join(process.cwd(), "package.json");
|
|
32534
|
+
if (fs4.existsSync(cwdPkgPath)) {
|
|
32535
|
+
let pkg2 = null;
|
|
32536
|
+
try {
|
|
32537
|
+
pkg2 = JSON.parse(fs4.readFileSync(cwdPkgPath, "utf-8"));
|
|
32538
|
+
} catch (err2) {
|
|
32539
|
+
console.error(
|
|
32540
|
+
`\u26A0 Could not parse ${cwdPkgPath} (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 pulling into a fresh ${appDirName(appName)}/ subdir.`
|
|
32541
|
+
);
|
|
32542
|
+
}
|
|
32543
|
+
if (pkg2?.lotics?.app_id === appId) return process.cwd();
|
|
32544
|
+
}
|
|
32545
|
+
return appDirName(appName);
|
|
32546
|
+
}
|
|
32429
32547
|
async function appPull(client, args) {
|
|
32430
32548
|
const app = await client.getApp(args.app_id);
|
|
32431
32549
|
if (!app.current_version_id) {
|
|
@@ -32435,16 +32553,16 @@ async function appPull(client, args) {
|
|
|
32435
32553
|
}
|
|
32436
32554
|
const version = await client.getAppVersion(app.id, app.current_version_id);
|
|
32437
32555
|
const sourceUrl = await client.getAppVersionSourceUrl(app.id, version.id);
|
|
32438
|
-
const targetPath =
|
|
32439
|
-
|
|
32440
|
-
const tmpFile =
|
|
32556
|
+
const targetPath = path5.resolve(args.targetPath ?? defaultPullTarget(app.id, app.name));
|
|
32557
|
+
fs4.mkdirSync(targetPath, { recursive: true });
|
|
32558
|
+
const tmpFile = path5.join(tmpdir(), `lotics-app-${app.id}-${Date.now()}.tar.gz`);
|
|
32441
32559
|
console.error(`Downloading source archive...`);
|
|
32442
32560
|
await downloadToFile(sourceUrl, tmpFile);
|
|
32443
32561
|
try {
|
|
32444
32562
|
console.error(`Extracting to ${targetPath}...`);
|
|
32445
32563
|
await runTar(["-xzf", tmpFile, "-C", targetPath], targetPath);
|
|
32446
32564
|
} finally {
|
|
32447
|
-
if (
|
|
32565
|
+
if (fs4.existsSync(tmpFile)) fs4.unlinkSync(tmpFile);
|
|
32448
32566
|
}
|
|
32449
32567
|
stampPulledManifest(targetPath, {
|
|
32450
32568
|
app_id: app.id,
|
|
@@ -32463,12 +32581,13 @@ async function appPull(client, args) {
|
|
|
32463
32581
|
`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/ (${written.join(", ")})`
|
|
32464
32582
|
);
|
|
32465
32583
|
}
|
|
32584
|
+
ensureWorkflowTsconfigExcludes(targetPath);
|
|
32466
32585
|
}
|
|
32467
32586
|
console.error(`Installing npm dependencies...`);
|
|
32468
32587
|
await runNpm(["install"], targetPath);
|
|
32469
32588
|
console.error(`
|
|
32470
32589
|
Ready. Next steps:`);
|
|
32471
|
-
console.error(` cd ${
|
|
32590
|
+
console.error(` cd ${path5.relative(process.cwd(), targetPath) || "."}`);
|
|
32472
32591
|
console.error(` # edit src/App.tsx`);
|
|
32473
32592
|
console.error(` lotics app deploy`);
|
|
32474
32593
|
}
|
|
@@ -32484,21 +32603,21 @@ function undeclaredCapabilities(sourceText, declared) {
|
|
|
32484
32603
|
return used;
|
|
32485
32604
|
}
|
|
32486
32605
|
function readAppSourceText(projectDir) {
|
|
32487
|
-
const srcDir =
|
|
32488
|
-
if (!
|
|
32606
|
+
const srcDir = path5.join(projectDir, "src");
|
|
32607
|
+
if (!fs4.existsSync(srcDir)) return "";
|
|
32489
32608
|
const parts = [];
|
|
32490
32609
|
const walk2 = (dir) => {
|
|
32491
|
-
for (const entry of
|
|
32492
|
-
const full =
|
|
32610
|
+
for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
|
|
32611
|
+
const full = path5.join(dir, entry.name);
|
|
32493
32612
|
if (entry.isDirectory()) walk2(full);
|
|
32494
|
-
else if (/\.(ts|tsx|js|jsx)$/.test(entry.name)) parts.push(
|
|
32613
|
+
else if (/\.(ts|tsx|js|jsx)$/.test(entry.name)) parts.push(fs4.readFileSync(full, "utf8"));
|
|
32495
32614
|
}
|
|
32496
32615
|
};
|
|
32497
32616
|
walk2(srcDir);
|
|
32498
32617
|
return parts.join("\n");
|
|
32499
32618
|
}
|
|
32500
32619
|
async function appDeploy(client, args) {
|
|
32501
|
-
const projectDir =
|
|
32620
|
+
const projectDir = path5.resolve(args.projectDir ?? process.cwd());
|
|
32502
32621
|
const meta = readAppMeta(projectDir);
|
|
32503
32622
|
const undeclared = undeclaredCapabilities(readAppSourceText(projectDir), meta.capabilities);
|
|
32504
32623
|
if (undeclared.length > 0) {
|
|
@@ -32512,14 +32631,14 @@ async function appDeploy(client, args) {
|
|
|
32512
32631
|
writeAppDts(projectDir, { workflows: meta.workflows, queries: meta.queries, agents: meta.agents });
|
|
32513
32632
|
console.error("Building...");
|
|
32514
32633
|
await runNpm(["run", "build"], projectDir);
|
|
32515
|
-
const distDir =
|
|
32516
|
-
if (!
|
|
32634
|
+
const distDir = path5.join(projectDir, "dist");
|
|
32635
|
+
if (!fs4.existsSync(distDir)) {
|
|
32517
32636
|
throw new Error(
|
|
32518
32637
|
`Build did not produce a dist/ directory in ${projectDir}. Check that 'npm run build' is configured correctly (Vite/etc. defaults to dist/).`
|
|
32519
32638
|
);
|
|
32520
32639
|
}
|
|
32521
|
-
const tmpSource =
|
|
32522
|
-
const tmpDist =
|
|
32640
|
+
const tmpSource = path5.join(tmpdir(), `lotics-source-${Date.now()}.tar.gz`);
|
|
32641
|
+
const tmpDist = path5.join(tmpdir(), `lotics-dist-${Date.now()}.tar.gz`);
|
|
32523
32642
|
try {
|
|
32524
32643
|
console.error("Packaging source...");
|
|
32525
32644
|
await runTar(
|
|
@@ -32541,8 +32660,8 @@ async function appDeploy(client, args) {
|
|
|
32541
32660
|
try {
|
|
32542
32661
|
const result = await client.deployAppVersion({
|
|
32543
32662
|
app_id: meta.app_id,
|
|
32544
|
-
source_archive:
|
|
32545
|
-
dist_archive:
|
|
32663
|
+
source_archive: fs4.readFileSync(tmpSource),
|
|
32664
|
+
dist_archive: fs4.readFileSync(tmpDist),
|
|
32546
32665
|
prev_version_id: meta.current_version_id,
|
|
32547
32666
|
message: args.message,
|
|
32548
32667
|
// Sync apps.queries from the manifest. Server validates each query
|
|
@@ -32576,8 +32695,8 @@ async function appDeploy(client, args) {
|
|
|
32576
32695
|
throw err2;
|
|
32577
32696
|
}
|
|
32578
32697
|
} finally {
|
|
32579
|
-
if (
|
|
32580
|
-
if (
|
|
32698
|
+
if (fs4.existsSync(tmpSource)) fs4.unlinkSync(tmpSource);
|
|
32699
|
+
if (fs4.existsSync(tmpDist)) fs4.unlinkSync(tmpDist);
|
|
32581
32700
|
}
|
|
32582
32701
|
}
|
|
32583
32702
|
async function warnIfUnbranded(client, appId) {
|
|
@@ -32598,7 +32717,7 @@ async function warnIfUnbranded(client, appId) {
|
|
|
32598
32717
|
}
|
|
32599
32718
|
}
|
|
32600
32719
|
async function appDev(client, args) {
|
|
32601
|
-
const projectDir =
|
|
32720
|
+
const projectDir = path5.resolve(args.projectDir ?? process.cwd());
|
|
32602
32721
|
const meta = readAppMeta(projectDir);
|
|
32603
32722
|
writeAppDts(projectDir, { workflows: meta.workflows, queries: meta.queries, agents: meta.agents });
|
|
32604
32723
|
const app = await client.getApp(meta.app_id);
|
|
@@ -32737,15 +32856,15 @@ async function appWorkflowSet(client, args) {
|
|
|
32737
32856
|
process.exit(1);
|
|
32738
32857
|
}
|
|
32739
32858
|
const file = workflowFilePath(projectDir, args.alias);
|
|
32740
|
-
if (!
|
|
32859
|
+
if (!fs4.existsSync(file)) {
|
|
32741
32860
|
console.error(
|
|
32742
|
-
`No workflow body at ${
|
|
32861
|
+
`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
32862
|
);
|
|
32744
32863
|
process.exit(1);
|
|
32745
32864
|
}
|
|
32746
|
-
const source = stripWorkflowHeader(
|
|
32865
|
+
const source = stripWorkflowHeader(fs4.readFileSync(file, "utf-8"));
|
|
32747
32866
|
if (source.trim() === "") {
|
|
32748
|
-
console.error(`Workflow body ${
|
|
32867
|
+
console.error(`Workflow body ${path5.relative(projectDir, file)} is empty after stripping the header.`);
|
|
32749
32868
|
process.exit(1);
|
|
32750
32869
|
}
|
|
32751
32870
|
const res = await client.setAppWorkflow(meta.app_id, args.alias, {
|
|
@@ -32777,22 +32896,97 @@ async function appWorkflowPull(client) {
|
|
|
32777
32896
|
console.error(
|
|
32778
32897
|
`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/` + (written.length > 0 ? ` (${written.join(", ")})` : "")
|
|
32779
32898
|
);
|
|
32899
|
+
ensureWorkflowTsconfigExcludes(projectDir);
|
|
32900
|
+
}
|
|
32901
|
+
async function appWorkflowCheck(args) {
|
|
32902
|
+
const projectDir = process.cwd();
|
|
32903
|
+
const meta = readAppMeta(projectDir);
|
|
32904
|
+
const bound = Object.keys(meta.workflows ?? {});
|
|
32905
|
+
let aliases;
|
|
32906
|
+
if (args.alias) {
|
|
32907
|
+
if (!bound.includes(args.alias)) {
|
|
32908
|
+
console.error(
|
|
32909
|
+
`No workflow "${args.alias}" in package.json#lotics.workflows. Bound aliases: ${bound.length > 0 ? bound.join(", ") : "(none)"}.`
|
|
32910
|
+
);
|
|
32911
|
+
process.exit(1);
|
|
32912
|
+
}
|
|
32913
|
+
aliases = [args.alias];
|
|
32914
|
+
} else {
|
|
32915
|
+
aliases = bound;
|
|
32916
|
+
}
|
|
32917
|
+
if (aliases.length === 0) {
|
|
32918
|
+
console.error(`App ${meta.app_id} has no bound workflows to check.`);
|
|
32919
|
+
return;
|
|
32920
|
+
}
|
|
32921
|
+
const toCheck = [];
|
|
32922
|
+
for (const alias of aliases) {
|
|
32923
|
+
const bodyPath = workflowFilePath(projectDir, alias);
|
|
32924
|
+
const globalsPath = workflowGlobalsPath(projectDir, alias);
|
|
32925
|
+
if (!fs4.existsSync(bodyPath)) {
|
|
32926
|
+
console.error(
|
|
32927
|
+
`\u26A0 Skipped "${alias}" \u2014 no body at ${path5.relative(projectDir, bodyPath)}. Run 'lotics app workflow pull' to write it.`
|
|
32928
|
+
);
|
|
32929
|
+
continue;
|
|
32930
|
+
}
|
|
32931
|
+
if (!fs4.existsSync(globalsPath)) {
|
|
32932
|
+
console.error(
|
|
32933
|
+
`Cannot check "${alias}" \u2014 missing types at ${path5.relative(projectDir, globalsPath)}. Run 'lotics app workflow pull' (or 'lotics app codegen') to fetch them.`
|
|
32934
|
+
);
|
|
32935
|
+
process.exit(1);
|
|
32936
|
+
}
|
|
32937
|
+
toCheck.push({ alias, input: { bodyPath, globalsPath } });
|
|
32938
|
+
}
|
|
32939
|
+
if (toCheck.length === 0) {
|
|
32940
|
+
console.error("No workflow bodies to check (every bound alias was skipped).");
|
|
32941
|
+
return;
|
|
32942
|
+
}
|
|
32943
|
+
const tsApi = await loadProjectTypescript(projectDir);
|
|
32944
|
+
const results = checkWorkflowBodies(tsApi, toCheck);
|
|
32945
|
+
printWorkflowCheckResults(projectDir, results);
|
|
32946
|
+
const failed = results.filter((r) => r.issues.length > 0);
|
|
32947
|
+
if (failed.length > 0) process.exit(1);
|
|
32948
|
+
}
|
|
32949
|
+
function printWorkflowCheckResults(projectDir, results) {
|
|
32950
|
+
let totalErrors = 0;
|
|
32951
|
+
for (const r of results) {
|
|
32952
|
+
const rel = path5.relative(projectDir, r.bodyPath);
|
|
32953
|
+
if (r.issues.length === 0) {
|
|
32954
|
+
console.error(`\u2713 ${r.alias} (${rel}) \u2014 no type errors`);
|
|
32955
|
+
continue;
|
|
32956
|
+
}
|
|
32957
|
+
totalErrors += r.issues.length;
|
|
32958
|
+
console.error(
|
|
32959
|
+
`\u2717 ${r.alias} (${rel}) \u2014 ${r.issues.length} error${r.issues.length === 1 ? "" : "s"}:`
|
|
32960
|
+
);
|
|
32961
|
+
for (const issue of r.issues) {
|
|
32962
|
+
const [first2, ...rest] = issue.message.split("\n");
|
|
32963
|
+
console.error(` ${rel}:${issue.line}:${issue.col} - ${issue.code}: ${first2}`);
|
|
32964
|
+
for (const line of rest) console.error(` ${line}`);
|
|
32965
|
+
}
|
|
32966
|
+
}
|
|
32967
|
+
const passed = results.length - results.filter((r) => r.issues.length > 0).length;
|
|
32968
|
+
console.error(
|
|
32969
|
+
totalErrors === 0 ? results.length === 1 ? `
|
|
32970
|
+
The workflow body type-checks clean.` : `
|
|
32971
|
+
All ${results.length} workflow bodies type-check clean.` : `
|
|
32972
|
+
${totalErrors} error${totalErrors === 1 ? "" : "s"} across ${results.length - passed} of ${results.length} ${results.length === 1 ? "body" : "bodies"}.`
|
|
32973
|
+
);
|
|
32780
32974
|
}
|
|
32781
32975
|
function findUiSrcDir(start) {
|
|
32782
|
-
let dir =
|
|
32976
|
+
let dir = path5.resolve(start);
|
|
32783
32977
|
for (; ; ) {
|
|
32784
|
-
const candidate =
|
|
32785
|
-
if (
|
|
32786
|
-
const parent =
|
|
32978
|
+
const candidate = path5.join(dir, "packages", "ui", "src");
|
|
32979
|
+
if (fs4.existsSync(candidate) && fs4.statSync(candidate).isDirectory()) return candidate;
|
|
32980
|
+
const parent = path5.dirname(dir);
|
|
32787
32981
|
if (parent === dir) return null;
|
|
32788
32982
|
dir = parent;
|
|
32789
32983
|
}
|
|
32790
32984
|
}
|
|
32791
32985
|
var UI_ALIAS_FIND_SOURCE = String.raw`/^@lotics\/ui\/(.+)$/`;
|
|
32792
32986
|
function appUiLink(args) {
|
|
32793
|
-
const projectDir =
|
|
32794
|
-
const viteConfigPath =
|
|
32795
|
-
if (!
|
|
32987
|
+
const projectDir = path5.resolve(args.projectDir ?? process.cwd());
|
|
32988
|
+
const viteConfigPath = path5.join(projectDir, "vite.config.ts");
|
|
32989
|
+
if (!fs4.existsSync(viteConfigPath)) {
|
|
32796
32990
|
throw new Error(
|
|
32797
32991
|
`No vite.config.ts at ${projectDir}. Run inside a 'lotics app' project directory.`
|
|
32798
32992
|
);
|
|
@@ -32803,13 +32997,13 @@ function appUiLink(args) {
|
|
|
32803
32997
|
"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
32998
|
);
|
|
32805
32999
|
}
|
|
32806
|
-
const hasComponent =
|
|
33000
|
+
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
33001
|
if (!hasComponent) {
|
|
32808
33002
|
throw new Error(
|
|
32809
33003
|
`No '@lotics/ui/${args.component}' under ${uiSrc} (expected ${args.component}.tsx/.ts). Check the component name.`
|
|
32810
33004
|
);
|
|
32811
33005
|
}
|
|
32812
|
-
const source =
|
|
33006
|
+
const source = fs4.readFileSync(viteConfigPath, "utf-8");
|
|
32813
33007
|
const aliasEntry = `{ find: ${UI_ALIAS_FIND_SOURCE}, replacement: ${JSON.stringify(`${uiSrc}/$1`)} },`;
|
|
32814
33008
|
const alreadyLinked = source.includes(UI_ALIAS_FIND_SOURCE);
|
|
32815
33009
|
if (args.remove) {
|
|
@@ -32818,7 +33012,7 @@ function appUiLink(args) {
|
|
|
32818
33012
|
return;
|
|
32819
33013
|
}
|
|
32820
33014
|
const stripped = source.replace(new RegExp(`^\\s*\\{ find: ${escapeRegExp(UI_ALIAS_FIND_SOURCE)}.*$\\n?`, "m"), "");
|
|
32821
|
-
|
|
33015
|
+
fs4.writeFileSync(viteConfigPath, stripped);
|
|
32822
33016
|
console.error(`Removed the @lotics/ui dev-link alias from ${viteConfigPath}.`);
|
|
32823
33017
|
console.error("Restart `lotics app dev` and rm -rf node_modules/.vite to clear cached modules.");
|
|
32824
33018
|
return;
|
|
@@ -32836,7 +33030,7 @@ function appUiLink(args) {
|
|
|
32836
33030
|
const insertAt = aliasMatch.index + aliasMatch[0].length;
|
|
32837
33031
|
const updated = `${source.slice(0, insertAt)}
|
|
32838
33032
|
${aliasEntry}${source.slice(insertAt)}`;
|
|
32839
|
-
|
|
33033
|
+
fs4.writeFileSync(viteConfigPath, updated);
|
|
32840
33034
|
console.error(`Dev-linked @lotics/ui \u2192 ${uiSrc} in ${viteConfigPath}.`);
|
|
32841
33035
|
console.error("Restart `lotics app dev` and rm -rf node_modules/.vite to clear cached modules.");
|
|
32842
33036
|
console.error("Finalize: PR the packages/ui change \u2192 publish \u2192 `lotics ui link <component> --remove` + bump the app's dep.");
|
|
@@ -32973,11 +33167,11 @@ async function ingestJsonArgs(opts) {
|
|
|
32973
33167
|
}
|
|
32974
33168
|
|
|
32975
33169
|
// src/xlsx.ts
|
|
32976
|
-
import
|
|
33170
|
+
import fs6 from "node:fs";
|
|
32977
33171
|
|
|
32978
33172
|
// src/file_command_io.ts
|
|
32979
|
-
import
|
|
32980
|
-
import
|
|
33173
|
+
import fs5 from "node:fs";
|
|
33174
|
+
import path6 from "node:path";
|
|
32981
33175
|
var CliError = class extends Error {
|
|
32982
33176
|
constructor(message) {
|
|
32983
33177
|
super(message);
|
|
@@ -32988,14 +33182,14 @@ function fail(message) {
|
|
|
32988
33182
|
throw new CliError(message);
|
|
32989
33183
|
}
|
|
32990
33184
|
function writeFileAtomic(filePath, bytes) {
|
|
32991
|
-
const dir =
|
|
32992
|
-
const tmp =
|
|
32993
|
-
|
|
33185
|
+
const dir = path6.dirname(path6.resolve(filePath));
|
|
33186
|
+
const tmp = path6.join(dir, `.${path6.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
|
|
33187
|
+
fs5.writeFileSync(tmp, bytes);
|
|
32994
33188
|
try {
|
|
32995
|
-
|
|
33189
|
+
fs5.renameSync(tmp, filePath);
|
|
32996
33190
|
} catch (error) {
|
|
32997
33191
|
try {
|
|
32998
|
-
|
|
33192
|
+
fs5.unlinkSync(tmp);
|
|
32999
33193
|
} catch {
|
|
33000
33194
|
}
|
|
33001
33195
|
throw error;
|
|
@@ -35778,16 +35972,16 @@ var MatcherView = class {
|
|
|
35778
35972
|
* @returns {string|undefined}
|
|
35779
35973
|
*/
|
|
35780
35974
|
getCurrentTag() {
|
|
35781
|
-
const
|
|
35782
|
-
return
|
|
35975
|
+
const path8 = this._matcher.path;
|
|
35976
|
+
return path8.length > 0 ? path8[path8.length - 1].tag : void 0;
|
|
35783
35977
|
}
|
|
35784
35978
|
/**
|
|
35785
35979
|
* Get current namespace.
|
|
35786
35980
|
* @returns {string|undefined}
|
|
35787
35981
|
*/
|
|
35788
35982
|
getCurrentNamespace() {
|
|
35789
|
-
const
|
|
35790
|
-
return
|
|
35983
|
+
const path8 = this._matcher.path;
|
|
35984
|
+
return path8.length > 0 ? path8[path8.length - 1].namespace : void 0;
|
|
35791
35985
|
}
|
|
35792
35986
|
/**
|
|
35793
35987
|
* Get current node's attribute value.
|
|
@@ -35795,9 +35989,9 @@ var MatcherView = class {
|
|
|
35795
35989
|
* @returns {*}
|
|
35796
35990
|
*/
|
|
35797
35991
|
getAttrValue(attrName) {
|
|
35798
|
-
const
|
|
35799
|
-
if (
|
|
35800
|
-
return
|
|
35992
|
+
const path8 = this._matcher.path;
|
|
35993
|
+
if (path8.length === 0) return void 0;
|
|
35994
|
+
return path8[path8.length - 1].values?.[attrName];
|
|
35801
35995
|
}
|
|
35802
35996
|
/**
|
|
35803
35997
|
* Check if current node has an attribute.
|
|
@@ -35805,9 +35999,9 @@ var MatcherView = class {
|
|
|
35805
35999
|
* @returns {boolean}
|
|
35806
36000
|
*/
|
|
35807
36001
|
hasAttr(attrName) {
|
|
35808
|
-
const
|
|
35809
|
-
if (
|
|
35810
|
-
const current =
|
|
36002
|
+
const path8 = this._matcher.path;
|
|
36003
|
+
if (path8.length === 0) return false;
|
|
36004
|
+
const current = path8[path8.length - 1];
|
|
35811
36005
|
return current.values !== void 0 && attrName in current.values;
|
|
35812
36006
|
}
|
|
35813
36007
|
/**
|
|
@@ -35815,18 +36009,18 @@ var MatcherView = class {
|
|
|
35815
36009
|
* @returns {number}
|
|
35816
36010
|
*/
|
|
35817
36011
|
getPosition() {
|
|
35818
|
-
const
|
|
35819
|
-
if (
|
|
35820
|
-
return
|
|
36012
|
+
const path8 = this._matcher.path;
|
|
36013
|
+
if (path8.length === 0) return -1;
|
|
36014
|
+
return path8[path8.length - 1].position ?? 0;
|
|
35821
36015
|
}
|
|
35822
36016
|
/**
|
|
35823
36017
|
* Get current node's repeat counter (occurrence count of this tag name).
|
|
35824
36018
|
* @returns {number}
|
|
35825
36019
|
*/
|
|
35826
36020
|
getCounter() {
|
|
35827
|
-
const
|
|
35828
|
-
if (
|
|
35829
|
-
return
|
|
36021
|
+
const path8 = this._matcher.path;
|
|
36022
|
+
if (path8.length === 0) return -1;
|
|
36023
|
+
return path8[path8.length - 1].counter ?? 0;
|
|
35830
36024
|
}
|
|
35831
36025
|
/**
|
|
35832
36026
|
* Get current node's sibling index (alias for getPosition).
|
|
@@ -37681,8 +37875,8 @@ function isAttribute(name) {
|
|
|
37681
37875
|
}
|
|
37682
37876
|
|
|
37683
37877
|
// ../../node_modules/fflate/esm/index.mjs
|
|
37684
|
-
import { createRequire } from "module";
|
|
37685
|
-
var require2 =
|
|
37878
|
+
import { createRequire as createRequire2 } from "module";
|
|
37879
|
+
var require2 = createRequire2("/");
|
|
37686
37880
|
var Worker;
|
|
37687
37881
|
try {
|
|
37688
37882
|
Worker = require2("worker_threads").Worker;
|
|
@@ -41282,10 +41476,10 @@ function resolveRelativePath(basePath, relativePath) {
|
|
|
41282
41476
|
}
|
|
41283
41477
|
return resolved.join("/");
|
|
41284
41478
|
}
|
|
41285
|
-
function findZipEntry(zipEntries,
|
|
41286
|
-
if (zipEntries[
|
|
41287
|
-
if (zipEntries[`xl/${
|
|
41288
|
-
const noSlash =
|
|
41479
|
+
function findZipEntry(zipEntries, path8) {
|
|
41480
|
+
if (zipEntries[path8]) return zipEntries[path8];
|
|
41481
|
+
if (zipEntries[`xl/${path8}`]) return zipEntries[`xl/${path8}`];
|
|
41482
|
+
const noSlash = path8.replace(/^\//, "");
|
|
41289
41483
|
if (zipEntries[noSlash]) return zipEntries[noSlash];
|
|
41290
41484
|
return void 0;
|
|
41291
41485
|
}
|
|
@@ -42583,9 +42777,9 @@ function parseExcelFromZip(zip, options) {
|
|
|
42583
42777
|
}
|
|
42584
42778
|
return result;
|
|
42585
42779
|
}
|
|
42586
|
-
function findEntry(zip,
|
|
42587
|
-
if (zip[
|
|
42588
|
-
const lower =
|
|
42780
|
+
function findEntry(zip, path8) {
|
|
42781
|
+
if (zip[path8]) return zip[path8];
|
|
42782
|
+
const lower = path8.toLowerCase();
|
|
42589
42783
|
for (const key of Object.keys(zip)) {
|
|
42590
42784
|
if (key.toLowerCase() === lower) return zip[key];
|
|
42591
42785
|
}
|
|
@@ -43196,12 +43390,12 @@ function extractPivotRoundTripInfo(originalZip) {
|
|
|
43196
43390
|
if (paths.length > 0) pivotTablesBySheetIndex.set(i2, paths);
|
|
43197
43391
|
}
|
|
43198
43392
|
const pivotXmlPaths = [];
|
|
43199
|
-
for (const
|
|
43200
|
-
if (
|
|
43201
|
-
pivotXmlPaths.push(
|
|
43393
|
+
for (const path8 of Object.keys(originalZip)) {
|
|
43394
|
+
if (path8.startsWith("xl/pivotTables/") && path8.endsWith(".xml")) {
|
|
43395
|
+
pivotXmlPaths.push(path8);
|
|
43202
43396
|
}
|
|
43203
|
-
if (
|
|
43204
|
-
pivotXmlPaths.push(
|
|
43397
|
+
if (path8.startsWith("xl/pivotCache/") && path8.endsWith(".xml")) {
|
|
43398
|
+
pivotXmlPaths.push(path8);
|
|
43205
43399
|
}
|
|
43206
43400
|
}
|
|
43207
43401
|
return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths };
|
|
@@ -43209,15 +43403,15 @@ function extractPivotRoundTripInfo(originalZip) {
|
|
|
43209
43403
|
function decode(bytes) {
|
|
43210
43404
|
return new TextDecoder().decode(bytes);
|
|
43211
43405
|
}
|
|
43212
|
-
function pivotContentTypeFor(
|
|
43213
|
-
if (
|
|
43214
|
-
return `<Override PartName="/${
|
|
43406
|
+
function pivotContentTypeFor(path8) {
|
|
43407
|
+
if (path8.startsWith("xl/pivotTables/") && path8.endsWith(".xml")) {
|
|
43408
|
+
return `<Override PartName="/${path8}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
|
|
43215
43409
|
}
|
|
43216
|
-
if (
|
|
43217
|
-
return `<Override PartName="/${
|
|
43410
|
+
if (path8.includes("/pivotCacheDefinition") && path8.endsWith(".xml")) {
|
|
43411
|
+
return `<Override PartName="/${path8}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
|
|
43218
43412
|
}
|
|
43219
|
-
if (
|
|
43220
|
-
return `<Override PartName="/${
|
|
43413
|
+
if (path8.includes("/pivotCacheRecords") && path8.endsWith(".xml")) {
|
|
43414
|
+
return `<Override PartName="/${path8}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
|
|
43221
43415
|
}
|
|
43222
43416
|
return void 0;
|
|
43223
43417
|
}
|
|
@@ -43289,13 +43483,13 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
43289
43483
|
regeneratedPaths.add(`xl/worksheets/sheet${i2 + 1}.xml`);
|
|
43290
43484
|
regeneratedPaths.add(`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`);
|
|
43291
43485
|
}
|
|
43292
|
-
for (const
|
|
43293
|
-
if (
|
|
43294
|
-
regeneratedPaths.add(
|
|
43486
|
+
for (const path8 of Object.keys(originalZip)) {
|
|
43487
|
+
if (path8.startsWith("xl/drawings/") || path8.startsWith("xl/charts/") || path8.startsWith("xl/tables/") || path8.startsWith("xl/media/")) {
|
|
43488
|
+
regeneratedPaths.add(path8);
|
|
43295
43489
|
}
|
|
43296
43490
|
}
|
|
43297
|
-
for (const [
|
|
43298
|
-
if (!regeneratedPaths.has(
|
|
43491
|
+
for (const [path8, data] of Object.entries(originalZip)) {
|
|
43492
|
+
if (!regeneratedPaths.has(path8)) entries[path8] = data;
|
|
43299
43493
|
}
|
|
43300
43494
|
}
|
|
43301
43495
|
const sharedStrings = buildSharedStrings(workbook);
|
|
@@ -43310,8 +43504,8 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
43310
43504
|
buildWorkbookRels(workbook, pivotInfo)
|
|
43311
43505
|
);
|
|
43312
43506
|
const extraContentTypes = [];
|
|
43313
|
-
for (const
|
|
43314
|
-
const ct = pivotContentTypeFor(
|
|
43507
|
+
for (const path8 of pivotInfo.pivotXmlPaths) {
|
|
43508
|
+
const ct = pivotContentTypeFor(path8);
|
|
43315
43509
|
if (ct) extraContentTypes.push(ct);
|
|
43316
43510
|
}
|
|
43317
43511
|
let globalChartIndex = 1;
|
|
@@ -45072,14 +45266,14 @@ var DependencyGraph = class {
|
|
|
45072
45266
|
stack.push({ cell: p, path: [cell, p] });
|
|
45073
45267
|
}
|
|
45074
45268
|
while (stack.length > 0) {
|
|
45075
|
-
const { cell: current, path:
|
|
45076
|
-
if (current === cell) return
|
|
45269
|
+
const { cell: current, path: path8 } = stack.pop();
|
|
45270
|
+
if (current === cell) return path8;
|
|
45077
45271
|
if (visited.has(current)) continue;
|
|
45078
45272
|
visited.add(current);
|
|
45079
45273
|
const nextPrec = this.precedents.get(current);
|
|
45080
45274
|
if (!nextPrec) continue;
|
|
45081
45275
|
for (const p of nextPrec) {
|
|
45082
|
-
stack.push({ cell: p, path: [...
|
|
45276
|
+
stack.push({ cell: p, path: [...path8, p] });
|
|
45083
45277
|
}
|
|
45084
45278
|
}
|
|
45085
45279
|
return null;
|
|
@@ -46070,8 +46264,8 @@ function adjustMergedCellsForColDelete(sheet, atCol, count) {
|
|
|
46070
46264
|
|
|
46071
46265
|
// src/xlsx.ts
|
|
46072
46266
|
function loadFile(filePath) {
|
|
46073
|
-
if (!
|
|
46074
|
-
const buffer =
|
|
46267
|
+
if (!fs6.existsSync(filePath)) fail(`File not found: ${filePath}`);
|
|
46268
|
+
const buffer = fs6.readFileSync(filePath);
|
|
46075
46269
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
46076
46270
|
const originalZip = unzipXlsx(arrayBuffer);
|
|
46077
46271
|
const parsed = parseExcelBuffer(arrayBuffer);
|
|
@@ -46121,7 +46315,7 @@ function lazyEngine(workbook) {
|
|
|
46121
46315
|
};
|
|
46122
46316
|
}
|
|
46123
46317
|
function readToJson(filePath) {
|
|
46124
|
-
const buffer =
|
|
46318
|
+
const buffer = fs6.readFileSync(filePath);
|
|
46125
46319
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
46126
46320
|
const parsed = parseExcelBuffer(arrayBuffer);
|
|
46127
46321
|
return {
|
|
@@ -46511,7 +46705,7 @@ async function runXlsxCommand(subcommand, toolArgs, restArgs) {
|
|
|
46511
46705
|
}
|
|
46512
46706
|
|
|
46513
46707
|
// src/docx.ts
|
|
46514
|
-
import
|
|
46708
|
+
import fs7 from "node:fs";
|
|
46515
46709
|
|
|
46516
46710
|
// ../docx/src/parse/parser.ts
|
|
46517
46711
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
@@ -48282,11 +48476,11 @@ async function parseDocx(buffer) {
|
|
|
48282
48476
|
const zip = await import_jszip.default.loadAsync(buffer);
|
|
48283
48477
|
const parts = /* @__PURE__ */ new Map();
|
|
48284
48478
|
const filePromises = [];
|
|
48285
|
-
zip.forEach((
|
|
48479
|
+
zip.forEach((path8, file) => {
|
|
48286
48480
|
if (file.dir) return;
|
|
48287
48481
|
filePromises.push(
|
|
48288
48482
|
file.async("uint8array").then((bytes) => {
|
|
48289
|
-
parts.set(
|
|
48483
|
+
parts.set(path8, bytes);
|
|
48290
48484
|
})
|
|
48291
48485
|
);
|
|
48292
48486
|
});
|
|
@@ -48515,9 +48709,9 @@ var DEFAULT_PARTS = [
|
|
|
48515
48709
|
["word/theme/theme1.xml", () => encoder.encode(THEME_XML)]
|
|
48516
48710
|
];
|
|
48517
48711
|
function fillDefaultParts(parts) {
|
|
48518
|
-
for (const [
|
|
48519
|
-
if (!parts.has(
|
|
48520
|
-
parts.set(
|
|
48712
|
+
for (const [path8, makeBytes] of DEFAULT_PARTS) {
|
|
48713
|
+
if (!parts.has(path8)) {
|
|
48714
|
+
parts.set(path8, makeBytes());
|
|
48521
48715
|
}
|
|
48522
48716
|
}
|
|
48523
48717
|
return parts;
|
|
@@ -48527,9 +48721,9 @@ function fillDefaultParts(parts) {
|
|
|
48527
48721
|
async function serializeDocx(doc) {
|
|
48528
48722
|
const zip = new import_jszip2.default();
|
|
48529
48723
|
const parts = fillDefaultParts(new Map(doc.parts));
|
|
48530
|
-
for (const [
|
|
48531
|
-
if (
|
|
48532
|
-
zip.file(
|
|
48724
|
+
for (const [path8, bytes] of parts) {
|
|
48725
|
+
if (path8 === "word/document.xml") continue;
|
|
48726
|
+
zip.file(path8, bytes);
|
|
48533
48727
|
}
|
|
48534
48728
|
const documentXml = serializeDocumentXml(doc);
|
|
48535
48729
|
zip.file("word/document.xml", documentXml);
|
|
@@ -48615,8 +48809,8 @@ var DEFAULT_DOC_ATTRS = {
|
|
|
48615
48809
|
"@_xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
|
48616
48810
|
};
|
|
48617
48811
|
async function loadFile2(filePath) {
|
|
48618
|
-
if (!
|
|
48619
|
-
const bytes =
|
|
48812
|
+
if (!fs7.existsSync(filePath)) fail(`File not found: ${filePath}`);
|
|
48813
|
+
const bytes = fs7.readFileSync(filePath);
|
|
48620
48814
|
return parseDocx(new Uint8Array(bytes));
|
|
48621
48815
|
}
|
|
48622
48816
|
async function writeDoc(filePath, doc) {
|
|
@@ -48973,6 +49167,8 @@ COMMANDS
|
|
|
48973
49167
|
lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body
|
|
48974
49168
|
through set_app_workflow (server verifies)
|
|
48975
49169
|
lotics app workflow pull Rewrite src/workflows/*.ts from the server
|
|
49170
|
+
lotics app workflow check [alias] Typecheck src/workflows bodies locally (one
|
|
49171
|
+
isolated program per alias; the app's own tsc)
|
|
48976
49172
|
lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address
|
|
48977
49173
|
lotics app rename "<new name>" Rename the app's display name (launcher title)
|
|
48978
49174
|
lotics app dev [path] Run the app locally with HMR (RPC forwarded to prod)
|
|
@@ -49080,8 +49276,8 @@ function prompt(question) {
|
|
|
49080
49276
|
});
|
|
49081
49277
|
});
|
|
49082
49278
|
}
|
|
49083
|
-
async function publicPost(
|
|
49084
|
-
const response = await fetch(`${API_BASE_URL}${
|
|
49279
|
+
async function publicPost(path8, body) {
|
|
49280
|
+
const response = await fetch(`${API_BASE_URL}${path8}`, {
|
|
49085
49281
|
method: "POST",
|
|
49086
49282
|
headers: { "Content-Type": "application/json" },
|
|
49087
49283
|
body: JSON.stringify(body)
|
|
@@ -49227,13 +49423,13 @@ async function resolveWorkspace(client, ctx) {
|
|
|
49227
49423
|
function resolveUploadPaths(rawPaths) {
|
|
49228
49424
|
const result = [];
|
|
49229
49425
|
for (const p of rawPaths) {
|
|
49230
|
-
const resolved =
|
|
49231
|
-
const stat =
|
|
49426
|
+
const resolved = path7.resolve(p);
|
|
49427
|
+
const stat = fs8.statSync(resolved);
|
|
49232
49428
|
if (stat.isDirectory()) {
|
|
49233
|
-
const entries =
|
|
49429
|
+
const entries = fs8.readdirSync(resolved, { withFileTypes: true });
|
|
49234
49430
|
for (const entry of entries) {
|
|
49235
49431
|
if (entry.isFile()) {
|
|
49236
|
-
result.push(
|
|
49432
|
+
result.push(path7.join(resolved, entry.name));
|
|
49237
49433
|
}
|
|
49238
49434
|
}
|
|
49239
49435
|
} else {
|
|
@@ -49352,6 +49548,10 @@ async function main() {
|
|
|
49352
49548
|
console.error("Usage: lotics ui link <component> [--remove]");
|
|
49353
49549
|
process.exit(1);
|
|
49354
49550
|
}
|
|
49551
|
+
if (command === "app" && subcommand === "workflow" && toolArgs === "check") {
|
|
49552
|
+
await appWorkflowCheck({ alias: restArgs[0] });
|
|
49553
|
+
return;
|
|
49554
|
+
}
|
|
49355
49555
|
if (command === "app" && subcommand === "codegen") {
|
|
49356
49556
|
const projectDir = toolArgs;
|
|
49357
49557
|
const ctx2 = resolveContext(flags);
|
|
@@ -49436,6 +49636,7 @@ async function main() {
|
|
|
49436
49636
|
console.error(" lotics app workflow run <alias> '<json>' Execute a bound app workflow end-to-end");
|
|
49437
49637
|
console.error(" lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body");
|
|
49438
49638
|
console.error(" lotics app workflow pull Rewrite src/workflows/*.ts from the server");
|
|
49639
|
+
console.error(" lotics app workflow check [alias] Typecheck src/workflows bodies locally");
|
|
49439
49640
|
console.error(" lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address");
|
|
49440
49641
|
console.error(` lotics app rename "<new name>" Rename the app's display name (launcher title)`);
|
|
49441
49642
|
console.error(" lotics app dev [path] Run the app locally with HMR + RPC forwarding");
|
|
@@ -49584,6 +49785,7 @@ Available workspaces:`);
|
|
|
49584
49785
|
console.error(" lotics app workflow run <alias> '<json>' Execute a bound app workflow");
|
|
49585
49786
|
console.error(" lotics app workflow set <alias> Push src/workflows/<alias>.ts");
|
|
49586
49787
|
console.error(" lotics app workflow pull Rewrite src/workflows/*.ts from the server");
|
|
49788
|
+
console.error(" lotics app workflow check [alias] Typecheck src/workflows bodies locally");
|
|
49587
49789
|
process.exit(1);
|
|
49588
49790
|
};
|
|
49589
49791
|
if (action === "run") {
|
|
@@ -49599,7 +49801,7 @@ Available workspaces:`);
|
|
|
49599
49801
|
const ingested = await ingestJsonArgs({
|
|
49600
49802
|
rawArg: restArgs[1],
|
|
49601
49803
|
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
49602
|
-
readFile: (p) =>
|
|
49804
|
+
readFile: (p) => fs8.readFileSync(p, "utf-8"),
|
|
49603
49805
|
readStdin
|
|
49604
49806
|
});
|
|
49605
49807
|
if (ingested.kind === "error") {
|
|
@@ -49731,7 +49933,7 @@ ${JSON.stringify(info.input_schema, null, 2)}`);
|
|
|
49731
49933
|
const ingested = await ingestJsonArgs({
|
|
49732
49934
|
rawArg: toolArgs,
|
|
49733
49935
|
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
49734
|
-
readFile: (p) =>
|
|
49936
|
+
readFile: (p) => fs8.readFileSync(p, "utf-8"),
|
|
49735
49937
|
readStdin
|
|
49736
49938
|
});
|
|
49737
49939
|
if (ingested.kind === "error") {
|