@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/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 +432 -233
- package/dist/starter_template.js +22 -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
|
|
@@ -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 =
|
|
32140
|
-
var WORKFLOW_GLOBALS_DIR =
|
|
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 =
|
|
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
|
|
32228
|
+
return path5.join(projectDir, WORKFLOWS_DIR, `${alias}.ts`);
|
|
32158
32229
|
}
|
|
32159
32230
|
function workflowGlobalsPath(projectDir, alias) {
|
|
32160
|
-
return
|
|
32231
|
+
return path5.join(projectDir, WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`);
|
|
32161
32232
|
}
|
|
32162
32233
|
function writeWorkflowGlobals(projectDir, alias, dts) {
|
|
32163
|
-
const dir =
|
|
32164
|
-
|
|
32234
|
+
const dir = path5.join(projectDir, WORKFLOW_GLOBALS_DIR);
|
|
32235
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
32165
32236
|
const file = workflowGlobalsPath(projectDir, alias);
|
|
32166
|
-
|
|
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 =
|
|
32172
|
-
|
|
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
|
-
|
|
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 =
|
|
32257
|
-
if (!
|
|
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(
|
|
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 =
|
|
32279
|
-
const pkg2 = JSON.parse(
|
|
32349
|
+
const pkgPath2 = path5.join(projectDir, "package.json");
|
|
32350
|
+
const pkg2 = JSON.parse(fs4.readFileSync(pkgPath2, "utf-8"));
|
|
32280
32351
|
pkg2.lotics = meta;
|
|
32281
|
-
|
|
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 =
|
|
32285
|
-
|
|
32383
|
+
const dotLotics = path5.join(projectDir, ".lotics");
|
|
32384
|
+
fs4.mkdirSync(dotLotics, { recursive: true });
|
|
32286
32385
|
const written = [
|
|
32287
|
-
[
|
|
32288
|
-
[
|
|
32289
|
-
[
|
|
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)
|
|
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(
|
|
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 =
|
|
32309
|
-
|
|
32310
|
-
const file =
|
|
32311
|
-
|
|
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 =
|
|
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 (!
|
|
32345
|
-
const body = stripWorkflowHeader(
|
|
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 ${
|
|
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
|
-
|
|
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 =
|
|
32378
|
-
if (
|
|
32379
|
-
const entries =
|
|
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
|
-
|
|
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 =
|
|
32400
|
-
|
|
32401
|
-
|
|
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 ${
|
|
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 =
|
|
32439
|
-
|
|
32440
|
-
const tmpFile =
|
|
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 (
|
|
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 ${
|
|
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 =
|
|
32488
|
-
if (!
|
|
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
|
|
32492
|
-
const full =
|
|
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(
|
|
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 =
|
|
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 =
|
|
32516
|
-
if (!
|
|
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 =
|
|
32522
|
-
const tmpDist =
|
|
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:
|
|
32545
|
-
dist_archive:
|
|
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 (
|
|
32580
|
-
if (
|
|
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 =
|
|
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 (!
|
|
32856
|
+
if (!fs4.existsSync(file)) {
|
|
32741
32857
|
console.error(
|
|
32742
|
-
`No workflow body at ${
|
|
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(
|
|
32862
|
+
const source = stripWorkflowHeader(fs4.readFileSync(file, "utf-8"));
|
|
32747
32863
|
if (source.trim() === "") {
|
|
32748
|
-
console.error(`Workflow body ${
|
|
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 =
|
|
32973
|
+
let dir = path5.resolve(start);
|
|
32783
32974
|
for (; ; ) {
|
|
32784
|
-
const candidate =
|
|
32785
|
-
if (
|
|
32786
|
-
const parent =
|
|
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 =
|
|
32794
|
-
const viteConfigPath =
|
|
32795
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
33167
|
+
import fs6 from "node:fs";
|
|
32977
33168
|
|
|
32978
33169
|
// src/file_command_io.ts
|
|
32979
|
-
import
|
|
32980
|
-
import
|
|
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 =
|
|
32992
|
-
const tmp =
|
|
32993
|
-
|
|
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
|
-
|
|
33186
|
+
fs5.renameSync(tmp, filePath);
|
|
32996
33187
|
} catch (error) {
|
|
32997
33188
|
try {
|
|
32998
|
-
|
|
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
|
|
35782
|
-
return
|
|
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
|
|
35790
|
-
return
|
|
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
|
|
35799
|
-
if (
|
|
35800
|
-
return
|
|
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
|
|
35809
|
-
if (
|
|
35810
|
-
const current =
|
|
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
|
|
35819
|
-
if (
|
|
35820
|
-
return
|
|
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
|
|
35828
|
-
if (
|
|
35829
|
-
return
|
|
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 =
|
|
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,
|
|
41286
|
-
if (zipEntries[
|
|
41287
|
-
if (zipEntries[`xl/${
|
|
41288
|
-
const noSlash =
|
|
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,
|
|
42587
|
-
if (zip[
|
|
42588
|
-
const lower =
|
|
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
|
|
43200
|
-
if (
|
|
43201
|
-
pivotXmlPaths.push(
|
|
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 (
|
|
43204
|
-
pivotXmlPaths.push(
|
|
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(
|
|
43213
|
-
if (
|
|
43214
|
-
return `<Override PartName="/${
|
|
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 (
|
|
43217
|
-
return `<Override PartName="/${
|
|
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 (
|
|
43220
|
-
return `<Override PartName="/${
|
|
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
|
|
43293
|
-
if (
|
|
43294
|
-
regeneratedPaths.add(
|
|
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 [
|
|
43298
|
-
if (!regeneratedPaths.has(
|
|
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
|
|
43314
|
-
const ct = pivotContentTypeFor(
|
|
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:
|
|
45076
|
-
if (current === cell) return
|
|
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: [...
|
|
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 (!
|
|
46074
|
-
const buffer =
|
|
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 =
|
|
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
|
|
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((
|
|
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(
|
|
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 [
|
|
48519
|
-
if (!parts.has(
|
|
48520
|
-
parts.set(
|
|
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 [
|
|
48531
|
-
if (
|
|
48532
|
-
zip.file(
|
|
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 (!
|
|
48619
|
-
const bytes =
|
|
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(
|
|
49084
|
-
const response = await fetch(`${API_BASE_URL}${
|
|
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 =
|
|
49231
|
-
const stat =
|
|
49423
|
+
const resolved = path7.resolve(p);
|
|
49424
|
+
const stat = fs8.statSync(resolved);
|
|
49232
49425
|
if (stat.isDirectory()) {
|
|
49233
|
-
const entries =
|
|
49426
|
+
const entries = fs8.readdirSync(resolved, { withFileTypes: true });
|
|
49234
49427
|
for (const entry of entries) {
|
|
49235
49428
|
if (entry.isFile()) {
|
|
49236
|
-
result.push(
|
|
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) =>
|
|
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) =>
|
|
49933
|
+
readFile: (p) => fs8.readFileSync(p, "utf-8"),
|
|
49735
49934
|
readStdin
|
|
49736
49935
|
});
|
|
49737
49936
|
if (ingested.kind === "error") {
|