@lotics/cli 0.165.0 → 0.172.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 +25 -4
- package/dist/src/cli.js +745 -423
- package/dist/src/client.d.ts +38 -1
- package/dist/src/client.js +42 -0
- package/docs/building_an_app.md +8 -0
- package/docs/cli_reference.md +3 -2
- package/package.json +4 -1
package/dist/src/cli.js
CHANGED
|
@@ -26822,12 +26822,12 @@ var require_tokens = __commonJS({
|
|
|
26822
26822
|
});
|
|
26823
26823
|
}
|
|
26824
26824
|
exports2.assignCategoriesMapProp = assignCategoriesMapProp;
|
|
26825
|
-
function singleAssignCategoriesToksMap(
|
|
26826
|
-
utils_1.forEach(
|
|
26825
|
+
function singleAssignCategoriesToksMap(path13, nextNode) {
|
|
26826
|
+
utils_1.forEach(path13, function(pathNode) {
|
|
26827
26827
|
nextNode.categoryMatchesMap[pathNode.tokenTypeIdx] = true;
|
|
26828
26828
|
});
|
|
26829
26829
|
utils_1.forEach(nextNode.CATEGORIES, function(nextCategory) {
|
|
26830
|
-
var newPath =
|
|
26830
|
+
var newPath = path13.concat(nextNode);
|
|
26831
26831
|
if (!utils_1.contains(newPath, nextCategory)) {
|
|
26832
26832
|
singleAssignCategoriesToksMap(newPath, nextCategory);
|
|
26833
26833
|
}
|
|
@@ -28590,10 +28590,10 @@ var require_interpreter = __commonJS({
|
|
|
28590
28590
|
/** @class */
|
|
28591
28591
|
(function(_super) {
|
|
28592
28592
|
__extends(AbstractNextPossibleTokensWalker2, _super);
|
|
28593
|
-
function AbstractNextPossibleTokensWalker2(topProd,
|
|
28593
|
+
function AbstractNextPossibleTokensWalker2(topProd, path13) {
|
|
28594
28594
|
var _this = _super.call(this) || this;
|
|
28595
28595
|
_this.topProd = topProd;
|
|
28596
|
-
_this.path =
|
|
28596
|
+
_this.path = path13;
|
|
28597
28597
|
_this.possibleTokTypes = [];
|
|
28598
28598
|
_this.nextProductionName = "";
|
|
28599
28599
|
_this.nextProductionOccurrence = 0;
|
|
@@ -28647,9 +28647,9 @@ var require_interpreter = __commonJS({
|
|
|
28647
28647
|
/** @class */
|
|
28648
28648
|
(function(_super) {
|
|
28649
28649
|
__extends(NextAfterTokenWalker2, _super);
|
|
28650
|
-
function NextAfterTokenWalker2(topProd,
|
|
28651
|
-
var _this = _super.call(this, topProd,
|
|
28652
|
-
_this.path =
|
|
28650
|
+
function NextAfterTokenWalker2(topProd, path13) {
|
|
28651
|
+
var _this = _super.call(this, topProd, path13) || this;
|
|
28652
|
+
_this.path = path13;
|
|
28653
28653
|
_this.nextTerminalName = "";
|
|
28654
28654
|
_this.nextTerminalOccurrence = 0;
|
|
28655
28655
|
_this.nextTerminalName = _this.path.lastTok.name;
|
|
@@ -29346,10 +29346,10 @@ var require_lookahead = __commonJS({
|
|
|
29346
29346
|
}
|
|
29347
29347
|
return result;
|
|
29348
29348
|
}
|
|
29349
|
-
function pathToHashKeys(
|
|
29349
|
+
function pathToHashKeys(path13) {
|
|
29350
29350
|
var keys3 = [""];
|
|
29351
|
-
for (var i2 = 0; i2 <
|
|
29352
|
-
var tokType =
|
|
29351
|
+
for (var i2 = 0; i2 < path13.length; i2++) {
|
|
29352
|
+
var tokType = path13[i2];
|
|
29353
29353
|
var longerKeys = [];
|
|
29354
29354
|
for (var j = 0; j < keys3.length; j++) {
|
|
29355
29355
|
var currShorterKey = keys3[j];
|
|
@@ -29661,9 +29661,9 @@ var require_checks = __commonJS({
|
|
|
29661
29661
|
return errors2;
|
|
29662
29662
|
}
|
|
29663
29663
|
exports2.validateRuleIsOverridden = validateRuleIsOverridden;
|
|
29664
|
-
function validateNoLeftRecursion(topRule, currRule, errMsgProvider,
|
|
29665
|
-
if (
|
|
29666
|
-
|
|
29664
|
+
function validateNoLeftRecursion(topRule, currRule, errMsgProvider, path13) {
|
|
29665
|
+
if (path13 === void 0) {
|
|
29666
|
+
path13 = [];
|
|
29667
29667
|
}
|
|
29668
29668
|
var errors2 = [];
|
|
29669
29669
|
var nextNonTerminals = getFirstNoneTerminal(currRule.definition);
|
|
@@ -29676,15 +29676,15 @@ var require_checks = __commonJS({
|
|
|
29676
29676
|
errors2.push({
|
|
29677
29677
|
message: errMsgProvider.buildLeftRecursionError({
|
|
29678
29678
|
topLevelRule: topRule,
|
|
29679
|
-
leftRecursionPath:
|
|
29679
|
+
leftRecursionPath: path13
|
|
29680
29680
|
}),
|
|
29681
29681
|
type: parser_1.ParserDefinitionErrorType.LEFT_RECURSION,
|
|
29682
29682
|
ruleName
|
|
29683
29683
|
});
|
|
29684
29684
|
}
|
|
29685
|
-
var validNextSteps = utils2.difference(nextNonTerminals,
|
|
29685
|
+
var validNextSteps = utils2.difference(nextNonTerminals, path13.concat([topRule]));
|
|
29686
29686
|
var errorsFromNextSteps = utils2.map(validNextSteps, function(currRefRule) {
|
|
29687
|
-
var newPath = utils2.cloneArr(
|
|
29687
|
+
var newPath = utils2.cloneArr(path13);
|
|
29688
29688
|
newPath.push(currRefRule);
|
|
29689
29689
|
return validateNoLeftRecursion(topRule, currRefRule, errMsgProvider, newPath);
|
|
29690
29690
|
});
|
|
@@ -37293,8 +37293,8 @@ var require_utils4 = __commonJS({
|
|
|
37293
37293
|
var result = transform2[inputType][outputType](input);
|
|
37294
37294
|
return result;
|
|
37295
37295
|
};
|
|
37296
|
-
exports2.resolve = function(
|
|
37297
|
-
var parts =
|
|
37296
|
+
exports2.resolve = function(path13) {
|
|
37297
|
+
var parts = path13.split("/");
|
|
37298
37298
|
var result = [];
|
|
37299
37299
|
for (var index = 0; index < parts.length; index++) {
|
|
37300
37300
|
var part = parts[index];
|
|
@@ -43147,18 +43147,18 @@ var require_object = __commonJS({
|
|
|
43147
43147
|
var object2 = new ZipObject(name2, zipObjectContent, o);
|
|
43148
43148
|
this.files[name2] = object2;
|
|
43149
43149
|
};
|
|
43150
|
-
var parentFolder = function(
|
|
43151
|
-
if (
|
|
43152
|
-
|
|
43150
|
+
var parentFolder = function(path13) {
|
|
43151
|
+
if (path13.slice(-1) === "/") {
|
|
43152
|
+
path13 = path13.substring(0, path13.length - 1);
|
|
43153
43153
|
}
|
|
43154
|
-
var lastSlash =
|
|
43155
|
-
return lastSlash > 0 ?
|
|
43154
|
+
var lastSlash = path13.lastIndexOf("/");
|
|
43155
|
+
return lastSlash > 0 ? path13.substring(0, lastSlash) : "";
|
|
43156
43156
|
};
|
|
43157
|
-
var forceTrailingSlash = function(
|
|
43158
|
-
if (
|
|
43159
|
-
|
|
43157
|
+
var forceTrailingSlash = function(path13) {
|
|
43158
|
+
if (path13.slice(-1) !== "/") {
|
|
43159
|
+
path13 += "/";
|
|
43160
43160
|
}
|
|
43161
|
-
return
|
|
43161
|
+
return path13;
|
|
43162
43162
|
};
|
|
43163
43163
|
var folderAdd = function(name2, createFolders) {
|
|
43164
43164
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults2.createFolders;
|
|
@@ -44162,7 +44162,7 @@ import dns from "node:dns";
|
|
|
44162
44162
|
import net2 from "node:net";
|
|
44163
44163
|
import fs14 from "node:fs";
|
|
44164
44164
|
import os4 from "node:os";
|
|
44165
|
-
import
|
|
44165
|
+
import path12 from "node:path";
|
|
44166
44166
|
import readline from "node:readline";
|
|
44167
44167
|
|
|
44168
44168
|
// ../shared/src/transport_error.ts
|
|
@@ -44301,6 +44301,26 @@ function getMimeType(filename) {
|
|
|
44301
44301
|
return MIME_MAP[ext] ?? "application/octet-stream";
|
|
44302
44302
|
}
|
|
44303
44303
|
var API_BASE_URL = process.env.LOTICS_API_URL ?? "https://api.lotics.ai";
|
|
44304
|
+
var WEB_APP_URL = "https://lotics.ai";
|
|
44305
|
+
async function fetchOfficialStarters() {
|
|
44306
|
+
let response;
|
|
44307
|
+
try {
|
|
44308
|
+
response = await fetch(`${API_BASE_URL}/v1/starters/official`, {
|
|
44309
|
+
signal: AbortSignal.timeout(SHELF_FETCH_TIMEOUT_MS)
|
|
44310
|
+
});
|
|
44311
|
+
} catch (error52) {
|
|
44312
|
+
throw new Error(
|
|
44313
|
+
`Could not reach Lotics to list the starters (${error52 instanceof Error ? error52.message : String(error52)}). Check your connection, or browse ${WEB_APP_URL}/docs/cli.`
|
|
44314
|
+
);
|
|
44315
|
+
}
|
|
44316
|
+
if (!response.ok) {
|
|
44317
|
+
throw new Error(
|
|
44318
|
+
`Lotics answered ${response.status} listing the starters. If this keeps happening, browse ${WEB_APP_URL}/docs/cli.`
|
|
44319
|
+
);
|
|
44320
|
+
}
|
|
44321
|
+
return await response.json();
|
|
44322
|
+
}
|
|
44323
|
+
var SHELF_FETCH_TIMEOUT_MS = 1e4;
|
|
44304
44324
|
var LoticsClient = class {
|
|
44305
44325
|
apiKey;
|
|
44306
44326
|
workspaceId;
|
|
@@ -44358,8 +44378,8 @@ var LoticsClient = class {
|
|
|
44358
44378
|
}
|
|
44359
44379
|
return headers;
|
|
44360
44380
|
}
|
|
44361
|
-
async request(method,
|
|
44362
|
-
const url2 = `${this.baseUrl}${
|
|
44381
|
+
async request(method, path13, body) {
|
|
44382
|
+
const url2 = `${this.baseUrl}${path13}`;
|
|
44363
44383
|
const headers = this.buildHeaders();
|
|
44364
44384
|
const init = { method, headers };
|
|
44365
44385
|
if (body !== void 0) {
|
|
@@ -45605,11 +45625,15 @@ function isNewerVersion(latest, current) {
|
|
|
45605
45625
|
if (lMin !== cMin) return lMin > cMin;
|
|
45606
45626
|
return lPat > cPat;
|
|
45607
45627
|
}
|
|
45628
|
+
function updateCommand() {
|
|
45629
|
+
if (process.versions.bun === void 0) return "npm i -g @lotics/cli";
|
|
45630
|
+
return process.platform === "win32" ? "irm https://lotics.ai/install.ps1 | iex" : "curl -fsSL https://lotics.ai/install.sh | bash";
|
|
45631
|
+
}
|
|
45608
45632
|
function printUpdateWarning(current, latest) {
|
|
45609
45633
|
if (!isNewerVersion(latest, current)) return;
|
|
45610
45634
|
console.error(`
|
|
45611
45635
|
Update available: ${current} \u2192 ${latest}`);
|
|
45612
|
-
console.error(`Run:
|
|
45636
|
+
console.error(`Run: ${updateCommand()}
|
|
45613
45637
|
`);
|
|
45614
45638
|
}
|
|
45615
45639
|
|
|
@@ -45672,17 +45696,22 @@ function resultSideEffects(result) {
|
|
|
45672
45696
|
}
|
|
45673
45697
|
|
|
45674
45698
|
// src/version.ts
|
|
45675
|
-
|
|
45676
|
-
|
|
45677
|
-
|
|
45678
|
-
|
|
45679
|
-
|
|
45680
|
-
|
|
45699
|
+
var VERSION = "0.172.0";
|
|
45700
|
+
|
|
45701
|
+
// src/timezone.ts
|
|
45702
|
+
function machineTimezone() {
|
|
45703
|
+
try {
|
|
45704
|
+
const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
45705
|
+
return zone !== void 0 && zone !== "" ? zone : void 0;
|
|
45706
|
+
} catch {
|
|
45707
|
+
return void 0;
|
|
45708
|
+
}
|
|
45709
|
+
}
|
|
45681
45710
|
|
|
45682
45711
|
// src/docs_command.ts
|
|
45683
45712
|
import fs5 from "node:fs";
|
|
45684
|
-
import
|
|
45685
|
-
import { fileURLToPath
|
|
45713
|
+
import path5 from "node:path";
|
|
45714
|
+
import { fileURLToPath } from "node:url";
|
|
45686
45715
|
var READING_ORDER = ["@lotics/app-sdk", "@lotics/ui", "@lotics/cli"];
|
|
45687
45716
|
function firstHeading(file2) {
|
|
45688
45717
|
let text;
|
|
@@ -45699,35 +45728,35 @@ function firstHeading(file2) {
|
|
|
45699
45728
|
}
|
|
45700
45729
|
function readVersion(pkgDir) {
|
|
45701
45730
|
try {
|
|
45702
|
-
const raw = fs5.readFileSync(
|
|
45731
|
+
const raw = fs5.readFileSync(path5.join(pkgDir, "package.json"), "utf-8");
|
|
45703
45732
|
return JSON.parse(raw).version ?? "?";
|
|
45704
45733
|
} catch {
|
|
45705
45734
|
return "?";
|
|
45706
45735
|
}
|
|
45707
45736
|
}
|
|
45708
45737
|
function ownPackageDir() {
|
|
45709
|
-
return
|
|
45738
|
+
return path5.resolve(path5.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
45710
45739
|
}
|
|
45711
45740
|
function referencePackageDirs(projectDir) {
|
|
45712
45741
|
const found = /* @__PURE__ */ new Map();
|
|
45713
45742
|
for (let dir = projectDir; ; ) {
|
|
45714
|
-
const scope =
|
|
45743
|
+
const scope = path5.join(dir, "node_modules", "@lotics");
|
|
45715
45744
|
if (fs5.existsSync(scope)) {
|
|
45716
45745
|
for (const name2 of fs5.readdirSync(scope)) {
|
|
45717
|
-
const pkgDir =
|
|
45718
|
-
const carries = fs5.existsSync(
|
|
45746
|
+
const pkgDir = path5.join(scope, name2);
|
|
45747
|
+
const carries = fs5.existsSync(path5.join(pkgDir, "AGENTS.md")) || fs5.existsSync(path5.join(pkgDir, "docs"));
|
|
45719
45748
|
if (carries && !found.has(`@lotics/${name2}`)) found.set(`@lotics/${name2}`, pkgDir);
|
|
45720
45749
|
}
|
|
45721
45750
|
}
|
|
45722
|
-
const parent =
|
|
45751
|
+
const parent = path5.dirname(dir);
|
|
45723
45752
|
if (parent === dir) break;
|
|
45724
45753
|
dir = parent;
|
|
45725
45754
|
}
|
|
45726
45755
|
const own = ownPackageDir();
|
|
45727
|
-
if (!found.has("@lotics/cli") && fs5.existsSync(
|
|
45756
|
+
if (!found.has("@lotics/cli") && fs5.existsSync(path5.join(own, "AGENTS.md"))) {
|
|
45728
45757
|
found.set("@lotics/cli", own);
|
|
45729
45758
|
}
|
|
45730
|
-
return [...found.entries()].map(([
|
|
45759
|
+
return [...found.entries()].map(([pkg, dir]) => ({ pkg, dir })).sort((a, b) => {
|
|
45731
45760
|
const ia = READING_ORDER.indexOf(a.pkg);
|
|
45732
45761
|
const ib = READING_ORDER.indexOf(b.pkg);
|
|
45733
45762
|
if (ia !== ib) return (ia < 0 ? READING_ORDER.length : ia) - (ib < 0 ? READING_ORDER.length : ib);
|
|
@@ -45736,26 +45765,26 @@ function referencePackageDirs(projectDir) {
|
|
|
45736
45765
|
}
|
|
45737
45766
|
function collectDocAreas(projectDir) {
|
|
45738
45767
|
const found = [];
|
|
45739
|
-
for (const { pkg
|
|
45768
|
+
for (const { pkg, dir } of referencePackageDirs(projectDir)) {
|
|
45740
45769
|
const version2 = readVersion(dir);
|
|
45741
|
-
const index =
|
|
45770
|
+
const index = path5.join(dir, "AGENTS.md");
|
|
45742
45771
|
if (fs5.existsSync(index)) {
|
|
45743
45772
|
found.push({
|
|
45744
|
-
area:
|
|
45745
|
-
pkg
|
|
45773
|
+
area: pkg.replace("@lotics/", ""),
|
|
45774
|
+
pkg,
|
|
45746
45775
|
version: version2,
|
|
45747
45776
|
absPath: index,
|
|
45748
45777
|
title: firstHeading(index)
|
|
45749
45778
|
});
|
|
45750
45779
|
}
|
|
45751
|
-
const docsDir =
|
|
45780
|
+
const docsDir = path5.join(dir, "docs");
|
|
45752
45781
|
if (!fs5.existsSync(docsDir)) continue;
|
|
45753
45782
|
for (const file2 of fs5.readdirSync(docsDir).sort()) {
|
|
45754
45783
|
if (!file2.endsWith(".md")) continue;
|
|
45755
|
-
const abs2 =
|
|
45784
|
+
const abs2 = path5.join(docsDir, file2);
|
|
45756
45785
|
found.push({
|
|
45757
45786
|
area: file2.replace(/\.md$/, ""),
|
|
45758
|
-
pkg
|
|
45787
|
+
pkg,
|
|
45759
45788
|
version: version2,
|
|
45760
45789
|
absPath: abs2,
|
|
45761
45790
|
title: firstHeading(abs2)
|
|
@@ -45802,7 +45831,7 @@ ${a.pkg} ${a.version}`);
|
|
|
45802
45831
|
return lines.join("\n");
|
|
45803
45832
|
}
|
|
45804
45833
|
function docsCommand(args) {
|
|
45805
|
-
const projectDir =
|
|
45834
|
+
const projectDir = path5.resolve(args.projectDir ?? process.cwd());
|
|
45806
45835
|
const areas = collectDocAreas(projectDir);
|
|
45807
45836
|
if (args.area === void 0 || args.area === "") {
|
|
45808
45837
|
console.log(renderDocIndex(areas));
|
|
@@ -45824,13 +45853,26 @@ function docsCommand(args) {
|
|
|
45824
45853
|
process.exit(1);
|
|
45825
45854
|
}
|
|
45826
45855
|
const hit = hits[0];
|
|
45827
|
-
console.error(`${hit.pkg} ${hit.version} \xB7 ${
|
|
45856
|
+
console.error(`${hit.pkg} ${hit.version} \xB7 ${path5.relative(projectDir, hit.absPath)}
|
|
45828
45857
|
`);
|
|
45829
45858
|
process.stdout.write(fs5.readFileSync(hit.absPath, "utf-8"));
|
|
45830
45859
|
}
|
|
45831
45860
|
|
|
45832
45861
|
// src/commands.ts
|
|
45833
45862
|
var COMMANDS = [
|
|
45863
|
+
{
|
|
45864
|
+
verbs: ["start"],
|
|
45865
|
+
help: [
|
|
45866
|
+
" lotics start <starter_id> [path] --email <you@co.com>",
|
|
45867
|
+
" First run, one command: create an account if this",
|
|
45868
|
+
" machine has none, then copy the starter into its",
|
|
45869
|
+
" workspace \u2014 schema, templates, knowledge docs,",
|
|
45870
|
+
" sample records, a deployed app \u2014 and print a",
|
|
45871
|
+
" one-time sign-in link. Drop --email to copy into",
|
|
45872
|
+
" the account you already have. --json prints one",
|
|
45873
|
+
" object and nothing else"
|
|
45874
|
+
]
|
|
45875
|
+
},
|
|
45834
45876
|
{
|
|
45835
45877
|
verbs: ["org"],
|
|
45836
45878
|
help: [
|
|
@@ -45859,7 +45901,9 @@ var COMMANDS = [
|
|
|
45859
45901
|
{
|
|
45860
45902
|
verbs: ["starter"],
|
|
45861
45903
|
help: [
|
|
45862
|
-
" lotics starter list Starters you can copy into this workspace",
|
|
45904
|
+
" lotics starter list Starters you can copy into this workspace. Works with",
|
|
45905
|
+
" NO account \u2014 it then lists the published shelf, so you",
|
|
45906
|
+
" can decide whether to copy one or build before signing up",
|
|
45863
45907
|
" lotics starter show <starter_id> What one carries: tables, docs, templates, sample data",
|
|
45864
45908
|
" lotics starter init <starter_id> [path]",
|
|
45865
45909
|
" Copy it in \u2014 schema, templates, knowledge docs,",
|
|
@@ -46046,7 +46090,7 @@ function matchesKnownFlag(known, arg) {
|
|
|
46046
46090
|
|
|
46047
46091
|
// src/report_command.ts
|
|
46048
46092
|
import fs6 from "node:fs";
|
|
46049
|
-
import
|
|
46093
|
+
import path6 from "node:path";
|
|
46050
46094
|
var LIMITS = { goal: 2e3, expected: 2e3, actual: 4e3, tried: 4e3, wanted: 2e3 };
|
|
46051
46095
|
var REPORT_USAGE = `Usage: lotics report '<json>' lotics report @report.json \u2026 | lotics report -
|
|
46052
46096
|
|
|
@@ -46107,9 +46151,9 @@ function parseReport(raw) {
|
|
|
46107
46151
|
}
|
|
46108
46152
|
function appIdOf(projectDir) {
|
|
46109
46153
|
try {
|
|
46110
|
-
const raw = fs6.readFileSync(
|
|
46111
|
-
const
|
|
46112
|
-
const appId =
|
|
46154
|
+
const raw = fs6.readFileSync(path6.join(projectDir, "package.json"), "utf-8");
|
|
46155
|
+
const pkg = JSON.parse(raw);
|
|
46156
|
+
const appId = pkg.lotics?.app_id;
|
|
46113
46157
|
return typeof appId === "string" && appId !== "" ? appId : void 0;
|
|
46114
46158
|
} catch {
|
|
46115
46159
|
return void 0;
|
|
@@ -46147,7 +46191,7 @@ async function reportCommand(client, options) {
|
|
|
46147
46191
|
|
|
46148
46192
|
// src/app_commands.ts
|
|
46149
46193
|
import fs8 from "node:fs";
|
|
46150
|
-
import
|
|
46194
|
+
import path9 from "node:path";
|
|
46151
46195
|
import { spawn as spawn2 } from "node:child_process";
|
|
46152
46196
|
import { createHash as createHash3 } from "node:crypto";
|
|
46153
46197
|
import { tmpdir } from "node:os";
|
|
@@ -46914,7 +46958,7 @@ function escapeHtml(s) {
|
|
|
46914
46958
|
import http from "node:http";
|
|
46915
46959
|
import net from "node:net";
|
|
46916
46960
|
import { existsSync } from "node:fs";
|
|
46917
|
-
import
|
|
46961
|
+
import path7 from "node:path";
|
|
46918
46962
|
import { spawn } from "node:child_process";
|
|
46919
46963
|
|
|
46920
46964
|
// src/child_env.ts
|
|
@@ -47498,6 +47542,9 @@ var STOP_DEADLINE_MS = 2e3;
|
|
|
47498
47542
|
function serializeRpcResult(result) {
|
|
47499
47543
|
return JSON.stringify(result ?? null);
|
|
47500
47544
|
}
|
|
47545
|
+
function nodeForChildProcess() {
|
|
47546
|
+
return process.versions.bun === void 0 ? process.execPath : "node";
|
|
47547
|
+
}
|
|
47501
47548
|
async function startDevServer(args) {
|
|
47502
47549
|
const wrapperPort = await pickPort(args.port ?? DEFAULT_PORT);
|
|
47503
47550
|
const vitePort = await pickPort(args.vitePort ?? DEFAULT_VITE_PORT, wrapperPort);
|
|
@@ -47509,14 +47556,14 @@ async function startDevServer(args) {
|
|
|
47509
47556
|
vite_url: viteUrl,
|
|
47510
47557
|
api_url: args.api_url
|
|
47511
47558
|
});
|
|
47512
|
-
const viteEntry =
|
|
47559
|
+
const viteEntry = path7.join(args.projectDir, "node_modules", "vite", "bin", "vite.js");
|
|
47513
47560
|
if (!existsSync(viteEntry)) {
|
|
47514
47561
|
throw new Error(
|
|
47515
47562
|
`Vite is not installed in ${args.projectDir} \u2014 run \`npm install\` there first.`
|
|
47516
47563
|
);
|
|
47517
47564
|
}
|
|
47518
47565
|
const viteChild = spawn(
|
|
47519
|
-
|
|
47566
|
+
nodeForChildProcess(),
|
|
47520
47567
|
[viteEntry, "--port", String(vitePort), "--strictPort"],
|
|
47521
47568
|
{
|
|
47522
47569
|
cwd: args.projectDir,
|
|
@@ -47871,6 +47918,36 @@ function openBrowser(url2) {
|
|
|
47871
47918
|
child.unref();
|
|
47872
47919
|
}
|
|
47873
47920
|
|
|
47921
|
+
// src/output.ts
|
|
47922
|
+
var machineMode = false;
|
|
47923
|
+
var collectedWarnings = [];
|
|
47924
|
+
function setMachineOutput(on) {
|
|
47925
|
+
machineMode = on;
|
|
47926
|
+
}
|
|
47927
|
+
function isMachineOutput() {
|
|
47928
|
+
return machineMode;
|
|
47929
|
+
}
|
|
47930
|
+
function note(text) {
|
|
47931
|
+
if (machineMode) return;
|
|
47932
|
+
console.error(text);
|
|
47933
|
+
}
|
|
47934
|
+
function warn(text) {
|
|
47935
|
+
if (machineMode) {
|
|
47936
|
+
collectedWarnings.push(text);
|
|
47937
|
+
return;
|
|
47938
|
+
}
|
|
47939
|
+
console.error(text);
|
|
47940
|
+
}
|
|
47941
|
+
function emitJson(value2) {
|
|
47942
|
+
const payload = collectedWarnings.length > 0 ? { ...value2, warnings: [...collectedWarnings] } : value2;
|
|
47943
|
+
collectedWarnings.length = 0;
|
|
47944
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
47945
|
+
}
|
|
47946
|
+
function flushPendingWarnings() {
|
|
47947
|
+
for (const text of collectedWarnings) console.error(text);
|
|
47948
|
+
collectedWarnings.length = 0;
|
|
47949
|
+
}
|
|
47950
|
+
|
|
47874
47951
|
// ../shared/src/app_dts.ts
|
|
47875
47952
|
var IDENTIFIER_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
47876
47953
|
function isValidIdentifier(name2) {
|
|
@@ -48437,7 +48514,7 @@ export type AppOptions = typeof OPT;
|
|
|
48437
48514
|
|
|
48438
48515
|
// src/app_workflow_check.ts
|
|
48439
48516
|
import fs7 from "node:fs";
|
|
48440
|
-
import
|
|
48517
|
+
import path8 from "node:path";
|
|
48441
48518
|
import { createRequire } from "node:module";
|
|
48442
48519
|
|
|
48443
48520
|
// ../shared/src/parse_workflow_js.ts
|
|
@@ -49209,10 +49286,10 @@ function mergeDefs(...defs) {
|
|
|
49209
49286
|
function cloneDef(schema) {
|
|
49210
49287
|
return mergeDefs(schema._zod.def);
|
|
49211
49288
|
}
|
|
49212
|
-
function getElementAtPath(obj,
|
|
49213
|
-
if (!
|
|
49289
|
+
function getElementAtPath(obj, path13) {
|
|
49290
|
+
if (!path13)
|
|
49214
49291
|
return obj;
|
|
49215
|
-
return
|
|
49292
|
+
return path13.reduce((acc, key) => acc?.[key], obj);
|
|
49216
49293
|
}
|
|
49217
49294
|
function promiseAllObject(promisesObj) {
|
|
49218
49295
|
const keys3 = Object.keys(promisesObj);
|
|
@@ -49621,11 +49698,11 @@ function explicitlyAborted(x2, startIndex = 0) {
|
|
|
49621
49698
|
}
|
|
49622
49699
|
return false;
|
|
49623
49700
|
}
|
|
49624
|
-
function prefixIssues(
|
|
49701
|
+
function prefixIssues(path13, issues) {
|
|
49625
49702
|
return issues.map((iss) => {
|
|
49626
49703
|
var _a4;
|
|
49627
49704
|
(_a4 = iss).path ?? (_a4.path = []);
|
|
49628
|
-
iss.path.unshift(
|
|
49705
|
+
iss.path.unshift(path13);
|
|
49629
49706
|
return iss;
|
|
49630
49707
|
});
|
|
49631
49708
|
}
|
|
@@ -49772,16 +49849,16 @@ function flattenError(error52, mapper = (issue2) => issue2.message) {
|
|
|
49772
49849
|
}
|
|
49773
49850
|
function formatError(error52, mapper = (issue2) => issue2.message) {
|
|
49774
49851
|
const fieldErrors = { _errors: [] };
|
|
49775
|
-
const processError = (error53,
|
|
49852
|
+
const processError = (error53, path13 = []) => {
|
|
49776
49853
|
for (const issue2 of error53.issues) {
|
|
49777
49854
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
49778
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
49855
|
+
issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
|
|
49779
49856
|
} else if (issue2.code === "invalid_key") {
|
|
49780
|
-
processError({ issues: issue2.issues }, [...
|
|
49857
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
49781
49858
|
} else if (issue2.code === "invalid_element") {
|
|
49782
|
-
processError({ issues: issue2.issues }, [...
|
|
49859
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
49783
49860
|
} else {
|
|
49784
|
-
const fullpath = [...
|
|
49861
|
+
const fullpath = [...path13, ...issue2.path];
|
|
49785
49862
|
if (fullpath.length === 0) {
|
|
49786
49863
|
fieldErrors._errors.push(mapper(issue2));
|
|
49787
49864
|
} else {
|
|
@@ -49808,17 +49885,17 @@ function formatError(error52, mapper = (issue2) => issue2.message) {
|
|
|
49808
49885
|
}
|
|
49809
49886
|
function treeifyError(error52, mapper = (issue2) => issue2.message) {
|
|
49810
49887
|
const result = { errors: [] };
|
|
49811
|
-
const processError = (error53,
|
|
49888
|
+
const processError = (error53, path13 = []) => {
|
|
49812
49889
|
var _a4, _b2;
|
|
49813
49890
|
for (const issue2 of error53.issues) {
|
|
49814
49891
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
49815
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
49892
|
+
issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
|
|
49816
49893
|
} else if (issue2.code === "invalid_key") {
|
|
49817
|
-
processError({ issues: issue2.issues }, [...
|
|
49894
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
49818
49895
|
} else if (issue2.code === "invalid_element") {
|
|
49819
|
-
processError({ issues: issue2.issues }, [...
|
|
49896
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
49820
49897
|
} else {
|
|
49821
|
-
const fullpath = [...
|
|
49898
|
+
const fullpath = [...path13, ...issue2.path];
|
|
49822
49899
|
if (fullpath.length === 0) {
|
|
49823
49900
|
result.errors.push(mapper(issue2));
|
|
49824
49901
|
continue;
|
|
@@ -49850,8 +49927,8 @@ function treeifyError(error52, mapper = (issue2) => issue2.message) {
|
|
|
49850
49927
|
}
|
|
49851
49928
|
function toDotPath(_path) {
|
|
49852
49929
|
const segs = [];
|
|
49853
|
-
const
|
|
49854
|
-
for (const seg of
|
|
49930
|
+
const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
49931
|
+
for (const seg of path13) {
|
|
49855
49932
|
if (typeof seg === "number")
|
|
49856
49933
|
segs.push(`[${seg}]`);
|
|
49857
49934
|
else if (typeof seg === "symbol")
|
|
@@ -62543,13 +62620,13 @@ function resolveRef(ref2, ctx) {
|
|
|
62543
62620
|
if (!ref2.startsWith("#")) {
|
|
62544
62621
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
62545
62622
|
}
|
|
62546
|
-
const
|
|
62547
|
-
if (
|
|
62623
|
+
const path13 = ref2.slice(1).split("/").filter(Boolean);
|
|
62624
|
+
if (path13.length === 0) {
|
|
62548
62625
|
return ctx.rootSchema;
|
|
62549
62626
|
}
|
|
62550
62627
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
62551
|
-
if (
|
|
62552
|
-
const key =
|
|
62628
|
+
if (path13[0] === defsKey) {
|
|
62629
|
+
const key = path13[1];
|
|
62553
62630
|
if (!key || !ctx.defs[key]) {
|
|
62554
62631
|
throw new Error(`Reference not found: ${ref2}`);
|
|
62555
62632
|
}
|
|
@@ -67305,9 +67382,9 @@ __export(expression_object_exports, {
|
|
|
67305
67382
|
pick: () => pick3,
|
|
67306
67383
|
values: () => values2
|
|
67307
67384
|
});
|
|
67308
|
-
function getNestedValue(obj,
|
|
67385
|
+
function getNestedValue(obj, path13) {
|
|
67309
67386
|
if (obj == null) return void 0;
|
|
67310
|
-
const parts =
|
|
67387
|
+
const parts = path13.split(".");
|
|
67311
67388
|
let value2 = obj;
|
|
67312
67389
|
for (const part of parts) {
|
|
67313
67390
|
if (value2 == null) return void 0;
|
|
@@ -67346,11 +67423,11 @@ function entries(obj) {
|
|
|
67346
67423
|
}
|
|
67347
67424
|
return Object.entries(obj);
|
|
67348
67425
|
}
|
|
67349
|
-
function get(obj,
|
|
67350
|
-
if (typeof
|
|
67426
|
+
function get(obj, path13, defaultValue) {
|
|
67427
|
+
if (typeof path13 !== "string") {
|
|
67351
67428
|
throw new Error("get: path must be a string");
|
|
67352
67429
|
}
|
|
67353
|
-
const value2 = getNestedValue(obj,
|
|
67430
|
+
const value2 = getNestedValue(obj, path13);
|
|
67354
67431
|
return value2 !== void 0 ? value2 : defaultValue;
|
|
67355
67432
|
}
|
|
67356
67433
|
function pick3(obj, fields) {
|
|
@@ -69246,17 +69323,17 @@ function readFromChanges(chain2) {
|
|
|
69246
69323
|
if (first3.kind === "bracket-number" || first3.kind === "bracket-expr") {
|
|
69247
69324
|
fail(first3.node, "changes is keyed by field name, not numeric index.");
|
|
69248
69325
|
}
|
|
69249
|
-
const
|
|
69326
|
+
const path13 = [{ at: "key", key: first3.key }];
|
|
69250
69327
|
for (const seg of segments.slice(1)) {
|
|
69251
69328
|
if (seg.kind === "bracket-number") {
|
|
69252
|
-
|
|
69329
|
+
path13.push({ at: "index", index: seg.index });
|
|
69253
69330
|
} else if (seg.kind === "bracket-expr") {
|
|
69254
|
-
|
|
69331
|
+
path13.push({ at: "index", index: seg.expr });
|
|
69255
69332
|
} else {
|
|
69256
|
-
|
|
69333
|
+
path13.push({ at: "key", key: seg.key });
|
|
69257
69334
|
}
|
|
69258
69335
|
}
|
|
69259
|
-
return { kind: "read", source: { from: "trigger_changes" }, path:
|
|
69336
|
+
return { kind: "read", source: { from: "trigger_changes" }, path: path13 };
|
|
69260
69337
|
});
|
|
69261
69338
|
}
|
|
69262
69339
|
var TRIGGER_RECORD_VIEWS = /* @__PURE__ */ new Map([
|
|
@@ -69274,17 +69351,17 @@ function readFromTrigger(chain2) {
|
|
|
69274
69351
|
return view === "trigger_changes" ? readFromChanges(lowered) : readFromRecord(view, lowered);
|
|
69275
69352
|
}
|
|
69276
69353
|
return wrapOptionalGuards(chain2, (segments) => {
|
|
69277
|
-
const
|
|
69354
|
+
const path13 = [];
|
|
69278
69355
|
for (const seg of segments) {
|
|
69279
69356
|
if (seg.kind === "bracket-number") {
|
|
69280
|
-
|
|
69357
|
+
path13.push({ at: "index", index: seg.index });
|
|
69281
69358
|
} else if (seg.kind === "bracket-expr") {
|
|
69282
|
-
|
|
69359
|
+
path13.push({ at: "index", index: seg.expr });
|
|
69283
69360
|
} else {
|
|
69284
|
-
|
|
69361
|
+
path13.push({ at: "key", key: seg.key });
|
|
69285
69362
|
}
|
|
69286
69363
|
}
|
|
69287
|
-
return { kind: "read", source: { from: "trigger" }, path:
|
|
69364
|
+
return { kind: "read", source: { from: "trigger" }, path: path13 };
|
|
69288
69365
|
});
|
|
69289
69366
|
}
|
|
69290
69367
|
function readFromRuntime(chain2) {
|
|
@@ -69306,17 +69383,17 @@ function readFromRuntime(chain2) {
|
|
|
69306
69383
|
const parked = PARKED_RUNTIME_KEYS.get(key);
|
|
69307
69384
|
if (parked) fail(first3.node, parked, parkedRuntimeKeyConstruct(key));
|
|
69308
69385
|
const source = { from: "runtime", key };
|
|
69309
|
-
const
|
|
69386
|
+
const path13 = [];
|
|
69310
69387
|
for (const seg of segments.slice(1)) {
|
|
69311
69388
|
if (seg.kind === "bracket-number") {
|
|
69312
|
-
|
|
69389
|
+
path13.push({ at: "index", index: seg.index });
|
|
69313
69390
|
} else if (seg.kind === "bracket-expr") {
|
|
69314
|
-
|
|
69391
|
+
path13.push({ at: "index", index: seg.expr });
|
|
69315
69392
|
} else {
|
|
69316
|
-
|
|
69393
|
+
path13.push({ at: "key", key: seg.key });
|
|
69317
69394
|
}
|
|
69318
69395
|
}
|
|
69319
|
-
return { kind: "read", source, path:
|
|
69396
|
+
return { kind: "read", source, path: path13 };
|
|
69320
69397
|
});
|
|
69321
69398
|
}
|
|
69322
69399
|
function readFromForeachItem(name2, chain2) {
|
|
@@ -69355,17 +69432,17 @@ function readFromLexical(name2, chain2) {
|
|
|
69355
69432
|
}
|
|
69356
69433
|
function readFromStepOutput(stepId, chain2) {
|
|
69357
69434
|
return wrapOptionalGuards(chain2, (segments) => {
|
|
69358
|
-
const
|
|
69435
|
+
const path13 = [];
|
|
69359
69436
|
for (const seg of segments) {
|
|
69360
69437
|
if (seg.kind === "bracket-number") {
|
|
69361
|
-
|
|
69438
|
+
path13.push({ at: "index", index: seg.index });
|
|
69362
69439
|
} else if (seg.kind === "bracket-expr") {
|
|
69363
|
-
|
|
69440
|
+
path13.push({ at: "index", index: seg.expr });
|
|
69364
69441
|
} else {
|
|
69365
|
-
|
|
69442
|
+
path13.push({ at: "key", key: seg.key });
|
|
69366
69443
|
}
|
|
69367
69444
|
}
|
|
69368
|
-
return { kind: "read", source: { from: "step_output", step_id: stepId }, path:
|
|
69445
|
+
return { kind: "read", source: { from: "step_output", step_id: stepId }, path: path13 };
|
|
69369
69446
|
});
|
|
69370
69447
|
}
|
|
69371
69448
|
function classifyRecordPath(segs) {
|
|
@@ -71038,7 +71115,7 @@ function subsetIssues(bodySource, offset) {
|
|
|
71038
71115
|
];
|
|
71039
71116
|
}
|
|
71040
71117
|
async function loadProjectTypescript(projectDir) {
|
|
71041
|
-
const requireFromProject = createRequire(
|
|
71118
|
+
const requireFromProject = createRequire(path8.join(projectDir, "package.json"));
|
|
71042
71119
|
let resolved;
|
|
71043
71120
|
try {
|
|
71044
71121
|
resolved = requireFromProject.resolve("typescript");
|
|
@@ -71051,9 +71128,9 @@ async function loadProjectTypescript(projectDir) {
|
|
|
71051
71128
|
return mod2.default ?? mod2;
|
|
71052
71129
|
}
|
|
71053
71130
|
function pathToImportUrl(p) {
|
|
71054
|
-
const resolved =
|
|
71131
|
+
const resolved = path8.resolve(p);
|
|
71055
71132
|
const prefixed = resolved.startsWith("/") ? resolved : `/${resolved}`;
|
|
71056
|
-
return `file://${prefixed.split(
|
|
71133
|
+
return `file://${prefixed.split(path8.sep).join("/")}`;
|
|
71057
71134
|
}
|
|
71058
71135
|
function checkOneWorkflowBody(tsApi, input) {
|
|
71059
71136
|
const wrapped = fs7.readFileSync(input.bodyPath, "utf-8");
|
|
@@ -71103,7 +71180,7 @@ function checkOneWorkflowBody(tsApi, input) {
|
|
|
71103
71180
|
}
|
|
71104
71181
|
function createCheckedSourceHost(tsApi, options, bodyPath, bodyText) {
|
|
71105
71182
|
const base = tsApi.createCompilerHost(options, false);
|
|
71106
|
-
const key = (fileName) => base.getCanonicalFileName(
|
|
71183
|
+
const key = (fileName) => base.getCanonicalFileName(path8.resolve(fileName).replace(/\\/g, "/"));
|
|
71107
71184
|
const bodyKey = key(bodyPath);
|
|
71108
71185
|
return {
|
|
71109
71186
|
...base,
|
|
@@ -71229,10 +71306,10 @@ function syncedEntry(entry) {
|
|
|
71229
71306
|
}
|
|
71230
71307
|
function readSynced(projectDir) {
|
|
71231
71308
|
try {
|
|
71232
|
-
const
|
|
71233
|
-
fs8.readFileSync(
|
|
71309
|
+
const pkg = JSON.parse(
|
|
71310
|
+
fs8.readFileSync(path9.join(projectDir, "package.json"), "utf-8")
|
|
71234
71311
|
);
|
|
71235
|
-
const raw =
|
|
71312
|
+
const raw = pkg.lotics?.synced ?? {};
|
|
71236
71313
|
return {
|
|
71237
71314
|
workflows: normalizeSyncedMap(raw.workflows),
|
|
71238
71315
|
agents: normalizeSyncedMap(raw.agents),
|
|
@@ -71251,19 +71328,19 @@ function normalizeSyncedMap(map3) {
|
|
|
71251
71328
|
);
|
|
71252
71329
|
}
|
|
71253
71330
|
function writeSynced(projectDir, kind, alias, entry) {
|
|
71254
|
-
const
|
|
71255
|
-
const
|
|
71256
|
-
if (!
|
|
71257
|
-
|
|
71258
|
-
|
|
71259
|
-
fs8.writeFileSync(
|
|
71331
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
71332
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
71333
|
+
if (!pkg.lotics) return;
|
|
71334
|
+
pkg.lotics.synced ??= {};
|
|
71335
|
+
pkg.lotics.synced[kind] = { ...pkg.lotics.synced[kind], [alias]: entry };
|
|
71336
|
+
fs8.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
71260
71337
|
}
|
|
71261
71338
|
function readManifestEntry(projectDir, kind, alias) {
|
|
71262
|
-
const
|
|
71263
|
-
if (!
|
|
71339
|
+
const pkg = readManifest(projectDir);
|
|
71340
|
+
if (!pkg.lotics) return { found: false };
|
|
71264
71341
|
const entry = { found: true };
|
|
71265
71342
|
let found = false;
|
|
71266
|
-
const declarations =
|
|
71343
|
+
const declarations = pkg.lotics[kind];
|
|
71267
71344
|
if (declarations && typeof declarations === "object" && !Array.isArray(declarations)) {
|
|
71268
71345
|
const map3 = declarations;
|
|
71269
71346
|
if (alias in map3) {
|
|
@@ -71271,7 +71348,7 @@ function readManifestEntry(projectDir, kind, alias) {
|
|
|
71271
71348
|
found = true;
|
|
71272
71349
|
}
|
|
71273
71350
|
}
|
|
71274
|
-
const baselines =
|
|
71351
|
+
const baselines = pkg.lotics.synced?.[kind];
|
|
71275
71352
|
if (baselines && alias in baselines) {
|
|
71276
71353
|
entry.synced = baselines[alias];
|
|
71277
71354
|
found = true;
|
|
@@ -71279,31 +71356,31 @@ function readManifestEntry(projectDir, kind, alias) {
|
|
|
71279
71356
|
return found ? entry : { found: false };
|
|
71280
71357
|
}
|
|
71281
71358
|
function readManifest(projectDir) {
|
|
71282
|
-
const
|
|
71283
|
-
return JSON.parse(fs8.readFileSync(
|
|
71359
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
71360
|
+
return JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
71284
71361
|
}
|
|
71285
71362
|
function removeFromManifest(projectDir, kind, alias) {
|
|
71286
|
-
const
|
|
71287
|
-
const
|
|
71288
|
-
if (!
|
|
71289
|
-
const declarations =
|
|
71363
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
71364
|
+
const pkg = readManifest(projectDir);
|
|
71365
|
+
if (!pkg.lotics) return;
|
|
71366
|
+
const declarations = pkg.lotics[kind];
|
|
71290
71367
|
if (declarations && typeof declarations === "object" && !Array.isArray(declarations)) {
|
|
71291
71368
|
delete declarations[alias];
|
|
71292
71369
|
}
|
|
71293
|
-
const baselines =
|
|
71370
|
+
const baselines = pkg.lotics.synced?.[kind];
|
|
71294
71371
|
if (baselines) delete baselines[alias];
|
|
71295
|
-
fs8.writeFileSync(
|
|
71372
|
+
fs8.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
71296
71373
|
}
|
|
71297
71374
|
function parkPrunedDeclaration(projectDir, kind, alias, removed) {
|
|
71298
|
-
const dir =
|
|
71375
|
+
const dir = path9.join(projectDir, ".lotics", "pruned", kind);
|
|
71299
71376
|
fs8.mkdirSync(dir, { recursive: true });
|
|
71300
|
-
const file2 =
|
|
71377
|
+
const file2 = path9.join(dir, `${alias}.json`);
|
|
71301
71378
|
fs8.writeFileSync(file2, JSON.stringify(removed, null, 2) + "\n");
|
|
71302
|
-
return
|
|
71379
|
+
return path9.relative(projectDir, file2);
|
|
71303
71380
|
}
|
|
71304
|
-
var WORKFLOWS_DIR =
|
|
71305
|
-
var WORKFLOW_GLOBALS_DIR =
|
|
71306
|
-
var AGENTS_DIR =
|
|
71381
|
+
var WORKFLOWS_DIR = path9.join("src", "workflows");
|
|
71382
|
+
var WORKFLOW_GLOBALS_DIR = path9.join(".lotics", "workflows");
|
|
71383
|
+
var AGENTS_DIR = path9.join("src", "agents");
|
|
71307
71384
|
var WORKFLOW_TSCONFIG_EXCLUDES = ["src/workflows", ".lotics/workflows"];
|
|
71308
71385
|
var LOTICS_INCLUDE_GLOB = ".lotics/**/*";
|
|
71309
71386
|
var STALE_LOTICS_INCLUDES = /* @__PURE__ */ new Set([".lotics", "./.lotics", ".lotics/"]);
|
|
@@ -71314,7 +71391,7 @@ function isMissingWorkflowBodyError(error52) {
|
|
|
71314
71391
|
return /has no step source|cannot be rendered|unsupported step/i.test(error52);
|
|
71315
71392
|
}
|
|
71316
71393
|
function workflowFileHeader(alias) {
|
|
71317
|
-
const refPath =
|
|
71394
|
+
const refPath = path9.join("..", "..", WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`).split(path9.sep).join("/");
|
|
71318
71395
|
return (
|
|
71319
71396
|
// The scaffold ships oxlint, whose `triple-slash-reference` rule flags the
|
|
71320
71397
|
// line below — so every pulled body arrived with a warning its author could
|
|
@@ -71337,27 +71414,27 @@ export {};
|
|
|
71337
71414
|
);
|
|
71338
71415
|
}
|
|
71339
71416
|
function workflowFilePath(projectDir, alias) {
|
|
71340
|
-
return
|
|
71417
|
+
return path9.join(projectDir, WORKFLOWS_DIR, `${alias}.ts`);
|
|
71341
71418
|
}
|
|
71342
71419
|
var GLOBALS_SUFFIX = ".globals.d.ts";
|
|
71343
71420
|
function workflowGlobalsPath(projectDir, alias) {
|
|
71344
|
-
return
|
|
71421
|
+
return path9.join(projectDir, WORKFLOW_GLOBALS_DIR, `${alias}${GLOBALS_SUFFIX}`);
|
|
71345
71422
|
}
|
|
71346
71423
|
function pruneOrphanWorkflowGlobals(projectDir, declared) {
|
|
71347
|
-
const dir =
|
|
71424
|
+
const dir = path9.join(projectDir, WORKFLOW_GLOBALS_DIR);
|
|
71348
71425
|
if (!fs8.existsSync(dir)) return [];
|
|
71349
71426
|
const removed = [];
|
|
71350
71427
|
for (const entry of fs8.readdirSync(dir)) {
|
|
71351
71428
|
if (!entry.endsWith(GLOBALS_SUFFIX)) continue;
|
|
71352
71429
|
const alias = entry.slice(0, -GLOBALS_SUFFIX.length);
|
|
71353
71430
|
if (declared.has(alias)) continue;
|
|
71354
|
-
fs8.unlinkSync(
|
|
71431
|
+
fs8.unlinkSync(path9.join(dir, entry));
|
|
71355
71432
|
removed.push(alias);
|
|
71356
71433
|
}
|
|
71357
71434
|
return removed.sort();
|
|
71358
71435
|
}
|
|
71359
71436
|
function orphanWorkflowBodies(projectDir, declared) {
|
|
71360
|
-
const dir =
|
|
71437
|
+
const dir = path9.join(projectDir, WORKFLOWS_DIR);
|
|
71361
71438
|
if (!fs8.existsSync(dir)) return [];
|
|
71362
71439
|
return fs8.readdirSync(dir).filter((e) => e.endsWith(".ts") && !e.endsWith(".d.ts") && !e.endsWith(".test.ts")).map((e) => e.slice(0, -".ts".length)).filter((alias) => !declared.has(alias)).sort();
|
|
71363
71440
|
}
|
|
@@ -71395,7 +71472,7 @@ function staleWorkflowGlobals(projectDir, workflows) {
|
|
|
71395
71472
|
return out;
|
|
71396
71473
|
}
|
|
71397
71474
|
function writeWorkflowGlobals(projectDir, alias, dts, declaration) {
|
|
71398
|
-
const dir =
|
|
71475
|
+
const dir = path9.join(projectDir, WORKFLOW_GLOBALS_DIR);
|
|
71399
71476
|
fs8.mkdirSync(dir, { recursive: true });
|
|
71400
71477
|
const file2 = workflowGlobalsPath(projectDir, alias);
|
|
71401
71478
|
const stamp = `${GLOBALS_STAMP_PREFIX}${workflowDeclarationStamp(declaration)}`;
|
|
@@ -71408,7 +71485,7 @@ function normalizeWorkflowBody(source) {
|
|
|
71408
71485
|
return source.replace(/\s+$/, "");
|
|
71409
71486
|
}
|
|
71410
71487
|
function writeWorkflowFile(projectDir, alias, source, envelope2 = { prefix: WORKFLOW_ENVELOPE_PREFIX, suffix: WORKFLOW_ENVELOPE_SUFFIX }) {
|
|
71411
|
-
const dir =
|
|
71488
|
+
const dir = path9.join(projectDir, WORKFLOWS_DIR);
|
|
71412
71489
|
fs8.mkdirSync(dir, { recursive: true });
|
|
71413
71490
|
const file2 = workflowFilePath(projectDir, alias);
|
|
71414
71491
|
const body = normalizeWorkflowBody(source);
|
|
@@ -71418,14 +71495,14 @@ ${envelope2.prefix}${body}${envelope2.suffix}
|
|
|
71418
71495
|
return file2;
|
|
71419
71496
|
}
|
|
71420
71497
|
function agentFilePath2(projectDir, alias) {
|
|
71421
|
-
return
|
|
71498
|
+
return path9.join(projectDir, ...agentFilePath(alias).split("/"));
|
|
71422
71499
|
}
|
|
71423
71500
|
var CLI_AGENT_NOTES = [
|
|
71424
71501
|
"Pulled from the LIVE app row; edit here, then: lotics app agent set <alias>",
|
|
71425
71502
|
"The typed fields (inputs/outputs/tool_names/model_tier) live in package.json#lotics.agents"
|
|
71426
71503
|
];
|
|
71427
71504
|
function writeAgentFile(projectDir, alias, instructions) {
|
|
71428
|
-
fs8.mkdirSync(
|
|
71505
|
+
fs8.mkdirSync(path9.join(projectDir, AGENTS_DIR), { recursive: true });
|
|
71429
71506
|
const file2 = agentFilePath2(projectDir, alias);
|
|
71430
71507
|
fs8.writeFileSync(
|
|
71431
71508
|
file2,
|
|
@@ -71451,15 +71528,15 @@ function writeAgentFiles(projectDir, agents, opts) {
|
|
|
71451
71528
|
return written;
|
|
71452
71529
|
}
|
|
71453
71530
|
function parkLiveAgentProse(projectDir, alias, instructions) {
|
|
71454
|
-
const dir =
|
|
71455
|
-
const file2 =
|
|
71531
|
+
const dir = path9.join(projectDir, ".lotics", "agents");
|
|
71532
|
+
const file2 = path9.join(dir, `${alias}.live.md`);
|
|
71456
71533
|
try {
|
|
71457
71534
|
fs8.mkdirSync(dir, { recursive: true });
|
|
71458
71535
|
fs8.writeFileSync(file2, normalizeAgentInstructions(instructions) + "\n");
|
|
71459
|
-
return
|
|
71536
|
+
return path9.relative(projectDir, file2);
|
|
71460
71537
|
} catch (err2) {
|
|
71461
71538
|
console.error(
|
|
71462
|
-
`\u26A0 Could not write the live prose for ${alias} to ${
|
|
71539
|
+
`\u26A0 Could not write the live prose for ${alias} to ${path9.relative(projectDir, file2)}: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
71463
71540
|
);
|
|
71464
71541
|
return null;
|
|
71465
71542
|
}
|
|
@@ -71475,15 +71552,15 @@ function reportUnseenLive(kind, unseen, appId) {
|
|
|
71475
71552
|
);
|
|
71476
71553
|
}
|
|
71477
71554
|
function parkLiveWorkflowBody(projectDir, alias, source) {
|
|
71478
|
-
const dir =
|
|
71479
|
-
const file2 =
|
|
71555
|
+
const dir = path9.join(projectDir, WORKFLOW_GLOBALS_DIR);
|
|
71556
|
+
const file2 = path9.join(dir, `${alias}.live.ts`);
|
|
71480
71557
|
try {
|
|
71481
71558
|
fs8.mkdirSync(dir, { recursive: true });
|
|
71482
71559
|
fs8.writeFileSync(file2, normalizeWorkflowBody(source) + "\n");
|
|
71483
|
-
return
|
|
71560
|
+
return path9.relative(projectDir, file2);
|
|
71484
71561
|
} catch (err2) {
|
|
71485
71562
|
console.error(
|
|
71486
|
-
`\u26A0 Could not write the live body for ${alias} to ${
|
|
71563
|
+
`\u26A0 Could not write the live body for ${alias} to ${path9.relative(projectDir, file2)}: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
71487
71564
|
);
|
|
71488
71565
|
return null;
|
|
71489
71566
|
}
|
|
@@ -71573,12 +71650,12 @@ async function writeWorkflowFiles(client, projectDir, app_id, appName, workflows
|
|
|
71573
71650
|
return { written, kept, unseenLive };
|
|
71574
71651
|
}
|
|
71575
71652
|
function writeWorkflowDescription(projectDir, alias, description) {
|
|
71576
|
-
const
|
|
71577
|
-
const
|
|
71578
|
-
const declaration =
|
|
71653
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
71654
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
71655
|
+
const declaration = pkg.lotics?.workflows?.[alias];
|
|
71579
71656
|
if (!declaration) return;
|
|
71580
71657
|
declaration.description = description;
|
|
71581
|
-
fs8.writeFileSync(
|
|
71658
|
+
fs8.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
71582
71659
|
}
|
|
71583
71660
|
async function fetchWorkflowGlobals(client, projectDir, app_id, alias, declaration) {
|
|
71584
71661
|
try {
|
|
@@ -71616,63 +71693,128 @@ function runTar(args, cwd) {
|
|
|
71616
71693
|
});
|
|
71617
71694
|
});
|
|
71618
71695
|
}
|
|
71696
|
+
function npmIsInstalled() {
|
|
71697
|
+
return new Promise((resolve2) => {
|
|
71698
|
+
const probe = spawn2("npm", ["--version"], {
|
|
71699
|
+
shell: process.platform === "win32",
|
|
71700
|
+
stdio: "ignore",
|
|
71701
|
+
env: ipv4ChildEnv(process.env)
|
|
71702
|
+
});
|
|
71703
|
+
probe.on("error", () => resolve2(false));
|
|
71704
|
+
probe.on("exit", (code) => resolve2(code === 0));
|
|
71705
|
+
});
|
|
71706
|
+
}
|
|
71619
71707
|
function runNpm(args, cwd) {
|
|
71708
|
+
const quiet = isMachineOutput();
|
|
71620
71709
|
return new Promise((resolve2, reject2) => {
|
|
71621
|
-
const proc = spawn2("npm", args, {
|
|
71622
|
-
|
|
71710
|
+
const proc = spawn2("npm", args, {
|
|
71711
|
+
cwd,
|
|
71712
|
+
// On Windows `npm` is `npm.cmd`, a batch file Node will not execute
|
|
71713
|
+
// without a shell — bare `spawn("npm")` dies at ENOENT, which took every
|
|
71714
|
+
// command that installs or builds with it. A shell is safe here because
|
|
71715
|
+
// the arguments are literals this file writes (`run build`, `ci
|
|
71716
|
+
// --ignore-scripts`); nothing a caller supplies reaches the command line.
|
|
71717
|
+
//
|
|
71718
|
+
// The alternative — run npm's own JS entry with `process.execPath`, as
|
|
71719
|
+
// `dev/server.ts` does for vite — works there because vite sits at a known
|
|
71720
|
+
// path inside the project. npm does not: nvm-windows, volta, corepack and
|
|
71721
|
+
// the installer each put it somewhere different, and letting the platform
|
|
71722
|
+
// resolve its own shim is the one approach that finds all of them.
|
|
71723
|
+
shell: process.platform === "win32",
|
|
71724
|
+
stdio: quiet ? ["ignore", "pipe", "pipe"] : "inherit",
|
|
71725
|
+
env: ipv4ChildEnv(process.env)
|
|
71726
|
+
});
|
|
71727
|
+
let captured = "";
|
|
71728
|
+
if (quiet) {
|
|
71729
|
+
const collect = (chunk) => {
|
|
71730
|
+
captured += chunk.toString();
|
|
71731
|
+
if (captured.length > NPM_LOG_TAIL_BYTES * 2) {
|
|
71732
|
+
captured = captured.slice(-NPM_LOG_TAIL_BYTES);
|
|
71733
|
+
}
|
|
71734
|
+
};
|
|
71735
|
+
proc.stdout?.on("data", collect);
|
|
71736
|
+
proc.stderr?.on("data", collect);
|
|
71737
|
+
}
|
|
71738
|
+
proc.on("error", (error52) => void failed(error52, null));
|
|
71623
71739
|
proc.on("exit", (code) => {
|
|
71624
|
-
if (code === 0)
|
|
71625
|
-
|
|
71740
|
+
if (code === 0) {
|
|
71741
|
+
resolve2();
|
|
71742
|
+
return;
|
|
71743
|
+
}
|
|
71744
|
+
void failed(void 0, code);
|
|
71626
71745
|
});
|
|
71746
|
+
async function failed(error52, code) {
|
|
71747
|
+
if (!await npmIsInstalled()) {
|
|
71748
|
+
reject2(
|
|
71749
|
+
new Error(
|
|
71750
|
+
"npm was not found, and building an app needs it.\n Install Node.js 18 or newer (npm comes with it), then run this again:\n https://nodejs.org/en/download\n The Lotics CLI itself needs no Node \u2014 only this build step does."
|
|
71751
|
+
)
|
|
71752
|
+
);
|
|
71753
|
+
return;
|
|
71754
|
+
}
|
|
71755
|
+
if (error52 !== void 0) {
|
|
71756
|
+
reject2(error52);
|
|
71757
|
+
return;
|
|
71758
|
+
}
|
|
71759
|
+
const tail = captured.slice(-NPM_LOG_TAIL_BYTES).trim();
|
|
71760
|
+
reject2(
|
|
71761
|
+
new Error(
|
|
71762
|
+
`npm ${args.join(" ")} exited with code ${code}` + (tail === "" ? "" : `
|
|
71763
|
+
--- npm output ---
|
|
71764
|
+
${tail}`)
|
|
71765
|
+
)
|
|
71766
|
+
);
|
|
71767
|
+
}
|
|
71627
71768
|
});
|
|
71628
71769
|
}
|
|
71770
|
+
var NPM_LOG_TAIL_BYTES = 8e3;
|
|
71629
71771
|
function npmInstallArgs(hasLockfile) {
|
|
71630
71772
|
return [hasLockfile ? "ci" : "install", "--ignore-scripts"];
|
|
71631
71773
|
}
|
|
71632
71774
|
function runNpmInstall(cwd) {
|
|
71633
|
-
const hasLockfile = fs8.existsSync(
|
|
71634
|
-
|
|
71775
|
+
const hasLockfile = fs8.existsSync(path9.join(cwd, "package-lock.json"));
|
|
71776
|
+
note(
|
|
71635
71777
|
hasLockfile ? "Installing npm dependencies (npm ci \u2014 the lockfile's exact tree, no install scripts)..." : "Installing npm dependencies (no lockfile yet \u2014 resolving ranges, no install scripts)..."
|
|
71636
71778
|
);
|
|
71637
71779
|
return runNpm(npmInstallArgs(hasLockfile), cwd);
|
|
71638
71780
|
}
|
|
71639
71781
|
function readAppWorkspaceId(projectDir) {
|
|
71640
71782
|
try {
|
|
71641
|
-
const
|
|
71642
|
-
if (!fs8.existsSync(
|
|
71643
|
-
const
|
|
71644
|
-
return
|
|
71783
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
71784
|
+
if (!fs8.existsSync(pkgPath)) return null;
|
|
71785
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
71786
|
+
return pkg.lotics?.workspace_id ?? null;
|
|
71645
71787
|
} catch {
|
|
71646
71788
|
return null;
|
|
71647
71789
|
}
|
|
71648
71790
|
}
|
|
71649
71791
|
function readAppMeta(projectDir) {
|
|
71650
|
-
const
|
|
71651
|
-
if (!fs8.existsSync(
|
|
71792
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
71793
|
+
if (!fs8.existsSync(pkgPath)) {
|
|
71652
71794
|
throw new Error(`No package.json found at ${projectDir}. Run 'lotics app create' first.`);
|
|
71653
71795
|
}
|
|
71654
|
-
const
|
|
71655
|
-
if (!
|
|
71796
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
71797
|
+
if (!pkg.lotics?.app_id || !pkg.lotics.workspace_id) {
|
|
71656
71798
|
throw new Error(
|
|
71657
71799
|
`package.json is missing the 'lotics' field with app_id and workspace_id. Was this folder created with 'lotics app create'?`
|
|
71658
71800
|
);
|
|
71659
71801
|
}
|
|
71660
|
-
noteScope({ app_id:
|
|
71802
|
+
noteScope({ app_id: pkg.lotics.app_id });
|
|
71661
71803
|
return {
|
|
71662
|
-
app_id:
|
|
71663
|
-
workspace_id:
|
|
71664
|
-
current_version_id:
|
|
71665
|
-
version_number:
|
|
71666
|
-
workflows:
|
|
71667
|
-
queries:
|
|
71668
|
-
agents:
|
|
71669
|
-
capabilities:
|
|
71804
|
+
app_id: pkg.lotics.app_id,
|
|
71805
|
+
workspace_id: pkg.lotics.workspace_id,
|
|
71806
|
+
current_version_id: pkg.lotics.current_version_id ?? null,
|
|
71807
|
+
version_number: pkg.lotics.version_number ?? null,
|
|
71808
|
+
workflows: pkg.lotics.workflows ?? {},
|
|
71809
|
+
queries: pkg.lotics.queries ?? {},
|
|
71810
|
+
agents: pkg.lotics.agents ?? {},
|
|
71811
|
+
capabilities: pkg.lotics.capabilities
|
|
71670
71812
|
};
|
|
71671
71813
|
}
|
|
71672
71814
|
function writeAppMeta(projectDir, meta3) {
|
|
71673
|
-
const
|
|
71674
|
-
const
|
|
71675
|
-
const existing =
|
|
71815
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
71816
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
71817
|
+
const existing = pkg.lotics && typeof pkg.lotics === "object" ? pkg.lotics : {};
|
|
71676
71818
|
const supplied = new Set(
|
|
71677
71819
|
Object.entries(meta3).filter(([, value2]) => value2 !== void 0).map(([key]) => key)
|
|
71678
71820
|
);
|
|
@@ -71680,20 +71822,20 @@ function writeAppMeta(projectDir, meta3) {
|
|
|
71680
71822
|
for (const [key, value2] of Object.entries(existing)) {
|
|
71681
71823
|
if (!supplied.has(key)) preserved[key] = value2;
|
|
71682
71824
|
}
|
|
71683
|
-
|
|
71684
|
-
fs8.writeFileSync(
|
|
71825
|
+
pkg.lotics = { ...meta3, ...preserved };
|
|
71826
|
+
fs8.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
71685
71827
|
}
|
|
71686
71828
|
function writeWorkflowOutputs(projectDir, alias, outputs) {
|
|
71687
|
-
const
|
|
71688
|
-
const
|
|
71689
|
-
const declaration =
|
|
71829
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
71830
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
71831
|
+
const declaration = pkg.lotics?.workflows?.[alias];
|
|
71690
71832
|
if (!declaration) {
|
|
71691
71833
|
throw new Error(
|
|
71692
71834
|
`package.json#lotics.workflows.${alias} disappeared before the derived-outputs write-back.`
|
|
71693
71835
|
);
|
|
71694
71836
|
}
|
|
71695
71837
|
declaration.outputs = outputs;
|
|
71696
|
-
fs8.writeFileSync(
|
|
71838
|
+
fs8.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
71697
71839
|
}
|
|
71698
71840
|
function workflowBodyDrift(projectDir, workflows, synced = {}) {
|
|
71699
71841
|
const drifted = [];
|
|
@@ -71709,7 +71851,7 @@ function workflowBodyDrift(projectDir, workflows, synced = {}) {
|
|
|
71709
71851
|
return drifted;
|
|
71710
71852
|
}
|
|
71711
71853
|
function ensureAppTsconfig(projectDir) {
|
|
71712
|
-
const tsconfigPath =
|
|
71854
|
+
const tsconfigPath = path9.join(projectDir, "tsconfig.json");
|
|
71713
71855
|
if (!fs8.existsSync(tsconfigPath)) {
|
|
71714
71856
|
console.error(
|
|
71715
71857
|
`\u26A0 No tsconfig.json at ${projectDir} \u2014 could not ensure "include" has "${LOTICS_INCLUDE_GLOB}" (a bare .lotics loads none of the generated types) or "exclude" has ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")}.`
|
|
@@ -71761,15 +71903,15 @@ function writeDevLinkTsconfig(projectDir) {
|
|
|
71761
71903
|
if (uiSrc) {
|
|
71762
71904
|
paths["@lotics/ui/*"] = [`${uiSrc}/*`];
|
|
71763
71905
|
for (const peer of readKitPeerNames(projectDir)) {
|
|
71764
|
-
const typesDir =
|
|
71765
|
-
const runtimeDir =
|
|
71906
|
+
const typesDir = path9.join(projectDir, "node_modules", typesPackageFor(peer));
|
|
71907
|
+
const runtimeDir = path9.join(projectDir, "node_modules", peer);
|
|
71766
71908
|
const target = fs8.existsSync(typesDir) ? `../node_modules/${typesPackageFor(peer)}` : fs8.existsSync(runtimeDir) ? `../node_modules/${peer}` : null;
|
|
71767
71909
|
if (!target) continue;
|
|
71768
71910
|
paths[peer] = [target];
|
|
71769
71911
|
paths[`${peer}/*`] = [`${target}/*`];
|
|
71770
71912
|
}
|
|
71771
71913
|
}
|
|
71772
|
-
const file2 =
|
|
71914
|
+
const file2 = path9.join(projectDir, ".lotics", "tsconfig.link.json");
|
|
71773
71915
|
const header = uiSrc ? `// GENERATED by \`lotics app codegen\` \u2014 do not edit.
|
|
71774
71916
|
// LOTICS_UI_SRC is set, so @lotics/ui resolves to your working copy for tsc,
|
|
71775
71917
|
// vitest, eslint and your editor \u2014 the same copy Vite is bundling. The peer
|
|
@@ -71786,8 +71928,8 @@ function writeDevLinkTsconfig(projectDir) {
|
|
|
71786
71928
|
}
|
|
71787
71929
|
function writeKitTypeAugmentation(projectDir) {
|
|
71788
71930
|
const uiSrc = process.env.LOTICS_UI_SRC;
|
|
71789
|
-
const source = uiSrc ?
|
|
71790
|
-
const target =
|
|
71931
|
+
const source = uiSrc ? path9.join(uiSrc, "react_native.d.ts") : path9.join(projectDir, "node_modules", "@lotics", "ui", "src", "react_native.d.ts");
|
|
71932
|
+
const target = path9.join(projectDir, ".lotics", "react_native.d.ts");
|
|
71791
71933
|
if (!fs8.existsSync(source)) {
|
|
71792
71934
|
if (fs8.existsSync(target)) fs8.rmSync(target);
|
|
71793
71935
|
return;
|
|
@@ -71804,7 +71946,7 @@ function typesPackageFor(peer) {
|
|
|
71804
71946
|
return peer.startsWith("@") ? `@types/${peer.slice(1).replace("/", "__")}` : `@types/${peer}`;
|
|
71805
71947
|
}
|
|
71806
71948
|
function readKitPeerNames(projectDir) {
|
|
71807
|
-
const kitPkg =
|
|
71949
|
+
const kitPkg = path9.join(projectDir, "node_modules", "@lotics", "ui", "package.json");
|
|
71808
71950
|
if (!fs8.existsSync(kitPkg)) return [];
|
|
71809
71951
|
const parsed = JSON.parse(fs8.readFileSync(kitPkg, "utf-8"));
|
|
71810
71952
|
const peers = parsed.peerDependencies;
|
|
@@ -71815,12 +71957,12 @@ function writeAppDtsKitLinks(projectDir) {
|
|
|
71815
71957
|
writeKitTypeAugmentation(projectDir);
|
|
71816
71958
|
}
|
|
71817
71959
|
function writeAppDts(projectDir, manifest) {
|
|
71818
|
-
const dotLotics =
|
|
71960
|
+
const dotLotics = path9.join(projectDir, ".lotics");
|
|
71819
71961
|
fs8.mkdirSync(dotLotics, { recursive: true });
|
|
71820
71962
|
const written = [
|
|
71821
|
-
[
|
|
71822
|
-
[
|
|
71823
|
-
[
|
|
71963
|
+
[path9.join(dotLotics, "app_workflows.d.ts"), generateAppWorkflowsDts(manifest.workflows)],
|
|
71964
|
+
[path9.join(dotLotics, "app_queries.d.ts"), generateAppQueriesDts(manifest.queries)],
|
|
71965
|
+
[path9.join(dotLotics, "app_agents.d.ts"), generateAppAgentsDts(manifest.agents)]
|
|
71824
71966
|
];
|
|
71825
71967
|
for (const [file2, content] of written) fs8.writeFileSync(file2, content);
|
|
71826
71968
|
writeAppDtsKitLinks(projectDir);
|
|
@@ -71829,8 +71971,8 @@ function writeAppDts(projectDir, manifest) {
|
|
|
71829
71971
|
return written.map(([file2]) => file2);
|
|
71830
71972
|
}
|
|
71831
71973
|
function readCodegenTablesAllowlist(projectDir) {
|
|
71832
|
-
const
|
|
71833
|
-
const tables =
|
|
71974
|
+
const pkg = JSON.parse(fs8.readFileSync(path9.join(projectDir, "package.json"), "utf-8"));
|
|
71975
|
+
const tables = pkg.lotics?.codegen?.tables;
|
|
71834
71976
|
return Array.isArray(tables) ? tables.filter((t) => typeof t === "string") : [];
|
|
71835
71977
|
}
|
|
71836
71978
|
function resolveCodegenTableIds(projectDir, queries) {
|
|
@@ -71842,9 +71984,9 @@ function resolveCodegenTableIds(projectDir, queries) {
|
|
|
71842
71984
|
return [...ids];
|
|
71843
71985
|
}
|
|
71844
71986
|
function writeAppFields(projectDir, tables) {
|
|
71845
|
-
const dotLotics =
|
|
71987
|
+
const dotLotics = path9.join(projectDir, ".lotics");
|
|
71846
71988
|
fs8.mkdirSync(dotLotics, { recursive: true });
|
|
71847
|
-
const file2 =
|
|
71989
|
+
const file2 = path9.join(dotLotics, "app_fields.ts");
|
|
71848
71990
|
fs8.writeFileSync(file2, generateAppFields(tables));
|
|
71849
71991
|
return file2;
|
|
71850
71992
|
}
|
|
@@ -71869,7 +72011,7 @@ async function writeGeneratedAppFields(client, projectDir, app, queries) {
|
|
|
71869
72011
|
return;
|
|
71870
72012
|
}
|
|
71871
72013
|
const fieldsPath = writeAppFields(projectDir, tables);
|
|
71872
|
-
|
|
72014
|
+
note(
|
|
71873
72015
|
`Wrote ${fieldsPath} (baked form \u2014 bespoke; ${tables.length} table${tables.length === 1 ? "" : "s"})`
|
|
71874
72016
|
);
|
|
71875
72017
|
}
|
|
@@ -71879,7 +72021,7 @@ async function writeGeneratedAppFields(client, projectDir, app, queries) {
|
|
|
71879
72021
|
}
|
|
71880
72022
|
function warnAppFieldsUnwritten(projectDir, err2) {
|
|
71881
72023
|
const reason = err2 instanceof Error ? err2.message : String(err2);
|
|
71882
|
-
if (fs8.existsSync(
|
|
72024
|
+
if (fs8.existsSync(path9.join(projectDir, ".lotics", "app_fields.ts"))) {
|
|
71883
72025
|
console.error(`\u26A0 Could not regenerate .lotics/app_fields.ts (${reason}). Kept the existing file.`);
|
|
71884
72026
|
return;
|
|
71885
72027
|
}
|
|
@@ -71890,7 +72032,7 @@ function warnAppFieldsUnwritten(projectDir, err2) {
|
|
|
71890
72032
|
function warnAboutDevLink(projectDir, command) {
|
|
71891
72033
|
const uiSrc = process.env.LOTICS_UI_SRC;
|
|
71892
72034
|
if (!uiSrc) return;
|
|
71893
|
-
const viteConfigPath =
|
|
72035
|
+
const viteConfigPath = path9.join(projectDir, "vite.config.ts");
|
|
71894
72036
|
const config2 = fs8.existsSync(viteConfigPath) ? fs8.readFileSync(viteConfigPath, "utf-8") : "";
|
|
71895
72037
|
const linked = config2.includes("loticsResolve") || config2.includes("LOTICS_UI_SRC");
|
|
71896
72038
|
if (!linked) {
|
|
@@ -71909,9 +72051,9 @@ function warnAboutDevLink(projectDir, command) {
|
|
|
71909
72051
|
}
|
|
71910
72052
|
}
|
|
71911
72053
|
var KIT_PACKAGES = ["@lotics/ui", "@lotics/app-sdk"];
|
|
71912
|
-
function installedKitVersion(projectDir,
|
|
72054
|
+
function installedKitVersion(projectDir, pkg) {
|
|
71913
72055
|
try {
|
|
71914
|
-
const manifest =
|
|
72056
|
+
const manifest = path9.join(projectDir, "node_modules", ...pkg.split("/"), "package.json");
|
|
71915
72057
|
const parsed = JSON.parse(fs8.readFileSync(manifest, "utf-8"));
|
|
71916
72058
|
const version2 = parsed.version;
|
|
71917
72059
|
return typeof version2 === "string" ? version2 : null;
|
|
@@ -71919,12 +72061,12 @@ function installedKitVersion(projectDir, pkg2) {
|
|
|
71919
72061
|
return null;
|
|
71920
72062
|
}
|
|
71921
72063
|
}
|
|
71922
|
-
async function publishedKitVersion(
|
|
72064
|
+
async function publishedKitVersion(pkg) {
|
|
71923
72065
|
const controller = new AbortController();
|
|
71924
72066
|
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
71925
72067
|
timeout.unref();
|
|
71926
72068
|
try {
|
|
71927
|
-
const response = await fetch(`https://registry.npmjs.org/${
|
|
72069
|
+
const response = await fetch(`https://registry.npmjs.org/${pkg}/latest`, {
|
|
71928
72070
|
signal: controller.signal
|
|
71929
72071
|
});
|
|
71930
72072
|
if (!response.ok) return null;
|
|
@@ -71938,13 +72080,13 @@ async function publishedKitVersion(pkg2) {
|
|
|
71938
72080
|
}
|
|
71939
72081
|
async function warnIfKitBehind(projectDir) {
|
|
71940
72082
|
const checks = await Promise.all(
|
|
71941
|
-
KIT_PACKAGES.map(async (
|
|
71942
|
-
const installed = installedKitVersion(projectDir,
|
|
72083
|
+
KIT_PACKAGES.map(async (pkg) => {
|
|
72084
|
+
const installed = installedKitVersion(projectDir, pkg);
|
|
71943
72085
|
if (!installed) return null;
|
|
71944
|
-
const latest = await publishedKitVersion(
|
|
72086
|
+
const latest = await publishedKitVersion(pkg);
|
|
71945
72087
|
if (!latest || !isNewerVersion(latest, installed)) return null;
|
|
71946
72088
|
const behindMajor = (Number.parseInt(latest, 10) || 0) > (Number.parseInt(installed, 10) || 0);
|
|
71947
|
-
return { pkg
|
|
72089
|
+
return { pkg, installed, latest, behindMajor };
|
|
71948
72090
|
})
|
|
71949
72091
|
);
|
|
71950
72092
|
const findings = checks.filter((c) => c !== null);
|
|
@@ -71959,7 +72101,7 @@ async function warnIfKitBehind(projectDir) {
|
|
|
71959
72101
|
|
|
71960
72102
|
Breaking changes are listed newest-first in
|
|
71961
72103
|
node_modules/@lotics/ui/MIGRATION.md.` : "";
|
|
71962
|
-
|
|
72104
|
+
warn(
|
|
71963
72105
|
`
|
|
71964
72106
|
\u26A0 This app builds against a kit a major release behind:
|
|
71965
72107
|
` + lines.join("\n") + migration + `
|
|
@@ -71975,12 +72117,12 @@ A newer kit is published \u2014 \`npm update ${findings.map((f) => f.pkg).join("
|
|
|
71975
72117
|
);
|
|
71976
72118
|
}
|
|
71977
72119
|
function ensureAppVitestSetup(projectDir) {
|
|
71978
|
-
const setupPath =
|
|
72120
|
+
const setupPath = path9.join(projectDir, VITEST_SETUP_FILENAME);
|
|
71979
72121
|
if (!fs8.existsSync(setupPath)) {
|
|
71980
72122
|
fs8.writeFileSync(setupPath, VITEST_SETUP_CONTENT);
|
|
71981
72123
|
console.error(`Wrote ${VITEST_SETUP_FILENAME} (wired by vite.config.ts; empty until you fill it).`);
|
|
71982
72124
|
}
|
|
71983
|
-
const viteConfigPath =
|
|
72125
|
+
const viteConfigPath = path9.join(projectDir, "vite.config.ts");
|
|
71984
72126
|
if (!fs8.existsSync(viteConfigPath)) return;
|
|
71985
72127
|
const viteConfig = fs8.readFileSync(viteConfigPath, "utf-8");
|
|
71986
72128
|
if (/setupFiles\s*:/.test(viteConfig) && viteConfig.includes(VITEST_SETUP_FILENAME)) return;
|
|
@@ -71990,7 +72132,7 @@ function ensureAppVitestSetup(projectDir) {
|
|
|
71990
72132
|
);
|
|
71991
72133
|
}
|
|
71992
72134
|
async function appCodegen(args) {
|
|
71993
|
-
const projectDir =
|
|
72135
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
71994
72136
|
const meta3 = readAppMeta(projectDir);
|
|
71995
72137
|
const dtsPaths = writeAppDts(projectDir, {
|
|
71996
72138
|
workflows: meta3.workflows,
|
|
@@ -72004,7 +72146,7 @@ async function appCodegen(args) {
|
|
|
72004
72146
|
}
|
|
72005
72147
|
for (const alias of orphanWorkflowBodies(projectDir, declared)) {
|
|
72006
72148
|
console.error(
|
|
72007
|
-
`\u26A0 ${
|
|
72149
|
+
`\u26A0 ${path9.join(WORKFLOWS_DIR, `${alias}.ts`)} is not declared in package.json#lotics.workflows \u2014 'workflow check' and 'workflow set' both skip it. Declare the alias or delete the file.`
|
|
72008
72150
|
);
|
|
72009
72151
|
}
|
|
72010
72152
|
if (!args.client) {
|
|
@@ -72063,15 +72205,15 @@ async function refreshWorkflowTypes(client, projectDir, app_id, alias, declarati
|
|
|
72063
72205
|
return true;
|
|
72064
72206
|
}
|
|
72065
72207
|
function readPriorStamp(projectDir) {
|
|
72066
|
-
const
|
|
72067
|
-
if (!fs8.existsSync(
|
|
72068
|
-
let
|
|
72208
|
+
const pkgPath = path9.join(projectDir, "package.json");
|
|
72209
|
+
if (!fs8.existsSync(pkgPath)) return null;
|
|
72210
|
+
let pkg;
|
|
72069
72211
|
try {
|
|
72070
|
-
|
|
72212
|
+
pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
72071
72213
|
} catch {
|
|
72072
72214
|
return null;
|
|
72073
72215
|
}
|
|
72074
|
-
const lotics =
|
|
72216
|
+
const lotics = pkg.lotics && typeof pkg.lotics === "object" ? pkg.lotics : null;
|
|
72075
72217
|
if (!lotics) return null;
|
|
72076
72218
|
const id = lotics.current_version_id;
|
|
72077
72219
|
const number4 = lotics.version_number;
|
|
@@ -72132,8 +72274,8 @@ function appDirName(name2) {
|
|
|
72132
72274
|
}
|
|
72133
72275
|
async function materializeScaffold(targetPath, files) {
|
|
72134
72276
|
for (const file2 of files) {
|
|
72135
|
-
const fullPath =
|
|
72136
|
-
fs8.mkdirSync(
|
|
72277
|
+
const fullPath = path9.join(targetPath, file2.path);
|
|
72278
|
+
fs8.mkdirSync(path9.dirname(fullPath), { recursive: true });
|
|
72137
72279
|
fs8.writeFileSync(fullPath, file2.content);
|
|
72138
72280
|
}
|
|
72139
72281
|
console.error(`Scaffolded ${files.length} files into ${targetPath}`);
|
|
@@ -72142,7 +72284,7 @@ async function materializeScaffold(targetPath, files) {
|
|
|
72142
72284
|
writeAppDtsKitLinks(targetPath);
|
|
72143
72285
|
}
|
|
72144
72286
|
async function appCreate(client, args) {
|
|
72145
|
-
const targetPath =
|
|
72287
|
+
const targetPath = path9.resolve(args.targetPath ?? appDirName(args.name));
|
|
72146
72288
|
if (fs8.existsSync(targetPath)) {
|
|
72147
72289
|
const entries2 = fs8.readdirSync(targetPath);
|
|
72148
72290
|
if (entries2.length > 0) {
|
|
@@ -72171,7 +72313,7 @@ async function appCreate(client, args) {
|
|
|
72171
72313
|
});
|
|
72172
72314
|
console.error(`
|
|
72173
72315
|
Ready. Next steps:`);
|
|
72174
|
-
console.error(` cd ${
|
|
72316
|
+
console.error(` cd ${path9.relative(process.cwd(), targetPath) || "."}`);
|
|
72175
72317
|
console.error(` lotics docs # the contracts, at the versions installed here`);
|
|
72176
72318
|
console.error(` # edit src/App.tsx, then:`);
|
|
72177
72319
|
console.error(` lotics app check # every pre-flight a deploy runs`);
|
|
@@ -72230,17 +72372,17 @@ async function appVersions(client, args) {
|
|
|
72230
72372
|
}
|
|
72231
72373
|
}
|
|
72232
72374
|
function defaultPullTarget(appId, appName) {
|
|
72233
|
-
const cwdPkgPath =
|
|
72375
|
+
const cwdPkgPath = path9.join(process.cwd(), "package.json");
|
|
72234
72376
|
if (fs8.existsSync(cwdPkgPath)) {
|
|
72235
|
-
let
|
|
72377
|
+
let pkg = null;
|
|
72236
72378
|
try {
|
|
72237
|
-
|
|
72379
|
+
pkg = JSON.parse(fs8.readFileSync(cwdPkgPath, "utf-8"));
|
|
72238
72380
|
} catch (err2) {
|
|
72239
72381
|
console.error(
|
|
72240
72382
|
`\u26A0 Could not parse ${cwdPkgPath} (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 pulling into a fresh ${appDirName(appName)}/ subdir.`
|
|
72241
72383
|
);
|
|
72242
72384
|
}
|
|
72243
|
-
if (
|
|
72385
|
+
if (pkg?.lotics?.app_id === appId) return process.cwd();
|
|
72244
72386
|
}
|
|
72245
72387
|
return appDirName(appName);
|
|
72246
72388
|
}
|
|
@@ -72280,7 +72422,7 @@ async function hydrateAppProject(client, targetPath, app, opts) {
|
|
|
72280
72422
|
);
|
|
72281
72423
|
opts.kept.push(...kept);
|
|
72282
72424
|
if (written.length > 0) {
|
|
72283
|
-
|
|
72425
|
+
note(
|
|
72284
72426
|
`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/ (${written.join(", ")})`
|
|
72285
72427
|
);
|
|
72286
72428
|
}
|
|
@@ -72312,7 +72454,7 @@ async function hydrateAppProject(client, targetPath, app, opts) {
|
|
|
72312
72454
|
unseenLiveProse.push({ alias, parked: parkLiveAgentProse(targetPath, alias, instructions) });
|
|
72313
72455
|
}
|
|
72314
72456
|
if (written.length > 0) {
|
|
72315
|
-
|
|
72457
|
+
note(
|
|
72316
72458
|
`Wrote ${written.length} agent instruction ${written.length === 1 ? "file" : "files"} to ${AGENTS_DIR}/ (${written.join(", ")})`
|
|
72317
72459
|
);
|
|
72318
72460
|
}
|
|
@@ -72332,21 +72474,21 @@ async function appPull(client, args) {
|
|
|
72332
72474
|
if (!versionId) throw new Error(`App ${app.id} has no version to pull.`);
|
|
72333
72475
|
const version2 = await client.getAppVersion(app.id, versionId);
|
|
72334
72476
|
const sourceUrl = await client.getAppVersionSourceUrl(app.id, version2.id);
|
|
72335
|
-
const targetPath =
|
|
72477
|
+
const targetPath = path9.resolve(args.targetPath ?? defaultPullTarget(app.id, app.name));
|
|
72336
72478
|
fs8.mkdirSync(targetPath, { recursive: true });
|
|
72337
72479
|
const prior = readPriorStamp(targetPath);
|
|
72338
|
-
const tmpFile =
|
|
72480
|
+
const tmpFile = path9.join(tmpdir(), `lotics-app-${app.id}-${Date.now()}.tar.gz`);
|
|
72339
72481
|
console.error(`Downloading source archive...`);
|
|
72340
72482
|
await downloadToFile(sourceUrl, tmpFile);
|
|
72341
72483
|
const keptLocal = [];
|
|
72342
72484
|
const restoredFromArchive = [];
|
|
72343
|
-
const stagingDir = fs8.mkdtempSync(
|
|
72485
|
+
const stagingDir = fs8.mkdtempSync(path9.join(tmpdir(), `lotics-pull-${app.id}-`));
|
|
72344
72486
|
try {
|
|
72345
72487
|
await runTar(["-xzf", tmpFile, "-C", stagingDir], stagingDir);
|
|
72346
72488
|
console.error(`Extracting to ${targetPath}...`);
|
|
72347
72489
|
const copied = copyTree(stagingDir, targetPath, {
|
|
72348
72490
|
overwrite: args.force === true,
|
|
72349
|
-
skip: [WORKFLOWS_DIR, AGENTS_DIR].map((d) => d.split(
|
|
72491
|
+
skip: [WORKFLOWS_DIR, AGENTS_DIR].map((d) => d.split(path9.sep).join("/"))
|
|
72350
72492
|
});
|
|
72351
72493
|
keptLocal.push(...copied.kept);
|
|
72352
72494
|
restoredFromArchive.push(...copied.created);
|
|
@@ -72375,20 +72517,20 @@ async function appPull(client, args) {
|
|
|
72375
72517
|
});
|
|
72376
72518
|
console.error(`
|
|
72377
72519
|
Ready. Next steps:`);
|
|
72378
|
-
console.error(` cd ${
|
|
72520
|
+
console.error(` cd ${path9.relative(process.cwd(), targetPath) || "."}`);
|
|
72379
72521
|
console.error(` lotics docs # the contracts, at the versions installed here`);
|
|
72380
72522
|
console.error(` # edit src/App.tsx, then:`);
|
|
72381
72523
|
console.error(` lotics app deploy`);
|
|
72382
72524
|
}
|
|
72383
72525
|
function readAppSourceText(projectDir) {
|
|
72384
|
-
const srcDir =
|
|
72526
|
+
const srcDir = path9.join(projectDir, "src");
|
|
72385
72527
|
if (!fs8.existsSync(srcDir)) return "";
|
|
72386
72528
|
const parts = [];
|
|
72387
72529
|
const walk2 = (dir) => {
|
|
72388
72530
|
for (const entry of fs8.readdirSync(dir, { withFileTypes: true })) {
|
|
72389
|
-
const full =
|
|
72531
|
+
const full = path9.join(dir, entry.name);
|
|
72390
72532
|
if (entry.isDirectory()) walk2(full);
|
|
72391
|
-
else if (isAppSourcePath(
|
|
72533
|
+
else if (isAppSourcePath(path9.relative(projectDir, full))) {
|
|
72392
72534
|
parts.push(fs8.readFileSync(full, "utf8"));
|
|
72393
72535
|
}
|
|
72394
72536
|
}
|
|
@@ -72397,7 +72539,7 @@ function readAppSourceText(projectDir) {
|
|
|
72397
72539
|
return parts.join("\n");
|
|
72398
72540
|
}
|
|
72399
72541
|
async function appDeploy(client, args) {
|
|
72400
|
-
const projectDir =
|
|
72542
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
72401
72543
|
const meta3 = readAppMeta(projectDir);
|
|
72402
72544
|
warnAboutDevLink(projectDir, "deploy");
|
|
72403
72545
|
const liveApp = await client.getApp(meta3.app_id);
|
|
@@ -72426,23 +72568,23 @@ async function appDeploy(client, args) {
|
|
|
72426
72568
|
meta3.queries ?? {}
|
|
72427
72569
|
);
|
|
72428
72570
|
} catch (err2) {
|
|
72429
|
-
|
|
72571
|
+
warn(
|
|
72430
72572
|
`\u26A0 Could not regenerate .lotics/app_fields.ts (${err2.message}).
|
|
72431
72573
|
The build will use whatever is on disk \u2014 run 'lotics app codegen' if this app is published.`
|
|
72432
72574
|
);
|
|
72433
72575
|
}
|
|
72434
|
-
|
|
72576
|
+
note("Building...");
|
|
72435
72577
|
await runNpm(["run", "build"], projectDir);
|
|
72436
|
-
const distDir =
|
|
72578
|
+
const distDir = path9.join(projectDir, "dist");
|
|
72437
72579
|
if (!fs8.existsSync(distDir)) {
|
|
72438
72580
|
throw new Error(
|
|
72439
72581
|
`Build did not produce a dist/ directory in ${projectDir}. Check that 'npm run build' is configured correctly (Vite/etc. defaults to dist/).`
|
|
72440
72582
|
);
|
|
72441
72583
|
}
|
|
72442
|
-
const tmpSource =
|
|
72443
|
-
const tmpDist =
|
|
72584
|
+
const tmpSource = path9.join(tmpdir(), `lotics-source-${Date.now()}.tar.gz`);
|
|
72585
|
+
const tmpDist = path9.join(tmpdir(), `lotics-dist-${Date.now()}.tar.gz`);
|
|
72444
72586
|
try {
|
|
72445
|
-
|
|
72587
|
+
note("Packaging source...");
|
|
72446
72588
|
await runTar(
|
|
72447
72589
|
[
|
|
72448
72590
|
"-czf",
|
|
@@ -72456,10 +72598,10 @@ async function appDeploy(client, args) {
|
|
|
72456
72598
|
],
|
|
72457
72599
|
projectDir
|
|
72458
72600
|
);
|
|
72459
|
-
|
|
72601
|
+
note("Packaging dist...");
|
|
72460
72602
|
await runTar(["-czf", tmpDist, "-C", distDir, "."], projectDir);
|
|
72461
72603
|
const liveQueries = await readLiveQueries(client, meta3.app_id);
|
|
72462
|
-
|
|
72604
|
+
note("Uploading...");
|
|
72463
72605
|
try {
|
|
72464
72606
|
const result = await client.deployAppVersion({
|
|
72465
72607
|
queries: liveQueries,
|
|
@@ -72498,23 +72640,23 @@ async function appDeploy(client, args) {
|
|
|
72498
72640
|
current_version_id: result.version_id,
|
|
72499
72641
|
version_number: result.version_number
|
|
72500
72642
|
});
|
|
72501
|
-
|
|
72502
|
-
|
|
72643
|
+
note(`Deployed v${result.version_number} (${result.version_id})`);
|
|
72644
|
+
note(`Bundle size: ${(result.bundle_size_bytes / 1024).toFixed(1)} KB`);
|
|
72503
72645
|
try {
|
|
72504
72646
|
const drifted = staleWorkflowGlobals(projectDir, meta3.workflows ?? {});
|
|
72505
72647
|
for (const { alias, declaration } of drifted) {
|
|
72506
72648
|
if (await refreshWorkflowTypes(client, projectDir, meta3.app_id, alias, declaration)) {
|
|
72507
|
-
|
|
72649
|
+
note(`Refreshed workflow types for ${alias} \u2014 this deploy moved its declaration.`);
|
|
72508
72650
|
}
|
|
72509
72651
|
}
|
|
72510
72652
|
} catch (err2) {
|
|
72511
|
-
|
|
72653
|
+
warn(`(types not refreshed: ${err2.message})`);
|
|
72512
72654
|
}
|
|
72513
72655
|
let liveAfter;
|
|
72514
72656
|
try {
|
|
72515
72657
|
liveAfter = await client.getApp(meta3.app_id);
|
|
72516
72658
|
} catch (err2) {
|
|
72517
|
-
|
|
72659
|
+
warn(`(skipped post-deploy checks: ${err2.message})`);
|
|
72518
72660
|
}
|
|
72519
72661
|
if (liveAfter) {
|
|
72520
72662
|
warnIfUnbranded(liveAfter);
|
|
@@ -72555,7 +72697,7 @@ function warnIfUnbranded(app) {
|
|
|
72555
72697
|
if (!app.icon) missing.push("icon");
|
|
72556
72698
|
if (!app.theme?.color) missing.push("color");
|
|
72557
72699
|
if (missing.length === 0) return;
|
|
72558
|
-
|
|
72700
|
+
warn(
|
|
72559
72701
|
`
|
|
72560
72702
|
\u26A0 This app has no ${missing.join(" or ")} set \u2014 it shows a generic tile in the launcher.
|
|
72561
72703
|
Set it: lotics run update_app '{"app_id":"${app.id}","icon":"<lucide-name>","theme":{"color":"blue"}}'
|
|
@@ -72584,7 +72726,7 @@ async function readLiveQueries(client, appId) {
|
|
|
72584
72726
|
}
|
|
72585
72727
|
}
|
|
72586
72728
|
async function appCheck(client, args = {}) {
|
|
72587
|
-
const projectDir =
|
|
72729
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
72588
72730
|
const meta3 = readAppMeta(projectDir);
|
|
72589
72731
|
const app = await client.getApp(meta3.app_id);
|
|
72590
72732
|
assertProjectIsCurrent(meta3, app);
|
|
@@ -72859,10 +73001,10 @@ function copyTree(from, to, opts, relative = "") {
|
|
|
72859
73001
|
const kept = [];
|
|
72860
73002
|
const created = [];
|
|
72861
73003
|
for (const entry of fs8.readdirSync(from, { withFileTypes: true })) {
|
|
72862
|
-
const src =
|
|
72863
|
-
const dest =
|
|
72864
|
-
const rel =
|
|
72865
|
-
if (opts.skip?.includes(rel.split(
|
|
73004
|
+
const src = path9.join(from, entry.name);
|
|
73005
|
+
const dest = path9.join(to, entry.name);
|
|
73006
|
+
const rel = path9.join(relative, entry.name);
|
|
73007
|
+
if (opts.skip?.includes(rel.split(path9.sep).join("/"))) continue;
|
|
72866
73008
|
if (entry.isDirectory()) {
|
|
72867
73009
|
fs8.mkdirSync(dest, { recursive: true });
|
|
72868
73010
|
const child = copyTree(src, dest, opts, rel);
|
|
@@ -73035,9 +73177,9 @@ function warnIfProjectFootguns(projectDir, sourceText) {
|
|
|
73035
73177
|
].join("\n")
|
|
73036
73178
|
);
|
|
73037
73179
|
}
|
|
73038
|
-
const configName = VITE_CONFIG_NAMES.find((name2) => fs8.existsSync(
|
|
73180
|
+
const configName = VITE_CONFIG_NAMES.find((name2) => fs8.existsSync(path9.join(projectDir, name2)));
|
|
73039
73181
|
if (configName !== void 0) {
|
|
73040
|
-
const config2 = fs8.readFileSync(
|
|
73182
|
+
const config2 = fs8.readFileSync(path9.join(projectDir, configName), "utf-8");
|
|
73041
73183
|
const defined = defineBlockKeys(config2);
|
|
73042
73184
|
const missing = ["global", "__DEV__"].filter((name2) => !defined.has(name2));
|
|
73043
73185
|
if (missing.length > 0) {
|
|
@@ -73133,7 +73275,7 @@ function warnIfUnboundAliases(app, called) {
|
|
|
73133
73275
|
console.error(lines.join("\n"));
|
|
73134
73276
|
}
|
|
73135
73277
|
async function appDev(client, args) {
|
|
73136
|
-
const projectDir =
|
|
73278
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
73137
73279
|
const meta3 = readAppMeta(projectDir);
|
|
73138
73280
|
warnAboutDevLink(projectDir, "dev");
|
|
73139
73281
|
writeAppDts(projectDir, { workflows: meta3.workflows, queries: meta3.queries, agents: meta3.agents });
|
|
@@ -73267,7 +73409,7 @@ async function appAgentSet(client, args) {
|
|
|
73267
73409
|
}
|
|
73268
73410
|
if (!hasDeclaration) {
|
|
73269
73411
|
console.error(
|
|
73270
|
-
`No instructions at ${
|
|
73412
|
+
`No instructions at ${path9.relative(projectDir, file2)}, and nothing declared in package.json#lotics.agents.${args.alias} to push instead.
|
|
73271
73413
|
Run 'lotics app pull ${meta3.app_id}' to write ${AGENTS_DIR}/${args.alias}.md, then edit it.`
|
|
73272
73414
|
);
|
|
73273
73415
|
process.exit(1);
|
|
@@ -73276,7 +73418,7 @@ async function appAgentSet(client, args) {
|
|
|
73276
73418
|
const instructions = hasProse ? stripAgentHeader(fs8.readFileSync(file2, "utf-8")) : void 0;
|
|
73277
73419
|
if (instructions === "") {
|
|
73278
73420
|
console.error(
|
|
73279
|
-
`${
|
|
73421
|
+
`${path9.relative(projectDir, file2)} is empty after stripping the header \u2014 refusing to push an empty prompt.`
|
|
73280
73422
|
);
|
|
73281
73423
|
process.exit(1);
|
|
73282
73424
|
}
|
|
@@ -73343,7 +73485,7 @@ async function appWorkflowSet(client, args) {
|
|
|
73343
73485
|
const file2 = workflowFilePath(projectDir, args.alias);
|
|
73344
73486
|
if (!fs8.existsSync(file2)) {
|
|
73345
73487
|
console.error(
|
|
73346
|
-
`No workflow body at ${
|
|
73488
|
+
`No workflow body at ${path9.relative(projectDir, file2)}.
|
|
73347
73489
|
If "${args.alias}" is already bound: lotics app pull ${meta3.app_id} (writes the body)
|
|
73348
73490
|
If it is a NEW alias you declared: create that file yourself, then re-run this.`
|
|
73349
73491
|
);
|
|
@@ -73352,7 +73494,7 @@ async function appWorkflowSet(client, args) {
|
|
|
73352
73494
|
noteScope({ alias: args.alias });
|
|
73353
73495
|
const source = stripWorkflowHeader(fs8.readFileSync(file2, "utf-8"));
|
|
73354
73496
|
if (source.trim() === "") {
|
|
73355
|
-
console.error(`Workflow body ${
|
|
73497
|
+
console.error(`Workflow body ${path9.relative(projectDir, file2)} is empty after stripping the header.`);
|
|
73356
73498
|
process.exit(1);
|
|
73357
73499
|
}
|
|
73358
73500
|
const res = await client.setAppWorkflow(meta3.app_id, args.alias, {
|
|
@@ -73491,13 +73633,13 @@ async function appWorkflowCheck(args) {
|
|
|
73491
73633
|
const globalsPath = workflowGlobalsPath(projectDir, alias);
|
|
73492
73634
|
if (!fs8.existsSync(bodyPath)) {
|
|
73493
73635
|
console.error(
|
|
73494
|
-
`\u26A0 Skipped "${alias}" \u2014 no body at ${
|
|
73636
|
+
`\u26A0 Skipped "${alias}" \u2014 no body at ${path9.relative(projectDir, bodyPath)}. Run 'lotics app workflow pull' to write it.`
|
|
73495
73637
|
);
|
|
73496
73638
|
continue;
|
|
73497
73639
|
}
|
|
73498
73640
|
if (!fs8.existsSync(globalsPath)) {
|
|
73499
73641
|
console.error(
|
|
73500
|
-
`Cannot check "${alias}" \u2014 missing types at ${
|
|
73642
|
+
`Cannot check "${alias}" \u2014 missing types at ${path9.relative(projectDir, globalsPath)}. Run 'lotics app codegen' to fetch them (it refreshes types WITHOUT touching your body; a pull would overwrite it).`
|
|
73501
73643
|
);
|
|
73502
73644
|
process.exit(1);
|
|
73503
73645
|
}
|
|
@@ -73533,7 +73675,7 @@ async function appWorkflowCheck(args) {
|
|
|
73533
73675
|
function printWorkflowCheckResults(projectDir, results) {
|
|
73534
73676
|
let totalErrors = 0;
|
|
73535
73677
|
for (const r of results) {
|
|
73536
|
-
const rel =
|
|
73678
|
+
const rel = path9.relative(projectDir, r.bodyPath);
|
|
73537
73679
|
if (r.issues.length === 0) {
|
|
73538
73680
|
console.error(`\u2713 ${r.alias} (${rel}) \u2014 clean`);
|
|
73539
73681
|
continue;
|
|
@@ -73585,6 +73727,7 @@ function parseArgs(argv) {
|
|
|
73585
73727
|
remove: void 0,
|
|
73586
73728
|
includeHidden: false,
|
|
73587
73729
|
timezone: void 0,
|
|
73730
|
+
email: void 0,
|
|
73588
73731
|
message: void 0,
|
|
73589
73732
|
session: void 0,
|
|
73590
73733
|
port: void 0,
|
|
@@ -73669,6 +73812,9 @@ function parseArgs(argv) {
|
|
|
73669
73812
|
case "--name":
|
|
73670
73813
|
flags.name = argv[++i2];
|
|
73671
73814
|
break;
|
|
73815
|
+
case "--email":
|
|
73816
|
+
flags.email = argv[++i2];
|
|
73817
|
+
break;
|
|
73672
73818
|
case "--description":
|
|
73673
73819
|
flags.description = argv[++i2];
|
|
73674
73820
|
break;
|
|
@@ -73779,8 +73925,53 @@ function parseArgs(argv) {
|
|
|
73779
73925
|
|
|
73780
73926
|
// src/starter_commands.ts
|
|
73781
73927
|
import fs9 from "node:fs";
|
|
73782
|
-
import
|
|
73928
|
+
import path10 from "node:path";
|
|
73783
73929
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
73930
|
+
function printStarterRows(rows) {
|
|
73931
|
+
const width = Math.max(...rows.map((row) => row.id.length));
|
|
73932
|
+
for (const row of rows) {
|
|
73933
|
+
const tags = row.tags ?? [];
|
|
73934
|
+
console.log(
|
|
73935
|
+
` ${row.id.padEnd(width)} ${row.name}${tags.length > 0 ? ` [${tags.join(", ")}]` : ""}`
|
|
73936
|
+
);
|
|
73937
|
+
if (row.description) console.log(` ${" ".repeat(width)} ${row.description}`);
|
|
73938
|
+
}
|
|
73939
|
+
}
|
|
73940
|
+
function noteCopiedContent(templates, knowledgeDocs) {
|
|
73941
|
+
if (templates.length > 0) {
|
|
73942
|
+
note(
|
|
73943
|
+
`
|
|
73944
|
+
${templates.length} document template${templates.length === 1 ? "" : "s"}: ${templates.join(", ")}
|
|
73945
|
+
These carry the publisher's wording and details, not yours \u2014 decide which should
|
|
73946
|
+
become your own documents. Editing them: lotics docs document_templates`
|
|
73947
|
+
);
|
|
73948
|
+
}
|
|
73949
|
+
if (knowledgeDocs.length > 0) {
|
|
73950
|
+
note(
|
|
73951
|
+
`
|
|
73952
|
+
${knowledgeDocs.length} knowledge doc${knowledgeDocs.length === 1 ? "" : "s"}: ${knowledgeDocs.join(", ")}
|
|
73953
|
+
These describe how the publisher works, and the app's agents read them.
|
|
73954
|
+
Rewrite what differs: lotics docs knowledge_docs`
|
|
73955
|
+
);
|
|
73956
|
+
}
|
|
73957
|
+
}
|
|
73958
|
+
async function starterListPublic() {
|
|
73959
|
+
const starters = await fetchOfficialStarters();
|
|
73960
|
+
if (starters.length === 0) {
|
|
73961
|
+
console.error("No starters are published yet \u2014 build one with `lotics docs building_an_app`.");
|
|
73962
|
+
return;
|
|
73963
|
+
}
|
|
73964
|
+
console.error(`${starters.length} starter${starters.length === 1 ? "" : "s"} published by Lotics:
|
|
73965
|
+
`);
|
|
73966
|
+
printStarterRows(starters);
|
|
73967
|
+
console.error(
|
|
73968
|
+
`
|
|
73969
|
+
lotics start <starter_id> --email you@company.com Copy one \u2014 creates your account too
|
|
73970
|
+
|
|
73971
|
+
This machine has no Lotics account yet, so this is the published shelf.
|
|
73972
|
+
Signed in, the same command also lists what your own organization published.`
|
|
73973
|
+
);
|
|
73974
|
+
}
|
|
73784
73975
|
async function starterList(client) {
|
|
73785
73976
|
const starters = await client.listStarters();
|
|
73786
73977
|
if (starters.length === 0) {
|
|
@@ -73789,19 +73980,19 @@ async function starterList(client) {
|
|
|
73789
73980
|
);
|
|
73790
73981
|
return;
|
|
73791
73982
|
}
|
|
73792
|
-
const width = Math.max(...starters.map((s) => s.id.length));
|
|
73793
73983
|
console.error(`${starters.length} starter${starters.length === 1 ? "" : "s"}:
|
|
73794
73984
|
`);
|
|
73795
|
-
|
|
73796
|
-
|
|
73797
|
-
s.
|
|
73798
|
-
s.
|
|
73799
|
-
|
|
73800
|
-
|
|
73801
|
-
|
|
73802
|
-
|
|
73803
|
-
|
|
73804
|
-
|
|
73985
|
+
printStarterRows(
|
|
73986
|
+
starters.map((s) => ({
|
|
73987
|
+
id: s.id,
|
|
73988
|
+
name: s.name,
|
|
73989
|
+
description: s.description,
|
|
73990
|
+
tags: [
|
|
73991
|
+
s.is_official ? "official" : null,
|
|
73992
|
+
s.owned_by_caller === true ? "yours" : null
|
|
73993
|
+
].filter((t) => t !== null)
|
|
73994
|
+
}))
|
|
73995
|
+
);
|
|
73805
73996
|
console.error(`
|
|
73806
73997
|
lotics starter init <starter_id> Copy one into this workspace`);
|
|
73807
73998
|
}
|
|
@@ -73814,6 +74005,9 @@ async function starterShow(client, starter_id) {
|
|
|
73814
74005
|
version ${starter.latest_version}
|
|
73815
74006
|
trust ${starter.is_official ? "official \u2014 reviewed by Lotics" : starter.owned_by_caller === true ? "your organization's own" : "not copyable from this organization"}`
|
|
73816
74007
|
);
|
|
74008
|
+
if (starter.icon !== void 0) {
|
|
74009
|
+
console.log(`icon ${starter.icon ?? "none \u2014 copies show a generic tile"}`);
|
|
74010
|
+
}
|
|
73817
74011
|
if (starter.retired_at !== null) {
|
|
73818
74012
|
console.log(`retired ${starter.retired_at} \u2014 can no longer be copied`);
|
|
73819
74013
|
}
|
|
@@ -73821,7 +74015,7 @@ trust ${starter.is_official ? "official \u2014 reviewed by Lotics" : starter
|
|
|
73821
74015
|
function reportKnowledgeWarnings(warnings) {
|
|
73822
74016
|
const missing = warnings.missing_expected_docs;
|
|
73823
74017
|
if (missing.length === 0) return;
|
|
73824
|
-
|
|
74018
|
+
warn(
|
|
73825
74019
|
`
|
|
73826
74020
|
\u26A0 ${missing.length} knowledge doc(s) this starter's agents expect are missing here:
|
|
73827
74021
|
` + missing.map((name2) => ` \u2022 ${name2}`).join("\n") + `
|
|
@@ -73831,40 +74025,55 @@ function reportKnowledgeWarnings(warnings) {
|
|
|
73831
74025
|
}
|
|
73832
74026
|
async function starterInit(client, args) {
|
|
73833
74027
|
const starter = await client.getPackage(args.starter_id);
|
|
73834
|
-
|
|
74028
|
+
note(
|
|
73835
74029
|
`Copying ${starter.name}${starter.is_official ? " (official)" : ""} into this workspace\u2026`
|
|
73836
74030
|
);
|
|
73837
74031
|
const result = await client.instantiateStarter(args.starter_id, {
|
|
73838
74032
|
...args.noSampleData === true ? { no_sample_data: true } : {},
|
|
73839
74033
|
...args.adopt === true ? { adopt: true } : {}
|
|
73840
74034
|
});
|
|
73841
|
-
const
|
|
73842
|
-
const
|
|
73843
|
-
const templates = Object.keys(result.binding.templates ?? {}).
|
|
74035
|
+
const tables = Object.keys(result.binding.entities ?? {}).sort();
|
|
74036
|
+
const knowledgeDocs = Object.keys(result.binding.knowledge ?? {}).sort();
|
|
74037
|
+
const templates = Object.keys(result.binding.templates ?? {}).sort();
|
|
73844
74038
|
const records = Object.values(result.sample_record_ids).reduce((n, ids) => n + ids.length, 0);
|
|
73845
|
-
|
|
73846
|
-
|
|
74039
|
+
const created = {
|
|
74040
|
+
tables,
|
|
74041
|
+
templates,
|
|
74042
|
+
knowledge_docs: knowledgeDocs,
|
|
74043
|
+
sample_records: records
|
|
74044
|
+
};
|
|
74045
|
+
note(
|
|
74046
|
+
` Created ${tables.length} table${tables.length === 1 ? "" : "s"}, ${templates.length} template${templates.length === 1 ? "" : "s"}, ${knowledgeDocs.length} knowledge doc${knowledgeDocs.length === 1 ? "" : "s"}, ${records} sample record${records === 1 ? "" : "s"}.`
|
|
73847
74047
|
);
|
|
73848
74048
|
reportKnowledgeWarnings(result.knowledge_warnings);
|
|
73849
74049
|
if (result.app_id === null || result.bundle_url === null) {
|
|
73850
|
-
|
|
73851
|
-
Done
|
|
73852
|
-
|
|
74050
|
+
note(`
|
|
74051
|
+
Done \u2014 these are yours now, with no link back to the starter.`);
|
|
74052
|
+
noteCopiedContent(templates, knowledgeDocs);
|
|
74053
|
+
return {
|
|
74054
|
+
starter_id: args.starter_id,
|
|
74055
|
+
starter_name: starter.name,
|
|
74056
|
+
version: result.version,
|
|
74057
|
+
app_id: null,
|
|
74058
|
+
project_dir: null,
|
|
74059
|
+
created,
|
|
74060
|
+
signin_url: null
|
|
74061
|
+
};
|
|
73853
74062
|
}
|
|
73854
|
-
const targetPath =
|
|
74063
|
+
const targetPath = path10.resolve(args.targetPath ?? appDirName(starter.name));
|
|
73855
74064
|
if (fs9.existsSync(targetPath) && fs9.readdirSync(targetPath).length > 0) {
|
|
73856
74065
|
throw new Error(
|
|
73857
74066
|
`Target directory ${targetPath} is not empty. The app (${result.app_id}) was created \u2014 pass an empty path and re-run, or finish it with "lotics app pull ${result.app_id}".`
|
|
73858
74067
|
);
|
|
73859
74068
|
}
|
|
73860
74069
|
fs9.mkdirSync(targetPath, { recursive: true });
|
|
73861
|
-
|
|
73862
|
-
const bundleFile =
|
|
73863
|
-
const wrapperDir = fs9.mkdtempSync(
|
|
74070
|
+
note(`Downloading source\u2026`);
|
|
74071
|
+
const bundleFile = path10.join(tmpdir2(), `lotics-starter-${args.starter_id}-${process.pid}.tar.gz`);
|
|
74072
|
+
const wrapperDir = fs9.mkdtempSync(path10.join(tmpdir2(), `lotics-starter-`));
|
|
73864
74073
|
try {
|
|
73865
74074
|
await downloadToFile(result.bundle_url, bundleFile);
|
|
73866
74075
|
await runTar(["-xzf", bundleFile, "-C", wrapperDir], wrapperDir);
|
|
73867
|
-
const sourceArchive =
|
|
74076
|
+
const sourceArchive = path10.join(wrapperDir, "source.tar.gz");
|
|
73868
74077
|
if (!fs9.existsSync(sourceArchive)) {
|
|
73869
74078
|
throw new Error(
|
|
73870
74079
|
`Starter bundle carried no source.tar.gz \u2014 the app (${result.app_id}) exists but has no code. Report this to the starter's publisher.`
|
|
@@ -73876,7 +74085,7 @@ Done. The documents and knowledge are yours to edit \u2014 nothing links back.`)
|
|
|
73876
74085
|
fs9.rmSync(wrapperDir, { recursive: true, force: true });
|
|
73877
74086
|
}
|
|
73878
74087
|
for (const dir of ["knowledge", "fixtures"]) {
|
|
73879
|
-
fs9.rmSync(
|
|
74088
|
+
fs9.rmSync(path10.join(targetPath, dir), { recursive: true, force: true });
|
|
73880
74089
|
}
|
|
73881
74090
|
const app = await client.getApp(result.app_id);
|
|
73882
74091
|
const kept = [];
|
|
@@ -73886,15 +74095,14 @@ Done. The documents and knowledge are yours to edit \u2014 nothing links back.`)
|
|
|
73886
74095
|
kept
|
|
73887
74096
|
});
|
|
73888
74097
|
if (starter.owned_by_caller !== true) {
|
|
73889
|
-
|
|
74098
|
+
warn(
|
|
73890
74099
|
`
|
|
73891
74100
|
Building ${starter.name} \u2014 this runs its build on your machine (its package scripts
|
|
73892
74101
|
and vite config are the publisher's code, executed as you).${starter.is_official ? " Lotics reviewed this starter." : ""}`
|
|
73893
74102
|
);
|
|
73894
74103
|
} else {
|
|
73895
|
-
|
|
74104
|
+
note(`Building and deploying\u2026`);
|
|
73896
74105
|
}
|
|
73897
|
-
await runNpm(["run", "build"], targetPath);
|
|
73898
74106
|
await appDeploy(client, {
|
|
73899
74107
|
projectDir: targetPath,
|
|
73900
74108
|
message: `Copied from starter ${starter.name}`
|
|
@@ -73907,14 +74115,14 @@ Building ${starter.name} \u2014 this runs its build on your machine (its package
|
|
|
73907
74115
|
});
|
|
73908
74116
|
signInUrl = link.url ?? null;
|
|
73909
74117
|
} catch (error52) {
|
|
73910
|
-
|
|
74118
|
+
warn(
|
|
73911
74119
|
`
|
|
73912
74120
|
(no sign-in link: ${error52 instanceof Error ? error52.message : String(error52)})
|
|
73913
74121
|
The copy is complete either way \u2014 open it with "lotics auth web".`
|
|
73914
74122
|
);
|
|
73915
74123
|
signInUrl = null;
|
|
73916
74124
|
}
|
|
73917
|
-
|
|
74125
|
+
note(
|
|
73918
74126
|
`
|
|
73919
74127
|
Done \u2014 ${starter.name} is live and yours.
|
|
73920
74128
|
App: ${result.app_id}
|
|
@@ -73922,42 +74130,55 @@ Done \u2014 ${starter.name} is live and yours.
|
|
|
73922
74130
|
|
|
73923
74131
|
Edit anything: the tables, the app source, the templates, the docs. There is no
|
|
73924
74132
|
link back to the starter and nothing to upgrade \u2014 this is your app now.
|
|
73925
|
-
Ship a change: cd ${
|
|
74133
|
+
Ship a change: cd ${path10.relative(process.cwd(), targetPath) || "."} && lotics app deploy -m "<what changed>"
|
|
74134
|
+
|
|
74135
|
+
How to change it: lotics docs building_an_app (then \`lotics docs\` for the rest \u2014
|
|
74136
|
+
the SDK and UI references are installed in this project, so they match its versions)`
|
|
73926
74137
|
);
|
|
73927
74138
|
if (records > 0) {
|
|
73928
|
-
|
|
74139
|
+
note(
|
|
73929
74140
|
`
|
|
73930
74141
|
${records} sample record${records === 1 ? "" : "s"} came with it. They are ordinary records \u2014
|
|
73931
74142
|
delete them whenever you like, or re-run with --no-sample-data next time.`
|
|
73932
74143
|
);
|
|
73933
74144
|
}
|
|
74145
|
+
noteCopiedContent(templates, knowledgeDocs);
|
|
73934
74146
|
if (signInUrl !== null) {
|
|
73935
|
-
|
|
74147
|
+
note(
|
|
73936
74148
|
`
|
|
73937
74149
|
Open it \u2014 one-time sign-in link, expires in 15 minutes:
|
|
73938
74150
|
${signInUrl}`
|
|
73939
74151
|
);
|
|
73940
74152
|
}
|
|
74153
|
+
return {
|
|
74154
|
+
starter_id: args.starter_id,
|
|
74155
|
+
starter_name: starter.name,
|
|
74156
|
+
version: result.version,
|
|
74157
|
+
app_id: result.app_id,
|
|
74158
|
+
project_dir: targetPath,
|
|
74159
|
+
created,
|
|
74160
|
+
signin_url: signInUrl
|
|
74161
|
+
};
|
|
73941
74162
|
}
|
|
73942
74163
|
async function starterFixturesCapture(client, args) {
|
|
73943
|
-
const projectDir =
|
|
74164
|
+
const projectDir = path10.resolve(args.projectDir ?? process.cwd());
|
|
73944
74165
|
const meta3 = readAppMeta(projectDir);
|
|
73945
74166
|
const result = await client.captureStarterFixtures(meta3.app_id, {
|
|
73946
74167
|
entities: args.entities,
|
|
73947
74168
|
...args.limit !== void 0 ? { limit: args.limit } : {}
|
|
73948
74169
|
});
|
|
73949
|
-
const fixturesDir =
|
|
74170
|
+
const fixturesDir = path10.join(projectDir, "fixtures");
|
|
73950
74171
|
fs9.mkdirSync(fixturesDir, { recursive: true });
|
|
73951
74172
|
let totalRows = 0;
|
|
73952
74173
|
for (const entry of result.captured) {
|
|
73953
|
-
const file2 =
|
|
74174
|
+
const file2 = path10.join(projectDir, entry.content_ref);
|
|
73954
74175
|
fs9.writeFileSync(file2, `${JSON.stringify(entry.file, null, 2)}
|
|
73955
74176
|
`, "utf-8");
|
|
73956
74177
|
totalRows += entry.file.rows.length;
|
|
73957
74178
|
console.error(
|
|
73958
74179
|
` ${entry.content_ref} \u2014 ${entry.file.rows.length} row${entry.file.rows.length === 1 ? "" : "s"}`
|
|
73959
74180
|
);
|
|
73960
|
-
for (const
|
|
74181
|
+
for (const line of entry.notes) console.error(` \u26A0 ${line}`);
|
|
73961
74182
|
}
|
|
73962
74183
|
if (result.captured.length === 0) {
|
|
73963
74184
|
console.error(
|
|
@@ -74041,7 +74262,7 @@ import fs11 from "node:fs";
|
|
|
74041
74262
|
|
|
74042
74263
|
// src/file_command_io.ts
|
|
74043
74264
|
import fs10 from "node:fs";
|
|
74044
|
-
import
|
|
74265
|
+
import path11 from "node:path";
|
|
74045
74266
|
var CliError = class extends Error {
|
|
74046
74267
|
constructor(message2) {
|
|
74047
74268
|
super(message2);
|
|
@@ -74064,8 +74285,8 @@ function rejectExtraArgs(rest2, arity, usage) {
|
|
|
74064
74285
|
fail2(`${usage} takes ${arity} argument${arity === 1 ? "" : "s"} after <file>, got ${rest2.length}. Unused: ${rest2.slice(arity).join(" ")}`);
|
|
74065
74286
|
}
|
|
74066
74287
|
function writeFileAtomic(filePath, bytes) {
|
|
74067
|
-
const dir =
|
|
74068
|
-
const tmp =
|
|
74288
|
+
const dir = path11.dirname(path11.resolve(filePath));
|
|
74289
|
+
const tmp = path11.join(dir, `.${path11.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
|
|
74069
74290
|
fs10.writeFileSync(tmp, bytes);
|
|
74070
74291
|
try {
|
|
74071
74292
|
fs10.renameSync(tmp, filePath);
|
|
@@ -76868,16 +77089,16 @@ var MatcherView = class {
|
|
|
76868
77089
|
* @returns {string|undefined}
|
|
76869
77090
|
*/
|
|
76870
77091
|
getCurrentTag() {
|
|
76871
|
-
const
|
|
76872
|
-
return
|
|
77092
|
+
const path13 = this._matcher.path;
|
|
77093
|
+
return path13.length > 0 ? path13[path13.length - 1].tag : void 0;
|
|
76873
77094
|
}
|
|
76874
77095
|
/**
|
|
76875
77096
|
* Get current namespace.
|
|
76876
77097
|
* @returns {string|undefined}
|
|
76877
77098
|
*/
|
|
76878
77099
|
getCurrentNamespace() {
|
|
76879
|
-
const
|
|
76880
|
-
return
|
|
77100
|
+
const path13 = this._matcher.path;
|
|
77101
|
+
return path13.length > 0 ? path13[path13.length - 1].namespace : void 0;
|
|
76881
77102
|
}
|
|
76882
77103
|
/**
|
|
76883
77104
|
* Get current node's attribute value.
|
|
@@ -76885,9 +77106,9 @@ var MatcherView = class {
|
|
|
76885
77106
|
* @returns {*}
|
|
76886
77107
|
*/
|
|
76887
77108
|
getAttrValue(attrName) {
|
|
76888
|
-
const
|
|
76889
|
-
if (
|
|
76890
|
-
return
|
|
77109
|
+
const path13 = this._matcher.path;
|
|
77110
|
+
if (path13.length === 0) return void 0;
|
|
77111
|
+
return path13[path13.length - 1].values?.[attrName];
|
|
76891
77112
|
}
|
|
76892
77113
|
/**
|
|
76893
77114
|
* Check if current node has an attribute.
|
|
@@ -76895,9 +77116,9 @@ var MatcherView = class {
|
|
|
76895
77116
|
* @returns {boolean}
|
|
76896
77117
|
*/
|
|
76897
77118
|
hasAttr(attrName) {
|
|
76898
|
-
const
|
|
76899
|
-
if (
|
|
76900
|
-
const current =
|
|
77119
|
+
const path13 = this._matcher.path;
|
|
77120
|
+
if (path13.length === 0) return false;
|
|
77121
|
+
const current = path13[path13.length - 1];
|
|
76901
77122
|
return current.values !== void 0 && attrName in current.values;
|
|
76902
77123
|
}
|
|
76903
77124
|
/**
|
|
@@ -76923,18 +77144,18 @@ var MatcherView = class {
|
|
|
76923
77144
|
* @returns {number}
|
|
76924
77145
|
*/
|
|
76925
77146
|
getPosition() {
|
|
76926
|
-
const
|
|
76927
|
-
if (
|
|
76928
|
-
return
|
|
77147
|
+
const path13 = this._matcher.path;
|
|
77148
|
+
if (path13.length === 0) return -1;
|
|
77149
|
+
return path13[path13.length - 1].position ?? 0;
|
|
76929
77150
|
}
|
|
76930
77151
|
/**
|
|
76931
77152
|
* Get current node's repeat counter (occurrence count of this tag name).
|
|
76932
77153
|
* @returns {number}
|
|
76933
77154
|
*/
|
|
76934
77155
|
getCounter() {
|
|
76935
|
-
const
|
|
76936
|
-
if (
|
|
76937
|
-
return
|
|
77156
|
+
const path13 = this._matcher.path;
|
|
77157
|
+
if (path13.length === 0) return -1;
|
|
77158
|
+
return path13[path13.length - 1].counter ?? 0;
|
|
76938
77159
|
}
|
|
76939
77160
|
/**
|
|
76940
77161
|
* Get current node's sibling index (alias for getPosition).
|
|
@@ -82592,10 +82813,10 @@ function resolveRelativePath(basePath, relativePath) {
|
|
|
82592
82813
|
}
|
|
82593
82814
|
return resolved.join("/");
|
|
82594
82815
|
}
|
|
82595
|
-
function findZipEntry(zipEntries,
|
|
82596
|
-
if (zipEntries[
|
|
82597
|
-
if (zipEntries[`xl/${
|
|
82598
|
-
const noSlash =
|
|
82816
|
+
function findZipEntry(zipEntries, path13) {
|
|
82817
|
+
if (zipEntries[path13]) return zipEntries[path13];
|
|
82818
|
+
if (zipEntries[`xl/${path13}`]) return zipEntries[`xl/${path13}`];
|
|
82819
|
+
const noSlash = path13.replace(/^\//, "");
|
|
82599
82820
|
if (zipEntries[noSlash]) return zipEntries[noSlash];
|
|
82600
82821
|
return void 0;
|
|
82601
82822
|
}
|
|
@@ -84496,9 +84717,9 @@ function parseExcelFromZip(zip, options) {
|
|
|
84496
84717
|
}
|
|
84497
84718
|
return result;
|
|
84498
84719
|
}
|
|
84499
|
-
function findEntry(zip,
|
|
84500
|
-
if (zip[
|
|
84501
|
-
const lower2 =
|
|
84720
|
+
function findEntry(zip, path13) {
|
|
84721
|
+
if (zip[path13]) return zip[path13];
|
|
84722
|
+
const lower2 = path13.toLowerCase();
|
|
84502
84723
|
for (const key of Object.keys(zip)) {
|
|
84503
84724
|
if (key.toLowerCase() === lower2) return zip[key];
|
|
84504
84725
|
}
|
|
@@ -85135,12 +85356,12 @@ function extractPivotRoundTripInfo(originalZip) {
|
|
|
85135
85356
|
if (paths.length > 0) pivotTablesBySheetIndex.set(i2, paths);
|
|
85136
85357
|
}
|
|
85137
85358
|
const pivotXmlPaths = [];
|
|
85138
|
-
for (const
|
|
85139
|
-
if (
|
|
85140
|
-
pivotXmlPaths.push(
|
|
85359
|
+
for (const path13 of Object.keys(originalZip)) {
|
|
85360
|
+
if (path13.startsWith("xl/pivotTables/") && path13.endsWith(".xml")) {
|
|
85361
|
+
pivotXmlPaths.push(path13);
|
|
85141
85362
|
}
|
|
85142
|
-
if (
|
|
85143
|
-
pivotXmlPaths.push(
|
|
85363
|
+
if (path13.startsWith("xl/pivotCache/") && path13.endsWith(".xml")) {
|
|
85364
|
+
pivotXmlPaths.push(path13);
|
|
85144
85365
|
}
|
|
85145
85366
|
}
|
|
85146
85367
|
return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths };
|
|
@@ -85148,15 +85369,15 @@ function extractPivotRoundTripInfo(originalZip) {
|
|
|
85148
85369
|
function decode3(bytes) {
|
|
85149
85370
|
return new TextDecoder().decode(bytes);
|
|
85150
85371
|
}
|
|
85151
|
-
function pivotContentTypeFor(
|
|
85152
|
-
if (
|
|
85153
|
-
return `<Override PartName="/${
|
|
85372
|
+
function pivotContentTypeFor(path13) {
|
|
85373
|
+
if (path13.startsWith("xl/pivotTables/") && path13.endsWith(".xml")) {
|
|
85374
|
+
return `<Override PartName="/${path13}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
|
|
85154
85375
|
}
|
|
85155
|
-
if (
|
|
85156
|
-
return `<Override PartName="/${
|
|
85376
|
+
if (path13.includes("/pivotCacheDefinition") && path13.endsWith(".xml")) {
|
|
85377
|
+
return `<Override PartName="/${path13}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
|
|
85157
85378
|
}
|
|
85158
|
-
if (
|
|
85159
|
-
return `<Override PartName="/${
|
|
85379
|
+
if (path13.includes("/pivotCacheRecords") && path13.endsWith(".xml")) {
|
|
85380
|
+
return `<Override PartName="/${path13}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
|
|
85160
85381
|
}
|
|
85161
85382
|
return void 0;
|
|
85162
85383
|
}
|
|
@@ -85229,16 +85450,16 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
85229
85450
|
regeneratedPaths.add(`xl/worksheets/sheet${i2 + 1}.xml`);
|
|
85230
85451
|
regeneratedPaths.add(`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`);
|
|
85231
85452
|
}
|
|
85232
|
-
for (const
|
|
85233
|
-
if (
|
|
85234
|
-
regeneratedPaths.add(
|
|
85453
|
+
for (const path13 of Object.keys(originalZip)) {
|
|
85454
|
+
if (path13.startsWith("xl/drawings/") || path13.startsWith("xl/charts/") || path13.startsWith("xl/tables/") || path13.startsWith("xl/media/")) {
|
|
85455
|
+
regeneratedPaths.add(path13);
|
|
85235
85456
|
}
|
|
85236
85457
|
}
|
|
85237
|
-
for (const [
|
|
85238
|
-
if (regeneratedPaths.has(
|
|
85239
|
-
const ext =
|
|
85458
|
+
for (const [path13, data2] of Object.entries(originalZip)) {
|
|
85459
|
+
if (regeneratedPaths.has(path13)) continue;
|
|
85460
|
+
const ext = path13.slice(path13.lastIndexOf(".") + 1).toLowerCase();
|
|
85240
85461
|
if (!DECLARED_EXTENSIONS.includes(ext)) continue;
|
|
85241
|
-
entries2[
|
|
85462
|
+
entries2[path13] = data2;
|
|
85242
85463
|
}
|
|
85243
85464
|
}
|
|
85244
85465
|
const sharedStrings = buildSharedStrings(workbook);
|
|
@@ -85254,8 +85475,8 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
85254
85475
|
buildWorkbookRels(workbook, pivotInfo)
|
|
85255
85476
|
);
|
|
85256
85477
|
const extraContentTypes = [];
|
|
85257
|
-
for (const
|
|
85258
|
-
const ct = pivotContentTypeFor(
|
|
85478
|
+
for (const path13 of pivotInfo.pivotXmlPaths) {
|
|
85479
|
+
const ct = pivotContentTypeFor(path13);
|
|
85259
85480
|
if (ct) extraContentTypes.push(ct);
|
|
85260
85481
|
}
|
|
85261
85482
|
let globalChartIndex = 1;
|
|
@@ -94441,14 +94662,14 @@ var DependencyGraph = class {
|
|
|
94441
94662
|
stack.push({ cell: p, path: [cell, p] });
|
|
94442
94663
|
}
|
|
94443
94664
|
while (stack.length > 0) {
|
|
94444
|
-
const { cell: current, path:
|
|
94445
|
-
if (current === cell || originCoarse.has(current)) return
|
|
94665
|
+
const { cell: current, path: path13 } = stack.pop();
|
|
94666
|
+
if (current === cell || originCoarse.has(current)) return path13;
|
|
94446
94667
|
if (visited.has(current)) continue;
|
|
94447
94668
|
visited.add(current);
|
|
94448
94669
|
const nextPrec = this.precedents.get(current);
|
|
94449
94670
|
if (!nextPrec) continue;
|
|
94450
94671
|
for (const p of nextPrec) {
|
|
94451
|
-
stack.push({ cell: p, path: [...
|
|
94672
|
+
stack.push({ cell: p, path: [...path13, p] });
|
|
94452
94673
|
}
|
|
94453
94674
|
}
|
|
94454
94675
|
return null;
|
|
@@ -98510,15 +98731,15 @@ function finalizeParagraph(ctx, parts, startCp, markCp, isCellMark, numbering) {
|
|
|
98510
98731
|
};
|
|
98511
98732
|
}
|
|
98512
98733
|
function readPictureAt(ctx, raw, cp) {
|
|
98513
|
-
const
|
|
98734
|
+
const note2 = (detail) => {
|
|
98514
98735
|
ctx.diagnostics.push({ kind: "image", location: { cp }, detail });
|
|
98515
98736
|
return null;
|
|
98516
98737
|
};
|
|
98517
|
-
if (raw.picLocation === void 0) return
|
|
98518
|
-
if (!ctx.data) return
|
|
98738
|
+
if (raw.picLocation === void 0) return note2("Picture anchor carries no Data-stream location; dropped");
|
|
98739
|
+
if (!ctx.data) return note2("Picture anchor found but the document has no Data stream; dropped");
|
|
98519
98740
|
const picture = readInlinePicture(ctx.data, raw.picLocation);
|
|
98520
98741
|
if (!picture) {
|
|
98521
|
-
return
|
|
98742
|
+
return note2(`Picture at Data+${raw.picLocation} is not a readable inline image; dropped`);
|
|
98522
98743
|
}
|
|
98523
98744
|
return picture;
|
|
98524
98745
|
}
|
|
@@ -101208,9 +101429,9 @@ function buildFootnotesXml(footnotes, ctx) {
|
|
|
101208
101429
|
boilerplateNote("separator", "-1", "w:separator"),
|
|
101209
101430
|
boilerplateNote("continuationSeparator", "0", "w:continuationSeparator")
|
|
101210
101431
|
];
|
|
101211
|
-
for (const
|
|
101212
|
-
const content =
|
|
101213
|
-
notes.push({ "w:footnote": content, ":@": { "@_w:id": String(
|
|
101432
|
+
for (const note2 of footnotes) {
|
|
101433
|
+
const content = note2.content.length > 0 ? note2.content.map((b) => buildBlockElement(b, ctx)) : [{ "w:p": [] }];
|
|
101434
|
+
notes.push({ "w:footnote": content, ":@": { "@_w:id": String(note2.index) } });
|
|
101214
101435
|
}
|
|
101215
101436
|
const root = { "w:footnotes": notes, ":@": { "@_xmlns:w": W_NS3 } };
|
|
101216
101437
|
return buildXml([root]);
|
|
@@ -101247,7 +101468,7 @@ function collectFonts(fonts, acc) {
|
|
|
101247
101468
|
function walkModel(model) {
|
|
101248
101469
|
const acc = { referencedStyleIstds: /* @__PURE__ */ new Set(), fontNames: /* @__PURE__ */ new Set() };
|
|
101249
101470
|
walkBlocks(model.body, acc);
|
|
101250
|
-
for (const
|
|
101471
|
+
for (const note2 of model.footnotes) walkBlocks(note2.content, acc);
|
|
101251
101472
|
for (const style of model.styles) {
|
|
101252
101473
|
if (style.chp) collectFonts(style.chp.fonts, acc);
|
|
101253
101474
|
}
|
|
@@ -101402,8 +101623,8 @@ async function docModelToDocx(model) {
|
|
|
101402
101623
|
// ../ooxml/src/opc.ts
|
|
101403
101624
|
var import_jszip = __toESM(require_lib4(), 1);
|
|
101404
101625
|
function dropFolderEntries(zip) {
|
|
101405
|
-
for (const [
|
|
101406
|
-
if (entry.dir) delete zip.files[
|
|
101626
|
+
for (const [path13, entry] of Object.entries(zip.files)) {
|
|
101627
|
+
if (entry.dir) delete zip.files[path13];
|
|
101407
101628
|
}
|
|
101408
101629
|
}
|
|
101409
101630
|
|
|
@@ -101658,11 +101879,11 @@ async function parseDocx(buffer) {
|
|
|
101658
101879
|
const zip = await import_jszip3.default.loadAsync(buffer);
|
|
101659
101880
|
const parts = /* @__PURE__ */ new Map();
|
|
101660
101881
|
const filePromises = [];
|
|
101661
|
-
zip.forEach((
|
|
101882
|
+
zip.forEach((path13, file2) => {
|
|
101662
101883
|
if (file2.dir) return;
|
|
101663
101884
|
filePromises.push(
|
|
101664
101885
|
file2.async("uint8array").then((bytes) => {
|
|
101665
|
-
parts.set(
|
|
101886
|
+
parts.set(path13, bytes);
|
|
101666
101887
|
})
|
|
101667
101888
|
);
|
|
101668
101889
|
});
|
|
@@ -101894,9 +102115,9 @@ var DEFAULT_PARTS = [
|
|
|
101894
102115
|
["word/theme/theme1.xml", () => encoder.encode(THEME_XML)]
|
|
101895
102116
|
];
|
|
101896
102117
|
function fillDefaultParts(parts) {
|
|
101897
|
-
for (const [
|
|
101898
|
-
if (!parts.has(
|
|
101899
|
-
parts.set(
|
|
102118
|
+
for (const [path13, makeBytes] of DEFAULT_PARTS) {
|
|
102119
|
+
if (!parts.has(path13)) {
|
|
102120
|
+
parts.set(path13, makeBytes());
|
|
101900
102121
|
}
|
|
101901
102122
|
}
|
|
101902
102123
|
return parts;
|
|
@@ -101906,9 +102127,9 @@ function fillDefaultParts(parts) {
|
|
|
101906
102127
|
async function serializeDocx(doc) {
|
|
101907
102128
|
const zip = new import_jszip4.default();
|
|
101908
102129
|
const parts = fillDefaultParts(new Map(doc.parts));
|
|
101909
|
-
for (const [
|
|
101910
|
-
if (
|
|
101911
|
-
zip.file(
|
|
102130
|
+
for (const [path13, bytes] of parts) {
|
|
102131
|
+
if (path13 === "word/document.xml") continue;
|
|
102132
|
+
zip.file(path13, bytes);
|
|
101912
102133
|
}
|
|
101913
102134
|
const documentXml = serializeDocumentXml(doc);
|
|
101914
102135
|
zip.file("word/document.xml", documentXml);
|
|
@@ -102697,12 +102918,12 @@ async function runKnowledgeCommand(client, subcommand, toolArgs, flags, restArgs
|
|
|
102697
102918
|
// src/preview.ts
|
|
102698
102919
|
import { spawn as spawn3 } from "node:child_process";
|
|
102699
102920
|
import { createServer } from "node:http";
|
|
102700
|
-
import { readFileSync
|
|
102921
|
+
import { readFileSync, writeFileSync, existsSync as existsSync2, mkdtempSync, rmSync, readdirSync } from "node:fs";
|
|
102701
102922
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
102702
102923
|
import { join as join2, dirname, resolve, extname, basename } from "node:path";
|
|
102703
|
-
import { fileURLToPath as
|
|
102924
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
102704
102925
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
102705
|
-
var HERE = dirname(
|
|
102926
|
+
var HERE = dirname(fileURLToPath2(import.meta.url));
|
|
102706
102927
|
function fail3(msg) {
|
|
102707
102928
|
console.error(msg);
|
|
102708
102929
|
process.exit(1);
|
|
@@ -102783,8 +103004,8 @@ async function runPreviewCommand(filePath, flags) {
|
|
|
102783
103004
|
"No Chrome/Chromium found. Set CHROME_PATH to a Chrome binary, or install one:\n npx playwright install chromium (then it's auto-detected)\n or install Google Chrome / Chromium via your package manager."
|
|
102784
103005
|
);
|
|
102785
103006
|
}
|
|
102786
|
-
const b64 =
|
|
102787
|
-
const bundle =
|
|
103007
|
+
const b64 = readFileSync(abs2).toString("base64");
|
|
103008
|
+
const bundle = readFileSync(bundlePath, "utf8");
|
|
102788
103009
|
const html = `<!doctype html><html><head><meta charset="utf-8"><style>body{margin:0;background:#fff;font-family:sans-serif}#root{padding:20px;max-width:1240px;margin:0 auto}</style></head><body><div id="root"></div><script>window.__LOTICS_RENDER=${JSON.stringify({ type, b64 })}</script><script src="/render_page.js"></script></body></html>`;
|
|
102789
103010
|
const server = createServer((req, res) => {
|
|
102790
103011
|
if (req.url === "/render_page.js") {
|
|
@@ -102830,7 +103051,7 @@ async function runPreviewCommand(filePath, flags) {
|
|
|
102830
103051
|
const portFile = join2(udd, "DevToolsActivePort");
|
|
102831
103052
|
for (let i2 = 0; i2 < 100 && !cdpPort; i2++) {
|
|
102832
103053
|
if (existsSync2(portFile)) {
|
|
102833
|
-
const p = parseInt(
|
|
103054
|
+
const p = parseInt(readFileSync(portFile, "utf8").split("\n")[0], 10);
|
|
102834
103055
|
if (p) cdpPort = p;
|
|
102835
103056
|
}
|
|
102836
103057
|
if (!cdpPort) await sleep(100);
|
|
@@ -102886,7 +103107,7 @@ async function runPreviewCommand(filePath, flags) {
|
|
|
102886
103107
|
const outPath = flags.output ? resolve(flags.output) : join2(dirname(abs2), basename(abs2, ext) + ".png");
|
|
102887
103108
|
writeFileSync(outPath, Buffer.from(shot.data, "base64"));
|
|
102888
103109
|
console.log(`Rendered ${basename(abs2)} \u2192 ${outPath} (${Math.min(w, MAX_CAPTURE)}\xD7${Math.min(h, MAX_CAPTURE)}, via ${basename(chrome)})`);
|
|
102889
|
-
for (const
|
|
103110
|
+
for (const warn2 of warnings) console.error(` \u26A0 ${warn2}`);
|
|
102890
103111
|
} finally {
|
|
102891
103112
|
cleanup();
|
|
102892
103113
|
}
|
|
@@ -103007,7 +103228,7 @@ Auth flags:
|
|
|
103007
103228
|
signup/api-key write a self-contained ./.lotics/config.json
|
|
103008
103229
|
(inline key) \u2014 for a hermetic worktree or CI.
|
|
103009
103230
|
--name <name> (signup) Display name (defaults to email prefix)
|
|
103010
|
-
--timezone <timezone> (signup) Workspace timezone (defaults to
|
|
103231
|
+
--timezone <timezone> (signup) Workspace timezone (defaults to this machine's, e.g. Asia/Ho_Chi_Minh)
|
|
103011
103232
|
|
|
103012
103233
|
API keys are stored once per org as named profiles in ~/.lotics/config.json.
|
|
103013
103234
|
Registering a second key adds a profile \u2014 it does not overwrite the first.
|
|
@@ -103037,8 +103258,8 @@ function prompt(question) {
|
|
|
103037
103258
|
});
|
|
103038
103259
|
});
|
|
103039
103260
|
}
|
|
103040
|
-
async function publicPost(
|
|
103041
|
-
const response = await fetch(`${API_BASE_URL}${
|
|
103261
|
+
async function publicPost(path13, body) {
|
|
103262
|
+
const response = await fetch(`${API_BASE_URL}${path13}`, {
|
|
103042
103263
|
method: "POST",
|
|
103043
103264
|
headers: { "Content-Type": "application/json" },
|
|
103044
103265
|
body: JSON.stringify(body)
|
|
@@ -103046,35 +103267,74 @@ async function publicPost(path14, body) {
|
|
|
103046
103267
|
const data2 = await response.json();
|
|
103047
103268
|
return { ok: response.ok, status: response.status, data: data2 };
|
|
103048
103269
|
}
|
|
103049
|
-
async function
|
|
103050
|
-
const
|
|
103051
|
-
if (
|
|
103052
|
-
|
|
103053
|
-
|
|
103054
|
-
}
|
|
103055
|
-
const name2 = flags.name ?? (process.stdin.isTTY ? await prompt("Name (enter to use email): ") : void 0);
|
|
103056
|
-
const body = { email: email3 };
|
|
103057
|
-
if (name2) body.name = name2;
|
|
103058
|
-
if (flags.timezone) body.timezone = flags.timezone;
|
|
103270
|
+
async function signupAccount(args) {
|
|
103271
|
+
const body = { email: args.email };
|
|
103272
|
+
if (args.name) body.name = args.name;
|
|
103273
|
+
const timezone = args.timezone ?? machineTimezone();
|
|
103274
|
+
if (timezone) body.timezone = timezone;
|
|
103059
103275
|
const { ok, status, data: data2 } = await publicPost("/v1/cli/signup", body);
|
|
103060
103276
|
if (!ok) {
|
|
103061
103277
|
if (status === 409) {
|
|
103062
|
-
|
|
103063
|
-
|
|
103064
|
-
|
|
103065
|
-
|
|
103066
|
-
|
|
103278
|
+
throw new Error(
|
|
103279
|
+
`An account with ${args.email} already exists.
|
|
103280
|
+
If this machine is already signed in: lotics auth whoami
|
|
103281
|
+
Otherwise take an API key from Settings \u2192 API keys at ${WEB_APP_URL}, then:
|
|
103282
|
+
lotics auth api-key <key>`
|
|
103283
|
+
);
|
|
103067
103284
|
}
|
|
103068
|
-
|
|
103285
|
+
if (status === 429) {
|
|
103286
|
+
throw new Error("Too many signup attempts. Try again later.");
|
|
103287
|
+
}
|
|
103288
|
+
throw new Error(`Signup failed: ${data2.message ?? JSON.stringify(data2)}`);
|
|
103069
103289
|
}
|
|
103070
103290
|
const apiKey = data2.api_key;
|
|
103071
103291
|
const orgId = data2.organization_id;
|
|
103072
103292
|
const workspaceId = data2.workspace_id;
|
|
103073
|
-
const orgName =
|
|
103293
|
+
const orgName = args.name || args.email.split("@")[0];
|
|
103074
103294
|
upsertProfile(orgId, { api_key: apiKey, org_name: orgName, workspace_id: workspaceId });
|
|
103075
103295
|
const existing = loadGlobalConfig() ?? {};
|
|
103076
|
-
saveGlobalConfig({ ...existing, email:
|
|
103077
|
-
setActiveOrg(orgId,
|
|
103296
|
+
saveGlobalConfig({ ...existing, email: args.email });
|
|
103297
|
+
setActiveOrg(orgId, args.local ? "local" : "global");
|
|
103298
|
+
return { email: args.email, apiKey, orgId, orgName, workspaceId };
|
|
103299
|
+
}
|
|
103300
|
+
function alreadySetUp(email3) {
|
|
103301
|
+
const config2 = loadGlobalConfig();
|
|
103302
|
+
if (config2?.email !== email3) return false;
|
|
103303
|
+
return Object.keys(config2.profiles ?? {}).length > 0;
|
|
103304
|
+
}
|
|
103305
|
+
async function handleSignup(positionalEmail, flags) {
|
|
103306
|
+
const email3 = positionalEmail ?? (process.stdin.isTTY ? await prompt("Email: ") : "");
|
|
103307
|
+
if (!email3) {
|
|
103308
|
+
console.error("Email is required. Usage: lotics auth signup <email>");
|
|
103309
|
+
process.exit(1);
|
|
103310
|
+
}
|
|
103311
|
+
if (alreadySetUp(email3)) {
|
|
103312
|
+
console.error(
|
|
103313
|
+
`This machine is already signed in as ${email3} \u2014 no new account needed.
|
|
103314
|
+
Carry on: lotics starter list
|
|
103315
|
+
Which account: lotics auth whoami` + // `--local` asked for a pin, and returning early gives none. Saying
|
|
103316
|
+
// nothing would leave a flag silently ignored, which is worse than the
|
|
103317
|
+
// 409 this replaced.
|
|
103318
|
+
(flags.local === true ? `
|
|
103319
|
+
--local pins a directory to an org, which signup does not do for an
|
|
103320
|
+
account that exists \u2014 use: lotics org use <name|id> --local` : "")
|
|
103321
|
+
);
|
|
103322
|
+
return;
|
|
103323
|
+
}
|
|
103324
|
+
const name2 = flags.name ?? (process.stdin.isTTY ? await prompt("Name (enter to use email): ") : void 0);
|
|
103325
|
+
let account;
|
|
103326
|
+
try {
|
|
103327
|
+
account = await signupAccount({
|
|
103328
|
+
email: email3,
|
|
103329
|
+
...name2 ? { name: name2 } : {},
|
|
103330
|
+
...flags.timezone ? { timezone: flags.timezone } : {},
|
|
103331
|
+
...flags.local === true ? { local: true } : {}
|
|
103332
|
+
});
|
|
103333
|
+
} catch (error52) {
|
|
103334
|
+
console.error(error52 instanceof Error ? error52.message : String(error52));
|
|
103335
|
+
process.exit(1);
|
|
103336
|
+
}
|
|
103337
|
+
const { orgId, orgName } = account;
|
|
103078
103338
|
console.error(`Account created. You can now use the CLI.`);
|
|
103079
103339
|
console.error(` Email: ${email3}`);
|
|
103080
103340
|
console.error(` Org: ${orgName} (${orgId})`);
|
|
@@ -103206,13 +103466,13 @@ async function resolveWorkspace(client, ctx) {
|
|
|
103206
103466
|
function resolveUploadPaths(rawPaths) {
|
|
103207
103467
|
const result = [];
|
|
103208
103468
|
for (const p of rawPaths) {
|
|
103209
|
-
const resolved =
|
|
103469
|
+
const resolved = path12.resolve(p);
|
|
103210
103470
|
const stat = fs14.statSync(resolved);
|
|
103211
103471
|
if (stat.isDirectory()) {
|
|
103212
103472
|
const entries2 = fs14.readdirSync(resolved, { withFileTypes: true });
|
|
103213
103473
|
for (const entry of entries2) {
|
|
103214
103474
|
if (entry.isFile()) {
|
|
103215
|
-
result.push(
|
|
103475
|
+
result.push(path12.join(resolved, entry.name));
|
|
103216
103476
|
}
|
|
103217
103477
|
}
|
|
103218
103478
|
} else {
|
|
@@ -103261,8 +103521,65 @@ async function main() {
|
|
|
103261
103521
|
console.log(VERSION);
|
|
103262
103522
|
return;
|
|
103263
103523
|
}
|
|
103524
|
+
if (command === "start") {
|
|
103525
|
+
const starterId = subcommand;
|
|
103526
|
+
if (!starterId) {
|
|
103527
|
+
console.error("Usage: lotics start <starter_id> [path] [--email <you@co.com>] [--json]");
|
|
103528
|
+
console.error(" Creates an account if this machine has none, then copies the starter");
|
|
103529
|
+
console.error(" into its workspace: schema, templates, knowledge docs, sample records");
|
|
103530
|
+
console.error(" and a deployed app. Ends with a one-time sign-in link.");
|
|
103531
|
+
console.error(" --json prints one object and nothing else.");
|
|
103532
|
+
process.exit(1);
|
|
103533
|
+
}
|
|
103534
|
+
if (flags.json) setMachineOutput(true);
|
|
103535
|
+
const existing = resolveContext(flags);
|
|
103536
|
+
if (existing === null) {
|
|
103537
|
+
const email3 = flags.email ?? (process.stdin.isTTY ? await prompt("Email: ") : "");
|
|
103538
|
+
if (!email3) {
|
|
103539
|
+
console.error(
|
|
103540
|
+
"This machine has no Lotics credential yet, so `start` needs an email to create one:\n lotics start " + starterId + " --email you@company.com"
|
|
103541
|
+
);
|
|
103542
|
+
process.exit(1);
|
|
103543
|
+
}
|
|
103544
|
+
try {
|
|
103545
|
+
const account = await signupAccount({
|
|
103546
|
+
email: email3,
|
|
103547
|
+
...flags.name ? { name: flags.name } : {},
|
|
103548
|
+
...flags.timezone ? { timezone: flags.timezone } : {},
|
|
103549
|
+
...flags.local === true ? { local: true } : {}
|
|
103550
|
+
});
|
|
103551
|
+
note(`Account created for ${account.email} \u2014 org ${account.orgName} (${account.orgId}).`);
|
|
103552
|
+
} catch (error52) {
|
|
103553
|
+
console.error(error52 instanceof Error ? error52.message : String(error52));
|
|
103554
|
+
process.exit(1);
|
|
103555
|
+
}
|
|
103556
|
+
} else if (flags.email !== void 0) {
|
|
103557
|
+
console.error(
|
|
103558
|
+
`Already authenticated (${SOURCE_LABELS[existing.source]}), so --email would create a SECOND account and copy into it.
|
|
103559
|
+
Copy into the account you have: lotics start ${starterId}
|
|
103560
|
+
Or create another one first: lotics auth signup ${flags.email}`
|
|
103561
|
+
);
|
|
103562
|
+
process.exit(1);
|
|
103563
|
+
}
|
|
103564
|
+
const { client: client2, ctx: ctx2 } = requireClient(flags);
|
|
103565
|
+
await resolveWorkspace(client2, ctx2);
|
|
103566
|
+
const result = await starterInit(client2, {
|
|
103567
|
+
starter_id: starterId,
|
|
103568
|
+
...toolArgs !== void 0 ? { targetPath: toolArgs } : {},
|
|
103569
|
+
...flags.noSampleData === true ? { noSampleData: true } : {},
|
|
103570
|
+
...flags.adopt === true ? { adopt: true } : {}
|
|
103571
|
+
});
|
|
103572
|
+
if (flags.json) {
|
|
103573
|
+
emitJson({ organization_id: ctx2.orgId, workspace_id: ctx2.workspaceId, ...result });
|
|
103574
|
+
}
|
|
103575
|
+
return;
|
|
103576
|
+
}
|
|
103264
103577
|
if (command === "starter") {
|
|
103265
103578
|
if (subcommand === "list") {
|
|
103579
|
+
if (resolveContext(flags) === null) {
|
|
103580
|
+
await starterListPublic();
|
|
103581
|
+
return;
|
|
103582
|
+
}
|
|
103266
103583
|
const { client: client2, ctx: ctx2 } = requireClient(flags);
|
|
103267
103584
|
await resolveWorkspace(client2, ctx2);
|
|
103268
103585
|
await starterList(client2);
|
|
@@ -103286,14 +103603,18 @@ async function main() {
|
|
|
103286
103603
|
console.error(" locally, so it needs node and a few minutes.");
|
|
103287
103604
|
process.exit(1);
|
|
103288
103605
|
}
|
|
103606
|
+
if (flags.json) setMachineOutput(true);
|
|
103289
103607
|
const { client: client2, ctx: ctx2 } = requireClient(flags);
|
|
103290
103608
|
await resolveWorkspace(client2, ctx2);
|
|
103291
|
-
await starterInit(client2, {
|
|
103609
|
+
const result = await starterInit(client2, {
|
|
103292
103610
|
starter_id: toolArgs,
|
|
103293
103611
|
...restArgs[0] !== void 0 ? { targetPath: restArgs[0] } : {},
|
|
103294
103612
|
...flags.noSampleData === true ? { noSampleData: true } : {},
|
|
103295
103613
|
...flags.adopt === true ? { adopt: true } : {}
|
|
103296
103614
|
});
|
|
103615
|
+
if (flags.json) {
|
|
103616
|
+
emitJson({ organization_id: ctx2.orgId, workspace_id: ctx2.workspaceId, ...result });
|
|
103617
|
+
}
|
|
103297
103618
|
return;
|
|
103298
103619
|
}
|
|
103299
103620
|
if (subcommand === "fixtures") {
|
|
@@ -103464,7 +103785,7 @@ async function main() {
|
|
|
103464
103785
|
if (command === "preview") {
|
|
103465
103786
|
if (subcommand && isStoredFileId(subcommand)) {
|
|
103466
103787
|
const { client: client2 } = requireClient(flags);
|
|
103467
|
-
const tmpDir = fs14.mkdtempSync(
|
|
103788
|
+
const tmpDir = fs14.mkdtempSync(path12.join(os4.tmpdir(), "lotics-preview-"));
|
|
103468
103789
|
try {
|
|
103469
103790
|
const { path: localPath, filename } = await client2.downloadFileById(subcommand, tmpDir);
|
|
103470
103791
|
const output = flags.output ?? defaultPreviewOutputPath(filename, process.cwd());
|
|
@@ -104067,6 +104388,7 @@ ${JSON.stringify(info.input_schema, null, 2)}`);
|
|
|
104067
104388
|
}
|
|
104068
104389
|
}
|
|
104069
104390
|
main().then(() => checkForUpdate(VERSION)).catch((error52) => {
|
|
104391
|
+
flushPendingWarnings();
|
|
104070
104392
|
console.error(describeCliError(error52));
|
|
104071
104393
|
process.exit(1);
|
|
104072
104394
|
});
|