@lotics/cli 0.136.0 → 0.142.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/AGENTS.md +20 -1
- package/README.md +47 -0
- package/dist/src/cli.js +2135 -419
- package/dist/src/client.d.ts +20 -0
- package/dist/src/client.js +8 -0
- package/docs/building_an_app.md +229 -0
- package/docs/cli_reference.md +6 -2
- package/docs/document_templates.md +3 -3
- package/package.json +1 -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(path12, nextNode) {
|
|
26826
|
+
utils_1.forEach(path12, 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 = path12.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, path12) {
|
|
28594
28594
|
var _this = _super.call(this) || this;
|
|
28595
28595
|
_this.topProd = topProd;
|
|
28596
|
-
_this.path =
|
|
28596
|
+
_this.path = path12;
|
|
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, path12) {
|
|
28651
|
+
var _this = _super.call(this, topProd, path12) || this;
|
|
28652
|
+
_this.path = path12;
|
|
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(path12) {
|
|
29350
29350
|
var keys3 = [""];
|
|
29351
|
-
for (var i2 = 0; i2 <
|
|
29352
|
-
var tokType =
|
|
29351
|
+
for (var i2 = 0; i2 < path12.length; i2++) {
|
|
29352
|
+
var tokType = path12[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, path12) {
|
|
29665
|
+
if (path12 === void 0) {
|
|
29666
|
+
path12 = [];
|
|
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: path12
|
|
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, path12.concat([topRule]));
|
|
29686
29686
|
var errorsFromNextSteps = utils2.map(validNextSteps, function(currRefRule) {
|
|
29687
|
-
var newPath = utils2.cloneArr(
|
|
29687
|
+
var newPath = utils2.cloneArr(path12);
|
|
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(path12) {
|
|
37297
|
+
var parts = path12.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(path12) {
|
|
43151
|
+
if (path12.slice(-1) === "/") {
|
|
43152
|
+
path12 = path12.substring(0, path12.length - 1);
|
|
43153
43153
|
}
|
|
43154
|
-
var lastSlash =
|
|
43155
|
-
return lastSlash > 0 ?
|
|
43154
|
+
var lastSlash = path12.lastIndexOf("/");
|
|
43155
|
+
return lastSlash > 0 ? path12.substring(0, lastSlash) : "";
|
|
43156
43156
|
};
|
|
43157
|
-
var forceTrailingSlash = function(
|
|
43158
|
-
if (
|
|
43159
|
-
|
|
43157
|
+
var forceTrailingSlash = function(path12) {
|
|
43158
|
+
if (path12.slice(-1) !== "/") {
|
|
43159
|
+
path12 += "/";
|
|
43160
43160
|
}
|
|
43161
|
-
return
|
|
43161
|
+
return path12;
|
|
43162
43162
|
};
|
|
43163
43163
|
var folderAdd = function(name2, createFolders) {
|
|
43164
43164
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults2.createFolders;
|
|
@@ -44160,9 +44160,9 @@ var require_lib4 = __commonJS({
|
|
|
44160
44160
|
// src/cli.ts
|
|
44161
44161
|
import dns from "node:dns";
|
|
44162
44162
|
import net2 from "node:net";
|
|
44163
|
-
import
|
|
44163
|
+
import fs13 from "node:fs";
|
|
44164
44164
|
import os4 from "node:os";
|
|
44165
|
-
import
|
|
44165
|
+
import path11 from "node:path";
|
|
44166
44166
|
import readline from "node:readline";
|
|
44167
44167
|
|
|
44168
44168
|
// ../shared/src/transport_error.ts
|
|
@@ -44345,8 +44345,8 @@ var LoticsClient = class {
|
|
|
44345
44345
|
}
|
|
44346
44346
|
return headers;
|
|
44347
44347
|
}
|
|
44348
|
-
async request(method,
|
|
44349
|
-
const url2 = `${this.baseUrl}${
|
|
44348
|
+
async request(method, path12, body) {
|
|
44349
|
+
const url2 = `${this.baseUrl}${path12}`;
|
|
44350
44350
|
const headers = this.buildHeaders();
|
|
44351
44351
|
const init = { method, headers };
|
|
44352
44352
|
if (body !== void 0) {
|
|
@@ -44360,6 +44360,14 @@ var LoticsClient = class {
|
|
|
44360
44360
|
async whoami() {
|
|
44361
44361
|
return this.request("GET", "/v1/cli/whoami");
|
|
44362
44362
|
}
|
|
44363
|
+
/**
|
|
44364
|
+
* File a hand-written report. Unlike a telemetry flush, the headers this
|
|
44365
|
+
* stamps are CORRECT: the invocation making the request is the one the report
|
|
44366
|
+
* is about, so the courier and the cargo are the same session.
|
|
44367
|
+
*/
|
|
44368
|
+
async sendReport(body) {
|
|
44369
|
+
return this.request("POST", "/v1/cli/report", body);
|
|
44370
|
+
}
|
|
44363
44371
|
setWorkspaceId(id) {
|
|
44364
44372
|
this.workspaceId = id;
|
|
44365
44373
|
}
|
|
@@ -45614,9 +45622,422 @@ var pkgPath = path5.resolve(path5.dirname(fileURLToPath(import.meta.url)), "../.
|
|
|
45614
45622
|
var pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
45615
45623
|
var VERSION = pkg.version;
|
|
45616
45624
|
|
|
45617
|
-
// src/
|
|
45625
|
+
// src/docs_command.ts
|
|
45626
|
+
import fs5 from "node:fs";
|
|
45627
|
+
import path6 from "node:path";
|
|
45628
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
45629
|
+
var READING_ORDER = ["@lotics/app-sdk", "@lotics/ui", "@lotics/cli"];
|
|
45630
|
+
function firstHeading(file2) {
|
|
45631
|
+
let text;
|
|
45632
|
+
try {
|
|
45633
|
+
text = fs5.readFileSync(file2, "utf-8");
|
|
45634
|
+
} catch {
|
|
45635
|
+
return "";
|
|
45636
|
+
}
|
|
45637
|
+
for (const line of text.split("\n", 40)) {
|
|
45638
|
+
const m = /^#\s+(.+?)\s*$/.exec(line);
|
|
45639
|
+
if (m) return m[1];
|
|
45640
|
+
}
|
|
45641
|
+
return "";
|
|
45642
|
+
}
|
|
45643
|
+
function readVersion(pkgDir) {
|
|
45644
|
+
try {
|
|
45645
|
+
const raw = fs5.readFileSync(path6.join(pkgDir, "package.json"), "utf-8");
|
|
45646
|
+
return JSON.parse(raw).version ?? "?";
|
|
45647
|
+
} catch {
|
|
45648
|
+
return "?";
|
|
45649
|
+
}
|
|
45650
|
+
}
|
|
45651
|
+
function ownPackageDir() {
|
|
45652
|
+
return path6.resolve(path6.dirname(fileURLToPath2(import.meta.url)), "../..");
|
|
45653
|
+
}
|
|
45654
|
+
function referencePackageDirs(projectDir) {
|
|
45655
|
+
const found = /* @__PURE__ */ new Map();
|
|
45656
|
+
for (let dir = projectDir; ; ) {
|
|
45657
|
+
const scope = path6.join(dir, "node_modules", "@lotics");
|
|
45658
|
+
if (fs5.existsSync(scope)) {
|
|
45659
|
+
for (const name2 of fs5.readdirSync(scope)) {
|
|
45660
|
+
const pkgDir = path6.join(scope, name2);
|
|
45661
|
+
const carries = fs5.existsSync(path6.join(pkgDir, "AGENTS.md")) || fs5.existsSync(path6.join(pkgDir, "docs"));
|
|
45662
|
+
if (carries && !found.has(`@lotics/${name2}`)) found.set(`@lotics/${name2}`, pkgDir);
|
|
45663
|
+
}
|
|
45664
|
+
}
|
|
45665
|
+
const parent = path6.dirname(dir);
|
|
45666
|
+
if (parent === dir) break;
|
|
45667
|
+
dir = parent;
|
|
45668
|
+
}
|
|
45669
|
+
const own = ownPackageDir();
|
|
45670
|
+
if (!found.has("@lotics/cli") && fs5.existsSync(path6.join(own, "AGENTS.md"))) {
|
|
45671
|
+
found.set("@lotics/cli", own);
|
|
45672
|
+
}
|
|
45673
|
+
return [...found.entries()].map(([pkg2, dir]) => ({ pkg: pkg2, dir })).sort((a, b) => {
|
|
45674
|
+
const ia = READING_ORDER.indexOf(a.pkg);
|
|
45675
|
+
const ib = READING_ORDER.indexOf(b.pkg);
|
|
45676
|
+
if (ia !== ib) return (ia < 0 ? READING_ORDER.length : ia) - (ib < 0 ? READING_ORDER.length : ib);
|
|
45677
|
+
return a.pkg.localeCompare(b.pkg);
|
|
45678
|
+
});
|
|
45679
|
+
}
|
|
45680
|
+
function collectDocAreas(projectDir) {
|
|
45681
|
+
const found = [];
|
|
45682
|
+
for (const { pkg: pkg2, dir } of referencePackageDirs(projectDir)) {
|
|
45683
|
+
const version2 = readVersion(dir);
|
|
45684
|
+
const index = path6.join(dir, "AGENTS.md");
|
|
45685
|
+
if (fs5.existsSync(index)) {
|
|
45686
|
+
found.push({
|
|
45687
|
+
area: pkg2.replace("@lotics/", ""),
|
|
45688
|
+
pkg: pkg2,
|
|
45689
|
+
version: version2,
|
|
45690
|
+
absPath: index,
|
|
45691
|
+
title: firstHeading(index)
|
|
45692
|
+
});
|
|
45693
|
+
}
|
|
45694
|
+
const docsDir = path6.join(dir, "docs");
|
|
45695
|
+
if (!fs5.existsSync(docsDir)) continue;
|
|
45696
|
+
for (const file2 of fs5.readdirSync(docsDir).sort()) {
|
|
45697
|
+
if (!file2.endsWith(".md")) continue;
|
|
45698
|
+
const abs2 = path6.join(docsDir, file2);
|
|
45699
|
+
found.push({
|
|
45700
|
+
area: file2.replace(/\.md$/, ""),
|
|
45701
|
+
pkg: pkg2,
|
|
45702
|
+
version: version2,
|
|
45703
|
+
absPath: abs2,
|
|
45704
|
+
title: firstHeading(abs2)
|
|
45705
|
+
});
|
|
45706
|
+
}
|
|
45707
|
+
}
|
|
45708
|
+
return found;
|
|
45709
|
+
}
|
|
45710
|
+
function qualified(a) {
|
|
45711
|
+
return `${a.pkg.replace("@lotics/", "")}/${a.area}`;
|
|
45712
|
+
}
|
|
45713
|
+
function matchDocArea(areas, query) {
|
|
45714
|
+
const q = query.trim().toLowerCase().replace(/\.md$/, "");
|
|
45715
|
+
const exact = areas.filter((a) => a.area.toLowerCase() === q || qualified(a).toLowerCase() === q);
|
|
45716
|
+
if (exact.length > 0) return exact;
|
|
45717
|
+
return areas.filter((a) => a.area.toLowerCase().includes(q));
|
|
45718
|
+
}
|
|
45719
|
+
function onlySelfReference(areas) {
|
|
45720
|
+
return areas.length > 0 && areas.every((a) => a.pkg === "@lotics/cli");
|
|
45721
|
+
}
|
|
45722
|
+
function renderDocIndex(areas) {
|
|
45723
|
+
if (areas.length === 0) {
|
|
45724
|
+
return "No reference packages resolved here.\n The references ship INSIDE the packages, so they appear once a project installs them:\n @lotics/app-sdk, @lotics/ui \u2014 run this from an app directory (see `lotics app create`).";
|
|
45725
|
+
}
|
|
45726
|
+
const lines = [];
|
|
45727
|
+
let currentPkg = "";
|
|
45728
|
+
for (const a of areas) {
|
|
45729
|
+
if (a.pkg !== currentPkg) {
|
|
45730
|
+
currentPkg = a.pkg;
|
|
45731
|
+
lines.push(`
|
|
45732
|
+
${a.pkg} ${a.version}`);
|
|
45733
|
+
}
|
|
45734
|
+
const name2 = a.absPath.endsWith("AGENTS.md") ? `${a.area} \u2190 start here` : a.area;
|
|
45735
|
+
lines.push(` ${name2.padEnd(24)}${a.title}`);
|
|
45736
|
+
}
|
|
45737
|
+
lines.push("\n lotics docs <area> print one, e.g. `lotics docs ai`");
|
|
45738
|
+
lines.push(" lotics docs <pkg>/<area> when two packages share a name");
|
|
45739
|
+
lines.push("\n Versions are the INSTALLED ones; a doc describes the version beside it.");
|
|
45740
|
+
if (onlySelfReference(areas)) {
|
|
45741
|
+
lines.push(
|
|
45742
|
+
"\n Only this CLI's own reference resolved here \u2014 the @lotics/app-sdk and @lotics/ui\n references are NOT among them. They ship inside those packages, so they appear\n once a project installs them: `lotics app create <name>` scaffolds one with both."
|
|
45743
|
+
);
|
|
45744
|
+
}
|
|
45745
|
+
return lines.join("\n");
|
|
45746
|
+
}
|
|
45747
|
+
function docsCommand(args) {
|
|
45748
|
+
const projectDir = path6.resolve(args.projectDir ?? process.cwd());
|
|
45749
|
+
const areas = collectDocAreas(projectDir);
|
|
45750
|
+
if (args.area === void 0 || args.area === "") {
|
|
45751
|
+
console.log(renderDocIndex(areas));
|
|
45752
|
+
return;
|
|
45753
|
+
}
|
|
45754
|
+
const hits = matchDocArea(areas, args.area);
|
|
45755
|
+
if (hits.length === 0) {
|
|
45756
|
+
console.error(
|
|
45757
|
+
`No reference area matching "${args.area}".
|
|
45758
|
+
Run \`lotics docs\` for what is installed here.`
|
|
45759
|
+
);
|
|
45760
|
+
process.exit(1);
|
|
45761
|
+
}
|
|
45762
|
+
if (hits.length > 1) {
|
|
45763
|
+
console.error(
|
|
45764
|
+
`"${args.area}" matches more than one reference \u2014 name the package:
|
|
45765
|
+
` + hits.map((a) => ` \u2022 lotics docs ${qualified(a)} (${a.pkg} ${a.version})`).join("\n")
|
|
45766
|
+
);
|
|
45767
|
+
process.exit(1);
|
|
45768
|
+
}
|
|
45769
|
+
const hit = hits[0];
|
|
45770
|
+
console.error(`${hit.pkg} ${hit.version} \xB7 ${path6.relative(projectDir, hit.absPath)}
|
|
45771
|
+
`);
|
|
45772
|
+
process.stdout.write(fs5.readFileSync(hit.absPath, "utf-8"));
|
|
45773
|
+
}
|
|
45774
|
+
|
|
45775
|
+
// src/commands.ts
|
|
45776
|
+
var COMMANDS = [
|
|
45777
|
+
{
|
|
45778
|
+
verbs: ["org"],
|
|
45779
|
+
help: [
|
|
45780
|
+
" lotics org List saved orgs (marks active)",
|
|
45781
|
+
" lotics org use <name|id> [--local] Switch active org (--local pins this dir)"
|
|
45782
|
+
]
|
|
45783
|
+
},
|
|
45784
|
+
{
|
|
45785
|
+
verbs: ["workspace"],
|
|
45786
|
+
help: [
|
|
45787
|
+
" lotics workspace List workspaces in the active org (marks current)",
|
|
45788
|
+
" lotics workspace select <id> Switch to a different workspace",
|
|
45789
|
+
" lotics workspace create <name> Create a new workspace (admin only)",
|
|
45790
|
+
" lotics workspace delete <id> --yes Delete a workspace (admin only; soft delete, recoverable)",
|
|
45791
|
+
" lotics workspace doctor Report dangling schema references (admin only)"
|
|
45792
|
+
]
|
|
45793
|
+
},
|
|
45794
|
+
{
|
|
45795
|
+
verbs: ["tools"],
|
|
45796
|
+
help: [
|
|
45797
|
+
" lotics tools List all available tools",
|
|
45798
|
+
" lotics tools <name> Show tool description and input schema"
|
|
45799
|
+
]
|
|
45800
|
+
},
|
|
45801
|
+
{
|
|
45802
|
+
verbs: ["install"],
|
|
45803
|
+
help: [" lotics install <package_id> Materialize a published package into this workspace"]
|
|
45804
|
+
},
|
|
45805
|
+
{
|
|
45806
|
+
verbs: ["upgrade"],
|
|
45807
|
+
help: [" lotics upgrade Take the installed package's next version"]
|
|
45808
|
+
},
|
|
45809
|
+
{
|
|
45810
|
+
verbs: ["docs"],
|
|
45811
|
+
help: [
|
|
45812
|
+
" lotics docs List the reference docs of the INSTALLED packages",
|
|
45813
|
+
" lotics docs <area> Print one (e.g. 'lotics docs ai')"
|
|
45814
|
+
]
|
|
45815
|
+
},
|
|
45816
|
+
{
|
|
45817
|
+
verbs: ["report"],
|
|
45818
|
+
help: [
|
|
45819
|
+
" lotics report '<json>' Tell the Lotics team what got in your way \u2014 a",
|
|
45820
|
+
" capability that is missing, a command that",
|
|
45821
|
+
" succeeded but did the wrong thing, an error that",
|
|
45822
|
+
" did not say how to fix it. Nothing else records",
|
|
45823
|
+
" these. A frame, not a paragraph: {goal, actual,",
|
|
45824
|
+
" expected?, tried?, wanted?} \u2014 run it bare for the",
|
|
45825
|
+
" full prompt. Also @file.json, or '-' for stdin"
|
|
45826
|
+
]
|
|
45827
|
+
},
|
|
45828
|
+
{
|
|
45829
|
+
verbs: ["run"],
|
|
45830
|
+
help: [
|
|
45831
|
+
" lotics run <tool> '<json>' Execute a tool",
|
|
45832
|
+
" lotics run <tool> @args.json Read JSON args from a file (large payloads)",
|
|
45833
|
+
" cat args.json | lotics run <tool> Read JSON args from stdin (large payloads)"
|
|
45834
|
+
]
|
|
45835
|
+
},
|
|
45836
|
+
{
|
|
45837
|
+
verbs: ["app"],
|
|
45838
|
+
help: [
|
|
45839
|
+
" lotics app create <name> [path] Create a new custom-code app + scaffold locally",
|
|
45840
|
+
" lotics app pull <app_id> [path] Bootstrap full local env (source + npm install + types)",
|
|
45841
|
+
" lotics app deploy -m <message> Build + upload current dir as a new version \u2014 COMMIT",
|
|
45842
|
+
" (-m is required \u2014 it's the version's audit trail;",
|
|
45843
|
+
" carries code + queries only \u2014 workflow bindings are",
|
|
45844
|
+
" managed by set_app_workflow / remove_app_workflow)",
|
|
45845
|
+
" lotics app versions [app_id] Show deploy history newest-first (version,",
|
|
45846
|
+
" timestamp, deployer, build status, -m message;",
|
|
45847
|
+
" * marks the currently served version)",
|
|
45848
|
+
" lotics app codegen [path] Regenerate .lotics/* (types + field/option ids)",
|
|
45849
|
+
" from the manifest + workspace schema \u2014 no deploy",
|
|
45850
|
+
" lotics app check Run every deploy pre-flight WITHOUT building or",
|
|
45851
|
+
" shipping: agent schemas vs the live app, workflow",
|
|
45852
|
+
" declarations and BODIES vs what is live, aliases",
|
|
45853
|
+
" the code calls but nothing bound, undeclared",
|
|
45854
|
+
" capabilities, query drift. Exits 1 on what a",
|
|
45855
|
+
" deploy would refuse, so CI can gate on it",
|
|
45856
|
+
" lotics app workflow run <alias> '<json>' Execute a bound app workflow end-to-end",
|
|
45857
|
+
" (inputs: inline JSON, @file, or stdin;",
|
|
45858
|
+
" --print-created reports created records +",
|
|
45859
|
+
" a paste-ready cleanup plan; --cleanup also",
|
|
45860
|
+
" deletes those records \u2014 NOT a rollback)",
|
|
45861
|
+
" lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body",
|
|
45862
|
+
" through set_app_workflow (server verifies)",
|
|
45863
|
+
" lotics app workflow pull Rewrite src/workflows/*.ts from the server",
|
|
45864
|
+
" lotics app workflow check [alias] Typecheck src/workflows bodies locally (one",
|
|
45865
|
+
" isolated program per alias; the app's own tsc)",
|
|
45866
|
+
" lotics app query set <alias> Push package.json#lotics.queries.<alias> to",
|
|
45867
|
+
" apps.queries via set_app_query (no deploy;",
|
|
45868
|
+
" re-synced by the next deploy from the manifest)",
|
|
45869
|
+
" lotics app agent run <app_id> <alias> '<json>' Run a bound app agent end-to-end",
|
|
45870
|
+
" (inputs: inline JSON, @file, or stdin; streams",
|
|
45871
|
+
" progress to stderr, reports the settled run;",
|
|
45872
|
+
" --session <id> continues a thread; --json)",
|
|
45873
|
+
" lotics app agent set <alias> Push the edited src/agents/<alias>.md instructions,",
|
|
45874
|
+
" and ONLY those \u2014 the server merges, so the typed",
|
|
45875
|
+
" fields keep whatever is bound (a manifest is a",
|
|
45876
|
+
" snapshot; replaying it would revert them). Change",
|
|
45877
|
+
" those with set_app_agent, then pull.",
|
|
45878
|
+
" lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address",
|
|
45879
|
+
` lotics app rename "<new name>" Rename the app's display name (launcher title)`,
|
|
45880
|
+
" lotics app dev [path] Run the app locally with HMR (RPC forwarded to prod)"
|
|
45881
|
+
]
|
|
45882
|
+
},
|
|
45883
|
+
{
|
|
45884
|
+
verbs: ["knowledge"],
|
|
45885
|
+
help: [
|
|
45886
|
+
" lotics knowledge list List knowledge docs (id, name, description)",
|
|
45887
|
+
" lotics knowledge create --name <n> [--description <d>] --from <file.md>",
|
|
45888
|
+
" Create a doc from a file (or --content <str>);",
|
|
45889
|
+
" prints the new id",
|
|
45890
|
+
" lotics knowledge get <id> [-o <file.md>]",
|
|
45891
|
+
" Fetch a doc's content (to a file, or stdout;",
|
|
45892
|
+
" --json for the full doc)",
|
|
45893
|
+
" lotics knowledge update <id> [--from <file.md> | --content <str>] [--name <n>] [--description <d>]",
|
|
45894
|
+
" Update a doc \u2014 sends only the fields you pass",
|
|
45895
|
+
" lotics knowledge rm <id> Archive a doc"
|
|
45896
|
+
]
|
|
45897
|
+
},
|
|
45898
|
+
{
|
|
45899
|
+
verbs: ["xlsx"],
|
|
45900
|
+
help: [
|
|
45901
|
+
" lotics xlsx <subcommand> ... Read/write/edit .xlsx files on your local filesystem",
|
|
45902
|
+
" (uses the bundled Lotics xlsx engine; prefer over",
|
|
45903
|
+
" npm xlsx/exceljs for round-trip fidelity)"
|
|
45904
|
+
]
|
|
45905
|
+
},
|
|
45906
|
+
{
|
|
45907
|
+
verbs: ["docx"],
|
|
45908
|
+
help: [
|
|
45909
|
+
" lotics docx <subcommand> ... Read/write/edit .docx files on your local filesystem",
|
|
45910
|
+
" (uses the bundled Lotics OOXML engine; preserves",
|
|
45911
|
+
" tables, images, and unknown markup verbatim)"
|
|
45912
|
+
]
|
|
45913
|
+
},
|
|
45914
|
+
{
|
|
45915
|
+
// `file` is a noun-group whose three verbs also stand alone.
|
|
45916
|
+
verbs: ["file"],
|
|
45917
|
+
aliases: ["upload", "download", "preview"],
|
|
45918
|
+
help: [
|
|
45919
|
+
" lotics file upload <file|dir...> Upload files (alias: lotics upload)",
|
|
45920
|
+
" lotics file download <file_id> Download a file by ID (alias: lotics download)",
|
|
45921
|
+
" lotics file download record <record_id> <field_key>",
|
|
45922
|
+
" Download all files on a record file field",
|
|
45923
|
+
" lotics file preview <file|fil_id> [-o png]",
|
|
45924
|
+
" Render a .docx/.xlsx to a PNG \u2014 a local path OR a",
|
|
45925
|
+
" stored file id (downloaded first). Frontend engines;",
|
|
45926
|
+
" needs a Chrome/Chromium on the machine"
|
|
45927
|
+
]
|
|
45928
|
+
}
|
|
45929
|
+
];
|
|
45930
|
+
function renderCommandsHelp() {
|
|
45931
|
+
return COMMANDS.flatMap((group) => group.help).join("\n");
|
|
45932
|
+
}
|
|
45933
|
+
function knownVerbs() {
|
|
45934
|
+
return new Set(COMMANDS.flatMap((group) => [...group.verbs, ...group.aliases ?? []]));
|
|
45935
|
+
}
|
|
45936
|
+
|
|
45937
|
+
// src/report_command.ts
|
|
45618
45938
|
import fs6 from "node:fs";
|
|
45619
45939
|
import path7 from "node:path";
|
|
45940
|
+
var LIMITS = { goal: 2e3, expected: 2e3, actual: 4e3, tried: 4e3, wanted: 2e3 };
|
|
45941
|
+
var REPORT_USAGE = `Usage: lotics report '<json>' lotics report @report.json \u2026 | lotics report -
|
|
45942
|
+
|
|
45943
|
+
Tell the Lotics team what got in your way. Most valuable, in order:
|
|
45944
|
+
|
|
45945
|
+
\u2022 A capability that seems missing \u2014 "there is no way to <X>".
|
|
45946
|
+
Nothing else can see this: no command ran, so nothing was recorded.
|
|
45947
|
+
\u2022 A command that succeeded but did the wrong thing. Exit 0 hides it completely.
|
|
45948
|
+
\u2022 An error message that did not name the remedy.
|
|
45949
|
+
\u2022 Anything that made authoring slower than it should have been.
|
|
45950
|
+
|
|
45951
|
+
The report is a frame, not a paragraph \u2014 these are the facts that exist only
|
|
45952
|
+
where you are sitting. The commands you ran attach themselves; do not retype them.
|
|
45953
|
+
|
|
45954
|
+
{
|
|
45955
|
+
"goal": "what you were trying to accomplish", (required)
|
|
45956
|
+
"actual": "what happened instead", (required)
|
|
45957
|
+
"expected": "what you expected \u2014 the gap is the defect",
|
|
45958
|
+
"tried": "what you already tried, and what it said",
|
|
45959
|
+
"wanted": "what would have unblocked you"
|
|
45960
|
+
}
|
|
45961
|
+
|
|
45962
|
+
There is no severity or category to pick. How bad and how common are read off
|
|
45963
|
+
the corpus; what you were trying to do is not recoverable from anywhere else.
|
|
45964
|
+
|
|
45965
|
+
Do not paste customer records, file contents, or credentials.`;
|
|
45966
|
+
function parseReport(raw) {
|
|
45967
|
+
const text = raw.trim();
|
|
45968
|
+
if (text === "") return { error: "Nothing to report." };
|
|
45969
|
+
let parsed;
|
|
45970
|
+
try {
|
|
45971
|
+
parsed = JSON.parse(text);
|
|
45972
|
+
} catch {
|
|
45973
|
+
return {
|
|
45974
|
+
error: text.startsWith("{") ? "That is not valid JSON." : "A report is a JSON object, not a sentence \u2014 the frame below is what makes it debuggable."
|
|
45975
|
+
};
|
|
45976
|
+
}
|
|
45977
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
45978
|
+
return { error: "A report is a JSON object." };
|
|
45979
|
+
}
|
|
45980
|
+
const fields = parsed;
|
|
45981
|
+
const read = (key) => {
|
|
45982
|
+
const value2 = fields[key];
|
|
45983
|
+
if (value2 === void 0 || value2 === null) return void 0;
|
|
45984
|
+
if (typeof value2 !== "string") return void 0;
|
|
45985
|
+
const trimmed = value2.trim();
|
|
45986
|
+
return trimmed === "" ? void 0 : trimmed.slice(0, LIMITS[key]);
|
|
45987
|
+
};
|
|
45988
|
+
const goal = read("goal");
|
|
45989
|
+
const actual = read("actual");
|
|
45990
|
+
const missing = [goal === void 0 ? "goal" : "", actual === void 0 ? "actual" : ""].filter(
|
|
45991
|
+
(k) => k !== ""
|
|
45992
|
+
);
|
|
45993
|
+
if (goal === void 0 || actual === void 0) {
|
|
45994
|
+
return { error: `A report needs ${missing.join(" and ")}.` };
|
|
45995
|
+
}
|
|
45996
|
+
return { report: { goal, actual, expected: read("expected"), tried: read("tried"), wanted: read("wanted") } };
|
|
45997
|
+
}
|
|
45998
|
+
function appIdOf(projectDir) {
|
|
45999
|
+
try {
|
|
46000
|
+
const raw = fs6.readFileSync(path7.join(projectDir, "package.json"), "utf-8");
|
|
46001
|
+
const pkg2 = JSON.parse(raw);
|
|
46002
|
+
const appId = pkg2.lotics?.app_id;
|
|
46003
|
+
return typeof appId === "string" && appId !== "" ? appId : void 0;
|
|
46004
|
+
} catch {
|
|
46005
|
+
return void 0;
|
|
46006
|
+
}
|
|
46007
|
+
}
|
|
46008
|
+
function echoReport(report) {
|
|
46009
|
+
console.error("\nNothing was sent. Your report, so it is not lost:\n");
|
|
46010
|
+
console.error(JSON.stringify(report, null, 2));
|
|
46011
|
+
}
|
|
46012
|
+
async function reportCommand(client, options) {
|
|
46013
|
+
const report = options.report;
|
|
46014
|
+
const session = getInvocation()?.session ?? null;
|
|
46015
|
+
try {
|
|
46016
|
+
await client.sendReport({
|
|
46017
|
+
report,
|
|
46018
|
+
cli_session_id: session,
|
|
46019
|
+
cli_version: options.version,
|
|
46020
|
+
workspace_id: options.workspaceId,
|
|
46021
|
+
app_id: appIdOf(options.projectDir ?? process.cwd())
|
|
46022
|
+
});
|
|
46023
|
+
} catch (error52) {
|
|
46024
|
+
console.error(
|
|
46025
|
+
`Could not file the report: ${error52 instanceof Error ? error52.message : String(error52)}`
|
|
46026
|
+
);
|
|
46027
|
+
echoReport(report);
|
|
46028
|
+
process.exit(1);
|
|
46029
|
+
}
|
|
46030
|
+
console.error("Filed. Thank you \u2014 this is read.");
|
|
46031
|
+
if (session === null) {
|
|
46032
|
+
console.error(
|
|
46033
|
+
"\n Sent without the session's commands attached \u2014 telemetry is off, so they were\n never recorded. `export LOTICS_TELEMETRY=1` attaches them to the next report,\n which is the difference between a description and a reproduction."
|
|
46034
|
+
);
|
|
46035
|
+
}
|
|
46036
|
+
}
|
|
46037
|
+
|
|
46038
|
+
// src/app_commands.ts
|
|
46039
|
+
import fs8 from "node:fs";
|
|
46040
|
+
import path9 from "node:path";
|
|
45620
46041
|
import { spawn as spawn2 } from "node:child_process";
|
|
45621
46042
|
import { randomUUID } from "node:crypto";
|
|
45622
46043
|
import { tmpdir } from "node:os";
|
|
@@ -46298,7 +46719,7 @@ import { Text } from "@lotics/ui/text";
|
|
|
46298
46719
|
|
|
46299
46720
|
@lotics/ui ships React Native primitives that render via react-native-web
|
|
46300
46721
|
in this Vite app (the alias is preconfigured in \`vite.config.ts\`). See
|
|
46301
|
-
the full
|
|
46722
|
+
the full catalog with \`lotics docs ui\`.
|
|
46302
46723
|
|
|
46303
46724
|
## Routing
|
|
46304
46725
|
|
|
@@ -46311,7 +46732,9 @@ shareable and survives a full refresh. Standalone (\`<slug>.lotics.app\`) it's a
|
|
|
46311
46732
|
normal browser router with real path URLs. A single-screen app can drop the
|
|
46312
46733
|
router and render one screen directly.
|
|
46313
46734
|
|
|
46314
|
-
|
|
46735
|
+
Run \`lotics docs\` for the SDK reference \u2014 it lists what the packages installed
|
|
46736
|
+
here actually ship, at the versions installed, so it can never point at a page
|
|
46737
|
+
that moved. (\`lotics docs ai\`, \`lotics docs queries\`, \`lotics docs ui\`.)
|
|
46315
46738
|
`
|
|
46316
46739
|
}
|
|
46317
46740
|
];
|
|
@@ -47553,11 +47976,15 @@ function codeWithoutComments(sourceText) {
|
|
|
47553
47976
|
return out.join("");
|
|
47554
47977
|
}
|
|
47555
47978
|
var ALIAS_CALL_HOOKS = {
|
|
47556
|
-
queries: "useQuery",
|
|
47557
|
-
workflows: "useWorkflow",
|
|
47558
|
-
agents: "useAgentRun"
|
|
47979
|
+
queries: ["useQuery", "usePaginatedQuery", "useInfiniteQuery", "useFieldOptions"],
|
|
47980
|
+
workflows: ["useWorkflow"],
|
|
47981
|
+
agents: ["useAgentRun"]
|
|
47559
47982
|
};
|
|
47560
47983
|
var LITERAL_ALIAS_ARG = `["'\`]([A-Za-z_$][A-Za-z0-9_$]*)["'\`]`;
|
|
47984
|
+
function isAppSourcePath(projectRelativePath) {
|
|
47985
|
+
const normalized = projectRelativePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
47986
|
+
return normalized.startsWith("src/") && /\.(ts|tsx|js|jsx)$/.test(normalized);
|
|
47987
|
+
}
|
|
47561
47988
|
function calledAppAliases(sourceText) {
|
|
47562
47989
|
const code = codeWithoutComments(sourceText);
|
|
47563
47990
|
const out = {
|
|
@@ -47566,17 +47993,19 @@ function calledAppAliases(sourceText) {
|
|
|
47566
47993
|
agents: [],
|
|
47567
47994
|
dynamic: []
|
|
47568
47995
|
};
|
|
47569
|
-
for (const [kind,
|
|
47996
|
+
for (const [kind, hooks] of Object.entries(ALIAS_CALL_HOOKS)) {
|
|
47570
47997
|
const seen = /* @__PURE__ */ new Set();
|
|
47571
|
-
|
|
47572
|
-
|
|
47573
|
-
const
|
|
47574
|
-
|
|
47575
|
-
|
|
47576
|
-
|
|
47998
|
+
for (const hook of hooks) {
|
|
47999
|
+
let isDynamic = false;
|
|
48000
|
+
for (const call of code.matchAll(new RegExp(`\\b${hook}\\s*\\(`, "g"))) {
|
|
48001
|
+
const rest2 = code.slice(call.index + call[0].length);
|
|
48002
|
+
const literal2 = new RegExp(`^\\s*${LITERAL_ALIAS_ARG}`).exec(rest2);
|
|
48003
|
+
if (literal2) seen.add(literal2[1]);
|
|
48004
|
+
else isDynamic = true;
|
|
48005
|
+
}
|
|
48006
|
+
if (isDynamic) out.dynamic.push(hook);
|
|
47577
48007
|
}
|
|
47578
48008
|
out[kind] = [...seen];
|
|
47579
|
-
if (isDynamic) out.dynamic.push(hook);
|
|
47580
48009
|
}
|
|
47581
48010
|
return out;
|
|
47582
48011
|
}
|
|
@@ -47870,8 +48299,8 @@ export type AppRoles = typeof ROLE;
|
|
|
47870
48299
|
}
|
|
47871
48300
|
|
|
47872
48301
|
// src/app_workflow_check.ts
|
|
47873
|
-
import
|
|
47874
|
-
import
|
|
48302
|
+
import fs7 from "node:fs";
|
|
48303
|
+
import path8 from "node:path";
|
|
47875
48304
|
import { createRequire } from "node:module";
|
|
47876
48305
|
|
|
47877
48306
|
// ../shared/src/parse_workflow_js.ts
|
|
@@ -48643,10 +49072,10 @@ function mergeDefs(...defs) {
|
|
|
48643
49072
|
function cloneDef(schema) {
|
|
48644
49073
|
return mergeDefs(schema._zod.def);
|
|
48645
49074
|
}
|
|
48646
|
-
function getElementAtPath(obj,
|
|
48647
|
-
if (!
|
|
49075
|
+
function getElementAtPath(obj, path12) {
|
|
49076
|
+
if (!path12)
|
|
48648
49077
|
return obj;
|
|
48649
|
-
return
|
|
49078
|
+
return path12.reduce((acc, key) => acc?.[key], obj);
|
|
48650
49079
|
}
|
|
48651
49080
|
function promiseAllObject(promisesObj) {
|
|
48652
49081
|
const keys3 = Object.keys(promisesObj);
|
|
@@ -49055,11 +49484,11 @@ function explicitlyAborted(x2, startIndex = 0) {
|
|
|
49055
49484
|
}
|
|
49056
49485
|
return false;
|
|
49057
49486
|
}
|
|
49058
|
-
function prefixIssues(
|
|
49487
|
+
function prefixIssues(path12, issues) {
|
|
49059
49488
|
return issues.map((iss) => {
|
|
49060
49489
|
var _a4;
|
|
49061
49490
|
(_a4 = iss).path ?? (_a4.path = []);
|
|
49062
|
-
iss.path.unshift(
|
|
49491
|
+
iss.path.unshift(path12);
|
|
49063
49492
|
return iss;
|
|
49064
49493
|
});
|
|
49065
49494
|
}
|
|
@@ -49206,16 +49635,16 @@ function flattenError(error52, mapper = (issue2) => issue2.message) {
|
|
|
49206
49635
|
}
|
|
49207
49636
|
function formatError(error52, mapper = (issue2) => issue2.message) {
|
|
49208
49637
|
const fieldErrors = { _errors: [] };
|
|
49209
|
-
const processError = (error53,
|
|
49638
|
+
const processError = (error53, path12 = []) => {
|
|
49210
49639
|
for (const issue2 of error53.issues) {
|
|
49211
49640
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
49212
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
49641
|
+
issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
|
|
49213
49642
|
} else if (issue2.code === "invalid_key") {
|
|
49214
|
-
processError({ issues: issue2.issues }, [...
|
|
49643
|
+
processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
|
|
49215
49644
|
} else if (issue2.code === "invalid_element") {
|
|
49216
|
-
processError({ issues: issue2.issues }, [...
|
|
49645
|
+
processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
|
|
49217
49646
|
} else {
|
|
49218
|
-
const fullpath = [...
|
|
49647
|
+
const fullpath = [...path12, ...issue2.path];
|
|
49219
49648
|
if (fullpath.length === 0) {
|
|
49220
49649
|
fieldErrors._errors.push(mapper(issue2));
|
|
49221
49650
|
} else {
|
|
@@ -49242,17 +49671,17 @@ function formatError(error52, mapper = (issue2) => issue2.message) {
|
|
|
49242
49671
|
}
|
|
49243
49672
|
function treeifyError(error52, mapper = (issue2) => issue2.message) {
|
|
49244
49673
|
const result = { errors: [] };
|
|
49245
|
-
const processError = (error53,
|
|
49674
|
+
const processError = (error53, path12 = []) => {
|
|
49246
49675
|
var _a4, _b2;
|
|
49247
49676
|
for (const issue2 of error53.issues) {
|
|
49248
49677
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
49249
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
49678
|
+
issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
|
|
49250
49679
|
} else if (issue2.code === "invalid_key") {
|
|
49251
|
-
processError({ issues: issue2.issues }, [...
|
|
49680
|
+
processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
|
|
49252
49681
|
} else if (issue2.code === "invalid_element") {
|
|
49253
|
-
processError({ issues: issue2.issues }, [...
|
|
49682
|
+
processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
|
|
49254
49683
|
} else {
|
|
49255
|
-
const fullpath = [...
|
|
49684
|
+
const fullpath = [...path12, ...issue2.path];
|
|
49256
49685
|
if (fullpath.length === 0) {
|
|
49257
49686
|
result.errors.push(mapper(issue2));
|
|
49258
49687
|
continue;
|
|
@@ -49284,8 +49713,8 @@ function treeifyError(error52, mapper = (issue2) => issue2.message) {
|
|
|
49284
49713
|
}
|
|
49285
49714
|
function toDotPath(_path) {
|
|
49286
49715
|
const segs = [];
|
|
49287
|
-
const
|
|
49288
|
-
for (const seg of
|
|
49716
|
+
const path12 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
49717
|
+
for (const seg of path12) {
|
|
49289
49718
|
if (typeof seg === "number")
|
|
49290
49719
|
segs.push(`[${seg}]`);
|
|
49291
49720
|
else if (typeof seg === "symbol")
|
|
@@ -61977,13 +62406,13 @@ function resolveRef(ref2, ctx) {
|
|
|
61977
62406
|
if (!ref2.startsWith("#")) {
|
|
61978
62407
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
61979
62408
|
}
|
|
61980
|
-
const
|
|
61981
|
-
if (
|
|
62409
|
+
const path12 = ref2.slice(1).split("/").filter(Boolean);
|
|
62410
|
+
if (path12.length === 0) {
|
|
61982
62411
|
return ctx.rootSchema;
|
|
61983
62412
|
}
|
|
61984
62413
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
61985
|
-
if (
|
|
61986
|
-
const key =
|
|
62414
|
+
if (path12[0] === defsKey) {
|
|
62415
|
+
const key = path12[1];
|
|
61987
62416
|
if (!key || !ctx.defs[key]) {
|
|
61988
62417
|
throw new Error(`Reference not found: ${ref2}`);
|
|
61989
62418
|
}
|
|
@@ -66666,9 +67095,9 @@ __export(expression_object_exports, {
|
|
|
66666
67095
|
pick: () => pick3,
|
|
66667
67096
|
values: () => values2
|
|
66668
67097
|
});
|
|
66669
|
-
function getNestedValue(obj,
|
|
67098
|
+
function getNestedValue(obj, path12) {
|
|
66670
67099
|
if (obj == null) return void 0;
|
|
66671
|
-
const parts =
|
|
67100
|
+
const parts = path12.split(".");
|
|
66672
67101
|
let value2 = obj;
|
|
66673
67102
|
for (const part of parts) {
|
|
66674
67103
|
if (value2 == null) return void 0;
|
|
@@ -66707,11 +67136,11 @@ function entries(obj) {
|
|
|
66707
67136
|
}
|
|
66708
67137
|
return Object.entries(obj);
|
|
66709
67138
|
}
|
|
66710
|
-
function get(obj,
|
|
66711
|
-
if (typeof
|
|
67139
|
+
function get(obj, path12, defaultValue) {
|
|
67140
|
+
if (typeof path12 !== "string") {
|
|
66712
67141
|
throw new Error("get: path must be a string");
|
|
66713
67142
|
}
|
|
66714
|
-
const value2 = getNestedValue(obj,
|
|
67143
|
+
const value2 = getNestedValue(obj, path12);
|
|
66715
67144
|
return value2 !== void 0 ? value2 : defaultValue;
|
|
66716
67145
|
}
|
|
66717
67146
|
function pick3(obj, fields) {
|
|
@@ -68594,17 +69023,17 @@ function readFromChanges(chain2) {
|
|
|
68594
69023
|
if (first3.kind === "bracket-number" || first3.kind === "bracket-expr") {
|
|
68595
69024
|
fail(first3.node, "changes is keyed by field name, not numeric index.");
|
|
68596
69025
|
}
|
|
68597
|
-
const
|
|
69026
|
+
const path12 = [{ at: "key", key: first3.key }];
|
|
68598
69027
|
for (const seg of segments.slice(1)) {
|
|
68599
69028
|
if (seg.kind === "bracket-number") {
|
|
68600
|
-
|
|
69029
|
+
path12.push({ at: "index", index: seg.index });
|
|
68601
69030
|
} else if (seg.kind === "bracket-expr") {
|
|
68602
|
-
|
|
69031
|
+
path12.push({ at: "index", index: seg.expr });
|
|
68603
69032
|
} else {
|
|
68604
|
-
|
|
69033
|
+
path12.push({ at: "key", key: seg.key });
|
|
68605
69034
|
}
|
|
68606
69035
|
}
|
|
68607
|
-
return { kind: "read", source: { from: "trigger_changes" }, path:
|
|
69036
|
+
return { kind: "read", source: { from: "trigger_changes" }, path: path12 };
|
|
68608
69037
|
});
|
|
68609
69038
|
}
|
|
68610
69039
|
var TRIGGER_RECORD_VIEWS = /* @__PURE__ */ new Map([
|
|
@@ -68622,17 +69051,17 @@ function readFromTrigger(chain2) {
|
|
|
68622
69051
|
return view === "trigger_changes" ? readFromChanges(lowered) : readFromRecord(view, lowered);
|
|
68623
69052
|
}
|
|
68624
69053
|
return wrapOptionalGuards(chain2, (segments) => {
|
|
68625
|
-
const
|
|
69054
|
+
const path12 = [];
|
|
68626
69055
|
for (const seg of segments) {
|
|
68627
69056
|
if (seg.kind === "bracket-number") {
|
|
68628
|
-
|
|
69057
|
+
path12.push({ at: "index", index: seg.index });
|
|
68629
69058
|
} else if (seg.kind === "bracket-expr") {
|
|
68630
|
-
|
|
69059
|
+
path12.push({ at: "index", index: seg.expr });
|
|
68631
69060
|
} else {
|
|
68632
|
-
|
|
69061
|
+
path12.push({ at: "key", key: seg.key });
|
|
68633
69062
|
}
|
|
68634
69063
|
}
|
|
68635
|
-
return { kind: "read", source: { from: "trigger" }, path:
|
|
69064
|
+
return { kind: "read", source: { from: "trigger" }, path: path12 };
|
|
68636
69065
|
});
|
|
68637
69066
|
}
|
|
68638
69067
|
function readFromRuntime(chain2) {
|
|
@@ -68654,17 +69083,17 @@ function readFromRuntime(chain2) {
|
|
|
68654
69083
|
const parked = PARKED_RUNTIME_KEYS.get(key);
|
|
68655
69084
|
if (parked) fail(first3.node, parked, parkedRuntimeKeyConstruct(key));
|
|
68656
69085
|
const source = { from: "runtime", key };
|
|
68657
|
-
const
|
|
69086
|
+
const path12 = [];
|
|
68658
69087
|
for (const seg of segments.slice(1)) {
|
|
68659
69088
|
if (seg.kind === "bracket-number") {
|
|
68660
|
-
|
|
69089
|
+
path12.push({ at: "index", index: seg.index });
|
|
68661
69090
|
} else if (seg.kind === "bracket-expr") {
|
|
68662
|
-
|
|
69091
|
+
path12.push({ at: "index", index: seg.expr });
|
|
68663
69092
|
} else {
|
|
68664
|
-
|
|
69093
|
+
path12.push({ at: "key", key: seg.key });
|
|
68665
69094
|
}
|
|
68666
69095
|
}
|
|
68667
|
-
return { kind: "read", source, path:
|
|
69096
|
+
return { kind: "read", source, path: path12 };
|
|
68668
69097
|
});
|
|
68669
69098
|
}
|
|
68670
69099
|
function readFromForeachItem(chain2) {
|
|
@@ -68700,17 +69129,17 @@ function readFromLexical(name2, chain2) {
|
|
|
68700
69129
|
}
|
|
68701
69130
|
function readFromStepOutput(stepId, chain2) {
|
|
68702
69131
|
return wrapOptionalGuards(chain2, (segments) => {
|
|
68703
|
-
const
|
|
69132
|
+
const path12 = [];
|
|
68704
69133
|
for (const seg of segments) {
|
|
68705
69134
|
if (seg.kind === "bracket-number") {
|
|
68706
|
-
|
|
69135
|
+
path12.push({ at: "index", index: seg.index });
|
|
68707
69136
|
} else if (seg.kind === "bracket-expr") {
|
|
68708
|
-
|
|
69137
|
+
path12.push({ at: "index", index: seg.expr });
|
|
68709
69138
|
} else {
|
|
68710
|
-
|
|
69139
|
+
path12.push({ at: "key", key: seg.key });
|
|
68711
69140
|
}
|
|
68712
69141
|
}
|
|
68713
|
-
return { kind: "read", source: { from: "step_output", step_id: stepId }, path:
|
|
69142
|
+
return { kind: "read", source: { from: "step_output", step_id: stepId }, path: path12 };
|
|
68714
69143
|
});
|
|
68715
69144
|
}
|
|
68716
69145
|
function classifyRecordPath(segs) {
|
|
@@ -70375,7 +70804,7 @@ function subsetIssues(bodySource, offset) {
|
|
|
70375
70804
|
];
|
|
70376
70805
|
}
|
|
70377
70806
|
async function loadProjectTypescript(projectDir) {
|
|
70378
|
-
const requireFromProject = createRequire(
|
|
70807
|
+
const requireFromProject = createRequire(path8.join(projectDir, "package.json"));
|
|
70379
70808
|
let resolved;
|
|
70380
70809
|
try {
|
|
70381
70810
|
resolved = requireFromProject.resolve("typescript");
|
|
@@ -70388,12 +70817,12 @@ async function loadProjectTypescript(projectDir) {
|
|
|
70388
70817
|
return mod2.default ?? mod2;
|
|
70389
70818
|
}
|
|
70390
70819
|
function pathToImportUrl(p) {
|
|
70391
|
-
const resolved =
|
|
70820
|
+
const resolved = path8.resolve(p);
|
|
70392
70821
|
const prefixed = resolved.startsWith("/") ? resolved : `/${resolved}`;
|
|
70393
|
-
return `file://${prefixed.split(
|
|
70822
|
+
return `file://${prefixed.split(path8.sep).join("/")}`;
|
|
70394
70823
|
}
|
|
70395
70824
|
function checkOneWorkflowBody(tsApi, input) {
|
|
70396
|
-
const wrapped =
|
|
70825
|
+
const wrapped = fs7.readFileSync(input.bodyPath, "utf-8");
|
|
70397
70826
|
const offset = bodyLineOffset(wrapped);
|
|
70398
70827
|
const subset = subsetIssues(stripWorkflowHeader(wrapped), offset);
|
|
70399
70828
|
if (subset) return subset;
|
|
@@ -70440,7 +70869,7 @@ function checkOneWorkflowBody(tsApi, input) {
|
|
|
70440
70869
|
}
|
|
70441
70870
|
function createCheckedSourceHost(tsApi, options, bodyPath, bodyText) {
|
|
70442
70871
|
const base = tsApi.createCompilerHost(options, false);
|
|
70443
|
-
const key = (fileName) => base.getCanonicalFileName(
|
|
70872
|
+
const key = (fileName) => base.getCanonicalFileName(path8.resolve(fileName).replace(/\\/g, "/"));
|
|
70444
70873
|
const bodyKey = key(bodyPath);
|
|
70445
70874
|
return {
|
|
70446
70875
|
...base,
|
|
@@ -70457,6 +70886,1035 @@ function checkWorkflowBodies(tsApi, aliases) {
|
|
|
70457
70886
|
}));
|
|
70458
70887
|
}
|
|
70459
70888
|
|
|
70889
|
+
// ../shared/src/schemas/table_fields.ts
|
|
70890
|
+
var tableFieldTypeNameSchema = zod_default.enum([
|
|
70891
|
+
"text",
|
|
70892
|
+
"number",
|
|
70893
|
+
"date",
|
|
70894
|
+
"boolean",
|
|
70895
|
+
"select",
|
|
70896
|
+
"select_member",
|
|
70897
|
+
"select_record_link",
|
|
70898
|
+
"files",
|
|
70899
|
+
"formula",
|
|
70900
|
+
"rollup",
|
|
70901
|
+
"lookup",
|
|
70902
|
+
"button",
|
|
70903
|
+
"autonumber"
|
|
70904
|
+
]);
|
|
70905
|
+
var tableFieldBaseSchema = zod_default.object({
|
|
70906
|
+
key: zod_default.string().describe("Unique field key"),
|
|
70907
|
+
name: zod_default.string().describe("Display name"),
|
|
70908
|
+
description: zod_default.string().describe("Field description"),
|
|
70909
|
+
confirm_before_update: zod_default.boolean().optional().describe("Show confirmation before AI updates")
|
|
70910
|
+
});
|
|
70911
|
+
var numberFormatSchema = zod_default.enum(["number", "currency", "percentage"]);
|
|
70912
|
+
var textFormatSchema = zod_default.enum(["text", "link", "markdown"]);
|
|
70913
|
+
var dateFormatSchema = zod_default.enum(["date", "datetime", "date_range", "datetime_range"]);
|
|
70914
|
+
var DEFAULT_VALUE_DESC = "Value pre-filled into a new record when none is supplied for this field. Applied on create only \u2014 existing records are never backfilled. null clears it.";
|
|
70915
|
+
var textDefaultValueSchema = zod_default.string().nullish().describe(DEFAULT_VALUE_DESC);
|
|
70916
|
+
var numberDefaultValueSchema = zod_default.number().nullish().describe(DEFAULT_VALUE_DESC);
|
|
70917
|
+
var booleanDefaultValueSchema = zod_default.boolean().nullish().describe(DEFAULT_VALUE_DESC);
|
|
70918
|
+
var dateDefaultValueSchema = zod_default.string().nullish().describe(`${DEFAULT_VALUE_DESC} A date string in the field's format.`);
|
|
70919
|
+
var selectDefaultValueSchema = zod_default.array(zod_default.string()).nullish().describe(`${DEFAULT_VALUE_DESC} Option key(s) \u2014 one for single-select.`);
|
|
70920
|
+
var memberDefaultValueSchema = zod_default.array(zod_default.string()).nullish().describe(`${DEFAULT_VALUE_DESC} Member ID(s) \u2014 one for single-select.`);
|
|
70921
|
+
var tableNumberFieldSchema = tableFieldBaseSchema.extend({
|
|
70922
|
+
type: zod_default.literal("number"),
|
|
70923
|
+
format: numberFormatSchema,
|
|
70924
|
+
currency: zod_default.string().optional().describe("ISO 4217 code"),
|
|
70925
|
+
default_value: numberDefaultValueSchema
|
|
70926
|
+
});
|
|
70927
|
+
var tableTextFieldSchema = tableFieldBaseSchema.extend({
|
|
70928
|
+
type: zod_default.literal("text"),
|
|
70929
|
+
unique: zod_default.boolean().optional().describe("Unique values required"),
|
|
70930
|
+
// it's `optional` only for backward compatibility
|
|
70931
|
+
format: textFormatSchema.optional(),
|
|
70932
|
+
default_value: textDefaultValueSchema
|
|
70933
|
+
});
|
|
70934
|
+
var tableDateFieldSchema = tableFieldBaseSchema.extend({
|
|
70935
|
+
type: zod_default.literal("date"),
|
|
70936
|
+
format: dateFormatSchema.optional(),
|
|
70937
|
+
timezone: zod_default.string().optional().describe("IANA timezone"),
|
|
70938
|
+
derive_from: zod_default.enum(["created_at", "updated_at"]).optional().describe(
|
|
70939
|
+
"Auto-populate from the row's system timestamp. `created_at` stamps once at insert time; `updated_at` re-stamps on every record edit. Derived fields are read-only \u2014 user-supplied values are silently ignored at write time, matching the formula/rollup/lookup pattern. Replaces the per-table after_create workflow pattern."
|
|
70940
|
+
),
|
|
70941
|
+
// A derived date is read-only, so derive_from and default_value are mutually
|
|
70942
|
+
// exclusive — enforced in validateFieldDefaultValue.
|
|
70943
|
+
default_value: dateDefaultValueSchema
|
|
70944
|
+
});
|
|
70945
|
+
var tableBooleanFieldSchema = tableFieldBaseSchema.extend({
|
|
70946
|
+
type: zod_default.literal("boolean"),
|
|
70947
|
+
default_value: booleanDefaultValueSchema
|
|
70948
|
+
});
|
|
70949
|
+
var tableSelectFieldOptionSchema = zod_default.object({
|
|
70950
|
+
key: zod_default.string(),
|
|
70951
|
+
name: zod_default.string(),
|
|
70952
|
+
color: optionColorSchema
|
|
70953
|
+
});
|
|
70954
|
+
var tableSelectFieldSchema = tableFieldBaseSchema.extend({
|
|
70955
|
+
type: zod_default.literal("select"),
|
|
70956
|
+
options: zod_default.array(tableSelectFieldOptionSchema),
|
|
70957
|
+
multi: zod_default.boolean().optional().describe("Allow multiple selections"),
|
|
70958
|
+
default_value: selectDefaultValueSchema
|
|
70959
|
+
});
|
|
70960
|
+
var tableSelectMemberFieldSchema = tableFieldBaseSchema.extend({
|
|
70961
|
+
type: zod_default.literal("select_member"),
|
|
70962
|
+
multi: zod_default.boolean().optional().describe("Allow multiple selections"),
|
|
70963
|
+
default_value: memberDefaultValueSchema
|
|
70964
|
+
});
|
|
70965
|
+
var recordLinkItemSchema = zod_default.object({
|
|
70966
|
+
id: zod_default.string(),
|
|
70967
|
+
display: zod_default.string()
|
|
70968
|
+
});
|
|
70969
|
+
var selectRecordLinkValueSchema = zod_default.array(recordLinkItemSchema);
|
|
70970
|
+
var tableSelectRecordLinkFieldInputSchema = tableFieldBaseSchema.extend({
|
|
70971
|
+
type: zod_default.literal("select_record_link"),
|
|
70972
|
+
table_id: zod_default.string().describe("Linked table ID"),
|
|
70973
|
+
display_field_keys: zod_default.array(zod_default.string()).optional().describe(
|
|
70974
|
+
"Field keys of the linked table shown as the link's display text and as the columns in the record picker. If omitted, auto-selects the first text field."
|
|
70975
|
+
),
|
|
70976
|
+
display_field_widths: zod_default.record(zod_default.string(), zod_default.number().int().positive()).optional().describe(
|
|
70977
|
+
"Per-column widths in pixels for the record picker, keyed by linked-table field key. Missing keys fall back to the default column width."
|
|
70978
|
+
),
|
|
70979
|
+
sync_both_ways: zod_default.boolean().optional().describe("Enable bidirectional link sync. If the target table has exactly one existing unpaired link field pointing back, pairs with it instead of creating a new field."),
|
|
70980
|
+
paired_field_display_field_keys: zod_default.array(zod_default.string()).optional().describe("Display fields for paired link"),
|
|
70981
|
+
paired_field_name: zod_default.string().optional().describe(
|
|
70982
|
+
"Name for the auto-created paired field on the target table when sync_both_ways=true. If omitted, falls back to the source table's name (auto-uniquified with a numeric suffix on collision). Rejected as a conflict if a field with this name already exists on the target."
|
|
70983
|
+
),
|
|
70984
|
+
cardinality: zod_default.enum(["one", "many"]).optional().describe(
|
|
70985
|
+
"How many linked records this field can hold. Default 'many' (multi-select). 'one' = single-select; this side holds exactly one link to the partner. Requires sync_both_ways/paired_field_key. Setting 'one' on both paired sides is rejected."
|
|
70986
|
+
)
|
|
70987
|
+
});
|
|
70988
|
+
var tableSelectRecordLinkFieldSchema = tableFieldBaseSchema.extend({
|
|
70989
|
+
type: zod_default.literal("select_record_link").describe("Field type for linking to records in another table"),
|
|
70990
|
+
table_id: zod_default.string().describe("ID of the target table that records can be linked to"),
|
|
70991
|
+
display_field_keys: zod_default.array(zod_default.string()).optional().default([]).describe(
|
|
70992
|
+
"Field keys of the linked table shown as the link's display text and as the columns in the record picker. If empty, the picker shows all fields."
|
|
70993
|
+
),
|
|
70994
|
+
display_field_widths: zod_default.record(zod_default.string(), zod_default.number().int().positive()).optional().describe(
|
|
70995
|
+
"Per-column widths in pixels for the record picker, keyed by linked-table field key. Missing keys fall back to the default column width."
|
|
70996
|
+
),
|
|
70997
|
+
paired_field_key: zod_default.string().optional().describe(
|
|
70998
|
+
"Key of the paired link field in the linked table. If set to a string, this indicates a bidirectional link where both tables can reference each other and data synchronizes in both directions. Both fields have paired_field_key pointing to each other. If set to null, explicitly disconnects the bidirectional link (clears paired_field_key on both sides). If undefined, no change is made to the existing paired_field_key."
|
|
70999
|
+
),
|
|
71000
|
+
cardinality: zod_default.enum(["one", "many"]).optional().describe(
|
|
71001
|
+
"How many linked records this field can hold. Default 'many' (multi-select). 'one' = single-select; this side holds exactly one link to the partner. Requires paired_field_key. Two paired sides cannot both be 'one'."
|
|
71002
|
+
)
|
|
71003
|
+
});
|
|
71004
|
+
var tableRollupFieldSchema = tableFieldBaseSchema.extend({
|
|
71005
|
+
type: zod_default.literal("rollup").describe(
|
|
71006
|
+
"Field type for aggregating values from linked records (sum, avg, filled, earliest, etc.)"
|
|
71007
|
+
),
|
|
71008
|
+
source_field_key: zod_default.string().describe("The field key of the select_record_link field to rollup from"),
|
|
71009
|
+
aggregate_option: aggregateOptionSchema.describe(
|
|
71010
|
+
"The field aggregation function to apply (e.g., sum, avg, filled, earliest)"
|
|
71011
|
+
),
|
|
71012
|
+
filter: tableRecordFiltersGroupNodeSchema.optional().describe(
|
|
71013
|
+
"Optional filter to apply to linked records before aggregation. Only records matching the filter conditions will be included in the rollup calculation."
|
|
71014
|
+
),
|
|
71015
|
+
aggregate_field_type: tableFieldTypeNameSchema.optional().describe(
|
|
71016
|
+
"What this rollup's CELL holds \u2014 'date' for earliest/latest, 'number' for every other operation (counts, sums, percentages). Derived from the operation, not from the aggregated field: a 'filled' count over a files column is a number. Server-derived at write time; ignored on input."
|
|
71017
|
+
),
|
|
71018
|
+
aggregate_field_format: zod_default.string().optional().describe(
|
|
71019
|
+
"The format of this rollup's own value. Operations that preserve the aggregated value's unit (sum/avg/median/min/max/range/earliest/latest) inherit the target field's format; counting operations are 'number', percentages 'percentage'. Server-derived at write time; ignored on input."
|
|
71020
|
+
),
|
|
71021
|
+
aggregate_field_currency: zod_default.string().optional().describe(
|
|
71022
|
+
"The currency code of this rollup's own value (e.g. 'USD', 'VND'), inherited from the aggregated field only when the operation preserves its unit \u2014 a COUNT of a currency column carries no currency. Server-derived at write time; ignored on input."
|
|
71023
|
+
)
|
|
71024
|
+
});
|
|
71025
|
+
var lookupOrderBySchema = zod_default.object({
|
|
71026
|
+
field_key: zod_default.string(),
|
|
71027
|
+
direction: zod_default.enum(["asc", "desc"])
|
|
71028
|
+
});
|
|
71029
|
+
var tableLookupFieldSchema = tableFieldBaseSchema.extend({
|
|
71030
|
+
type: zod_default.literal("lookup").describe("Field type for displaying values from fields in linked records"),
|
|
71031
|
+
source_field_key: zod_default.string().describe("The field key of the select_record_link field to lookup from"),
|
|
71032
|
+
lookup_field_key: zod_default.string().describe("The field key from the linked records to display"),
|
|
71033
|
+
lookup_field_type: tableFieldTypeNameSchema.optional().describe(
|
|
71034
|
+
"The type of the target lookup field (e.g. 'text', 'number', 'date'). Resolved from the linked table's field definition at read time."
|
|
71035
|
+
),
|
|
71036
|
+
lookup_field_format: zod_default.string().optional().describe(
|
|
71037
|
+
"The format of the target lookup field (e.g. 'currency', 'percentage', 'datetime'). Resolved from the linked table's field definition at read time."
|
|
71038
|
+
),
|
|
71039
|
+
lookup_field_currency: zod_default.string().optional().describe(
|
|
71040
|
+
"The currency code of the target lookup field (e.g. 'USD', 'VND'). Resolved from the linked table's field definition at read time."
|
|
71041
|
+
),
|
|
71042
|
+
lookup_field_options: zod_default.array(zod_default.object({ key: zod_default.string(), name: zod_default.string(), color: zod_default.string().optional() })).optional().describe(
|
|
71043
|
+
"Options for select-type lookup fields. Synced from the source select field's options."
|
|
71044
|
+
),
|
|
71045
|
+
order_by: lookupOrderBySchema.optional().describe(
|
|
71046
|
+
"When set, sort the linked records by this field on the linked table and return ONLY the picked field from the single extreme record (desc=latest, asc=earliest), as a one-element array. Omit to return every linked record's value as an array. field_key must be a field on the linked table."
|
|
71047
|
+
)
|
|
71048
|
+
});
|
|
71049
|
+
var tableFilesFieldSchema = tableFieldBaseSchema.extend({
|
|
71050
|
+
type: zod_default.literal("files").describe("Field type for file attachments (images, PDFs, documents)")
|
|
71051
|
+
});
|
|
71052
|
+
var formulaInputSchema = zod_default.object({
|
|
71053
|
+
expression: zod_default.string().describe(
|
|
71054
|
+
"JavaScript expression. Uses {Field Name} for field references."
|
|
71055
|
+
),
|
|
71056
|
+
format: zod_default.enum(["number", "currency", "percentage", "link"]).optional().describe(
|
|
71057
|
+
"Display format. 'number' / 'currency' / 'percentage' for numeric results; 'link' for text-output formulas that return a URL \u2014 renders the result as a clickable link."
|
|
71058
|
+
),
|
|
71059
|
+
currency: zod_default.string().optional().describe("ISO 4217 currency code, e.g. USD, VND, EUR")
|
|
71060
|
+
});
|
|
71061
|
+
var formulaSchema = formulaInputSchema.extend({
|
|
71062
|
+
output_type: zod_default.enum(["number", "text", "date", "datetime", "boolean"]).optional().describe("Output type of the formula. Inferred by the backend from the expression \u2014 read-only on input. `datetime` when the result carries a time of day (references a datetime field or a time-bearing helper)."),
|
|
71063
|
+
volatile: zod_default.boolean().optional().describe("Whether the formula's result depends on `now()` or other non-deterministic helpers. Inferred by the backend \u2014 read-only on input.")
|
|
71064
|
+
});
|
|
71065
|
+
var tableFormulaFieldSchema = tableFieldBaseSchema.extend({
|
|
71066
|
+
type: zod_default.literal("formula").describe("Field type for calculated values based on expressions"),
|
|
71067
|
+
formula: formulaSchema.describe("Formula configuration and expression")
|
|
71068
|
+
});
|
|
71069
|
+
var workflowMetadataSchema = zod_default.object({
|
|
71070
|
+
table_ids: zod_default.array(zod_default.string()).describe("IDs of the tables this workflow affects"),
|
|
71071
|
+
staged_for_app_id: zod_default.string().optional().describe(
|
|
71072
|
+
"Present while the row is a draft-staged fork for this app; cleared when the app publishes the binding. Marked rows left unbound are archived at publish/discard."
|
|
71073
|
+
)
|
|
71074
|
+
});
|
|
71075
|
+
var workflowSchema = zod_default.object({
|
|
71076
|
+
id: zod_default.string().describe("Unique identifier for the workflow"),
|
|
71077
|
+
name: zod_default.string().describe("Display name of the workflow"),
|
|
71078
|
+
description: zod_default.string().describe("Human-readable description of what this workflow does"),
|
|
71079
|
+
steps: zod_default.unknown().describe(
|
|
71080
|
+
"AST-valued step tree (tool calls, conditionals, loops)."
|
|
71081
|
+
),
|
|
71082
|
+
metadata: workflowMetadataSchema.nullable().optional().describe("Metadata for the workflow"),
|
|
71083
|
+
current_version: zod_default.number().int().describe("Current version number"),
|
|
71084
|
+
enabled: zod_default.boolean().describe("Whether this workflow is active"),
|
|
71085
|
+
workspace_id: zod_default.string().describe("ID of the workspace this workflow belongs to"),
|
|
71086
|
+
created_at: zod_default.string().describe("Timestamp when workflow was created"),
|
|
71087
|
+
updated_at: zod_default.string().describe("Timestamp of last update")
|
|
71088
|
+
});
|
|
71089
|
+
var tableButtonFieldSchema = tableFieldBaseSchema.extend({
|
|
71090
|
+
type: zod_default.literal("button").describe("Field type for action buttons"),
|
|
71091
|
+
text: zod_default.string().describe("Button label text displayed to users"),
|
|
71092
|
+
workflow_id: zod_default.string().nullable().optional().describe(
|
|
71093
|
+
"ID of the workflow the button presses trigger. Null means no action configured \u2014 pressing the button is a no-op. Button authoring is retired: existing bindings keep running, but nothing sets a new one."
|
|
71094
|
+
)
|
|
71095
|
+
});
|
|
71096
|
+
var tableAutonumberFieldSchema = tableFieldBaseSchema.extend({
|
|
71097
|
+
type: zod_default.literal("autonumber"),
|
|
71098
|
+
prefix: zod_default.string().optional().describe(
|
|
71099
|
+
"Literal prefix prepended to every display value (e.g. 'KH-' \u2192 'KH-001'). Ignored when `template` is set."
|
|
71100
|
+
),
|
|
71101
|
+
padding: zod_default.number().int().min(1).max(20).optional().describe(
|
|
71102
|
+
"Zero-pad the integer to this width. Default 1 (no padding). 3 \u2192 '001', '012', '123', '1234' (overflow uses the actual width). Ignored when `template` is set."
|
|
71103
|
+
),
|
|
71104
|
+
template: zod_default.string().optional().describe(
|
|
71105
|
+
"Format template with placeholder tokens evaluated at insert time. Tokens: {N} (raw integer), {N:W} (zero-padded to width W, e.g. {N:3} \u2192 001), {YEAR} (4-digit year), {YEAR:2} (2-digit year), {MONTH} (2-digit month), {DAY} (2-digit day). Date tokens use the workspace timezone. Example: 'HM-{YEAR}-{N:3}' yields 'HM-2026-001'. Stored as the composed string; subsequent template edits do NOT re-format existing rows (date tokens would lose the original creation date)."
|
|
71106
|
+
)
|
|
71107
|
+
});
|
|
71108
|
+
var tableFieldSchema = zod_default.discriminatedUnion("type", [
|
|
71109
|
+
tableNumberFieldSchema,
|
|
71110
|
+
tableTextFieldSchema,
|
|
71111
|
+
tableDateFieldSchema,
|
|
71112
|
+
tableBooleanFieldSchema,
|
|
71113
|
+
tableSelectFieldSchema,
|
|
71114
|
+
tableSelectMemberFieldSchema,
|
|
71115
|
+
tableSelectRecordLinkFieldSchema,
|
|
71116
|
+
tableRollupFieldSchema,
|
|
71117
|
+
tableLookupFieldSchema,
|
|
71118
|
+
tableFilesFieldSchema,
|
|
71119
|
+
tableFormulaFieldSchema,
|
|
71120
|
+
tableButtonFieldSchema,
|
|
71121
|
+
tableAutonumberFieldSchema
|
|
71122
|
+
]);
|
|
71123
|
+
var tableFieldInputSchema = zod_default.discriminatedUnion("type", [
|
|
71124
|
+
tableNumberFieldSchema,
|
|
71125
|
+
tableTextFieldSchema,
|
|
71126
|
+
tableDateFieldSchema,
|
|
71127
|
+
tableBooleanFieldSchema,
|
|
71128
|
+
tableSelectFieldSchema,
|
|
71129
|
+
tableSelectMemberFieldSchema,
|
|
71130
|
+
tableSelectRecordLinkFieldInputSchema,
|
|
71131
|
+
tableRollupFieldSchema,
|
|
71132
|
+
tableLookupFieldSchema,
|
|
71133
|
+
tableFilesFieldSchema,
|
|
71134
|
+
tableFormulaFieldSchema,
|
|
71135
|
+
tableButtonFieldSchema,
|
|
71136
|
+
tableAutonumberFieldSchema
|
|
71137
|
+
]);
|
|
71138
|
+
var tableFieldsSchema = zod_default.array(tableFieldSchema);
|
|
71139
|
+
var tableFieldCreateBaseSchema = zod_default.object({
|
|
71140
|
+
name: zod_default.string().describe("Display name"),
|
|
71141
|
+
description: zod_default.string().describe("Field description"),
|
|
71142
|
+
confirm_before_update: zod_default.boolean().optional().describe("Show confirmation before AI updates")
|
|
71143
|
+
});
|
|
71144
|
+
var tableSelectFieldOptionCreateSchema = zod_default.object({
|
|
71145
|
+
name: zod_default.string(),
|
|
71146
|
+
color: optionColorSchema
|
|
71147
|
+
});
|
|
71148
|
+
var tableFieldTypeConfigSchema = zod_default.discriminatedUnion("type", [
|
|
71149
|
+
zod_default.object({
|
|
71150
|
+
type: zod_default.literal("number"),
|
|
71151
|
+
format: numberFormatSchema.default("number"),
|
|
71152
|
+
currency: zod_default.string().optional().describe("ISO 4217 code"),
|
|
71153
|
+
default_value: numberDefaultValueSchema
|
|
71154
|
+
}),
|
|
71155
|
+
zod_default.object({
|
|
71156
|
+
type: zod_default.literal("text"),
|
|
71157
|
+
unique: zod_default.boolean().optional().describe("Unique values required"),
|
|
71158
|
+
format: textFormatSchema.default("text"),
|
|
71159
|
+
default_value: textDefaultValueSchema
|
|
71160
|
+
}),
|
|
71161
|
+
zod_default.object({
|
|
71162
|
+
type: zod_default.literal("date"),
|
|
71163
|
+
format: dateFormatSchema.optional(),
|
|
71164
|
+
timezone: zod_default.string().optional().describe("IANA timezone"),
|
|
71165
|
+
derive_from: zod_default.enum(["created_at", "updated_at"]).nullable().optional().describe("Auto-populate from row system timestamp; field becomes read-only. Only valid for date/datetime formats. Pass null to clear and revert to a manual date field."),
|
|
71166
|
+
default_value: dateDefaultValueSchema
|
|
71167
|
+
}),
|
|
71168
|
+
zod_default.object({
|
|
71169
|
+
type: zod_default.literal("boolean"),
|
|
71170
|
+
default_value: booleanDefaultValueSchema
|
|
71171
|
+
}),
|
|
71172
|
+
zod_default.object({
|
|
71173
|
+
type: zod_default.literal("select"),
|
|
71174
|
+
options: zod_default.array(tableSelectFieldOptionCreateSchema),
|
|
71175
|
+
multi: zod_default.boolean().optional().describe("Allow multiple selections"),
|
|
71176
|
+
default_value: selectDefaultValueSchema
|
|
71177
|
+
}),
|
|
71178
|
+
zod_default.object({
|
|
71179
|
+
type: zod_default.literal("select_member"),
|
|
71180
|
+
multi: zod_default.boolean().optional().describe("Allow multiple selections"),
|
|
71181
|
+
default_value: memberDefaultValueSchema
|
|
71182
|
+
}),
|
|
71183
|
+
zod_default.object({
|
|
71184
|
+
type: zod_default.literal("select_record_link"),
|
|
71185
|
+
table_id: zod_default.string().describe("Linked table ID"),
|
|
71186
|
+
display_field_keys: zod_default.array(zod_default.string()).optional().describe(
|
|
71187
|
+
"Field keys of the linked table shown as the link's display text and as the columns in the record picker. If omitted, auto-selects the first text field."
|
|
71188
|
+
),
|
|
71189
|
+
display_field_widths: zod_default.record(zod_default.string(), zod_default.number().int().positive()).optional().describe(
|
|
71190
|
+
"Per-column widths in pixels for the record picker, keyed by linked-table field key. Missing keys fall back to the default column width."
|
|
71191
|
+
),
|
|
71192
|
+
sync_both_ways: zod_default.boolean().optional().describe("Enable bidirectional link sync. If the target table has exactly one existing unpaired link field pointing back, pairs with it instead of creating a new field."),
|
|
71193
|
+
paired_field_display_field_keys: zod_default.array(zod_default.string()).optional().describe("Paired field display"),
|
|
71194
|
+
paired_field_name: zod_default.string().optional().describe(
|
|
71195
|
+
"Name for the auto-created paired field on the target table when sync_both_ways=true. Omit to default to the source table's name (auto-uniquified on collision). If supplied and a field with the same name already exists on the target, the create is rejected."
|
|
71196
|
+
),
|
|
71197
|
+
cardinality: zod_default.enum(["one", "many"]).optional().describe(
|
|
71198
|
+
"How many linked records this field can hold. Default 'many' (multi-select). 'one' = single-select; this side holds exactly one link to the partner. Requires sync_both_ways. Two paired sides cannot both be 'one'."
|
|
71199
|
+
)
|
|
71200
|
+
}),
|
|
71201
|
+
zod_default.object({
|
|
71202
|
+
type: zod_default.literal("rollup"),
|
|
71203
|
+
source_field_key: zod_default.string().describe("Source link field key"),
|
|
71204
|
+
aggregate_option: aggregateOptionSchema,
|
|
71205
|
+
filter: tableRecordFiltersGroupNodeSchema.optional().describe("Filter linked records")
|
|
71206
|
+
}),
|
|
71207
|
+
zod_default.object({
|
|
71208
|
+
type: zod_default.literal("lookup"),
|
|
71209
|
+
source_field_key: zod_default.string().describe("Source link field key"),
|
|
71210
|
+
lookup_field_key: zod_default.string().describe("Field to display"),
|
|
71211
|
+
order_by: lookupOrderBySchema.optional().describe("Ordered lookup: pick only the extreme linked record's field (desc=latest, asc=earliest)")
|
|
71212
|
+
}),
|
|
71213
|
+
zod_default.object({
|
|
71214
|
+
type: zod_default.literal("files")
|
|
71215
|
+
}),
|
|
71216
|
+
zod_default.object({
|
|
71217
|
+
type: zod_default.literal("formula"),
|
|
71218
|
+
formula: formulaInputSchema
|
|
71219
|
+
}),
|
|
71220
|
+
// `button` is deliberately absent: button fields are legacy — this union
|
|
71221
|
+
// shapes CREATE input only, and new buttons can no longer be created
|
|
71222
|
+
// (see LEGACY_FIELD_TYPES). Stored button fields still parse via the
|
|
71223
|
+
// stored-field union above, and update paths keep accepting text edits.
|
|
71224
|
+
zod_default.object({
|
|
71225
|
+
type: zod_default.literal("autonumber"),
|
|
71226
|
+
prefix: zod_default.string().optional().describe("Literal prefix prepended to display (ignored when template is set)"),
|
|
71227
|
+
padding: zod_default.number().int().min(1).max(20).optional().describe("Zero-pad the integer to this width (default 1) (ignored when template is set)"),
|
|
71228
|
+
template: zod_default.string().optional().describe(
|
|
71229
|
+
"Format template \u2014 tokens evaluate at insert time: {N}, {N:W} (padded), {YEAR}, {YEAR:2}, {MONTH}, {DAY}. Date tokens use workspace timezone. Example: 'HM-{YEAR}-{N:3}' \u2192 'HM-2026-001'."
|
|
71230
|
+
)
|
|
71231
|
+
})
|
|
71232
|
+
]);
|
|
71233
|
+
var tableFieldCreateInputSchema = zod_default.intersection(
|
|
71234
|
+
tableFieldCreateBaseSchema,
|
|
71235
|
+
tableFieldTypeConfigSchema
|
|
71236
|
+
);
|
|
71237
|
+
var fieldVisibilitySchema = zod_default.enum(["visible", "hidden"]).describe(
|
|
71238
|
+
"Field visibility state: 'visible' = shown to everyone, 'hidden' = not shown by default but members can toggle"
|
|
71239
|
+
);
|
|
71240
|
+
|
|
71241
|
+
// ../shared/src/schemas/field_config.ts
|
|
71242
|
+
var fieldConfigEntrySchema = zod_default.object({
|
|
71243
|
+
key: zod_default.string().min(1).describe("Field key"),
|
|
71244
|
+
visibility: fieldVisibilitySchema,
|
|
71245
|
+
width: zod_default.number().optional()
|
|
71246
|
+
});
|
|
71247
|
+
|
|
71248
|
+
// ../shared/src/schemas/iam.ts
|
|
71249
|
+
var jsonSchemaSchema = zod_default.string();
|
|
71250
|
+
var organizationSchema = zod_default.object({
|
|
71251
|
+
id: zod_default.string().describe("Unique identifier for the organization"),
|
|
71252
|
+
name: zod_default.string().describe("Display name of the organization"),
|
|
71253
|
+
slug: zod_default.string().nullable().describe("Slug for the organization")
|
|
71254
|
+
});
|
|
71255
|
+
var memberSchema = zod_default.object({
|
|
71256
|
+
member_id: zod_default.string().describe("Unique identifier for the member"),
|
|
71257
|
+
organization_id: zod_default.string().describe("Organization ID the member belongs to"),
|
|
71258
|
+
name: zod_default.string().describe("Display name of the member"),
|
|
71259
|
+
email_address: zod_default.string().describe("Email address of the member"),
|
|
71260
|
+
role: zod_default.enum(["owner", "admin", "member"]).describe("Organization role"),
|
|
71261
|
+
image: zod_default.string().nullable().optional().describe("URL to the member's profile picture"),
|
|
71262
|
+
account_type: zod_default.enum(["self_managed", "admin_managed"]).describe(
|
|
71263
|
+
"How the account is credentialed. admin_managed means an admin chose the sign-in identifier and set the password, so the address has no inbox \u2014 nothing may be emailed to it until the member claims a real one."
|
|
71264
|
+
)
|
|
71265
|
+
});
|
|
71266
|
+
var pendingInvitationSchema = zod_default.object({
|
|
71267
|
+
invitation_id: zod_default.string().describe("Unique identifier for the pending invitation"),
|
|
71268
|
+
organization_id: zod_default.string().describe("Organization the invitee will join on accept"),
|
|
71269
|
+
email: zod_default.string().describe("Email the invitation was sent to"),
|
|
71270
|
+
name: zod_default.string().nullable().describe("Admin-supplied display name (carried onto member.name on accept; invitee can override at accept time)"),
|
|
71271
|
+
role: zod_default.enum(["owner", "admin", "member"]).describe("Role the invitee will receive on accept"),
|
|
71272
|
+
expires_at: zod_default.string().describe("ISO timestamp when the invitation expires")
|
|
71273
|
+
});
|
|
71274
|
+
var workspaceSchema = zod_default.object({
|
|
71275
|
+
id: zod_default.string().describe("Unique identifier for the workspace"),
|
|
71276
|
+
name: zod_default.string().describe("Display name of the workspace"),
|
|
71277
|
+
default_currency: zod_default.string().describe("Default currency code for the workspace"),
|
|
71278
|
+
timezone: zod_default.string().describe("IANA timezone name (e.g., 'America/New_York', 'Asia/Tokyo')"),
|
|
71279
|
+
organization_id: zod_default.string().describe("Organization ID this workspace belongs to"),
|
|
71280
|
+
created_at: zod_default.string().describe("Timestamp when workspace was created")
|
|
71281
|
+
});
|
|
71282
|
+
var memberGroupSchema = zod_default.object({
|
|
71283
|
+
id: zod_default.string().describe("Unique identifier for the member group"),
|
|
71284
|
+
name: zod_default.string().describe("Display name of the group"),
|
|
71285
|
+
description: zod_default.string().optional().describe("Optional description of the group's purpose"),
|
|
71286
|
+
member_ids: zod_default.array(zod_default.string()).describe("Array of member IDs in this group"),
|
|
71287
|
+
invitation_ids: zod_default.array(zod_default.string()).describe("Array of pending invitation IDs pre-granted membership; migrated to member_ids on accept"),
|
|
71288
|
+
organization_id: zod_default.string().describe("ID of the organization this group belongs to"),
|
|
71289
|
+
created_at: zod_default.string().describe("Timestamp when group was created"),
|
|
71290
|
+
created_by: zod_default.string().describe("Member ID of the user who created this group")
|
|
71291
|
+
});
|
|
71292
|
+
var principalGroupSchema = zod_default.object({
|
|
71293
|
+
id: zod_default.string().describe("Unique identifier for the member group"),
|
|
71294
|
+
name: zod_default.string().describe("Display name of the group"),
|
|
71295
|
+
description: zod_default.string().optional().describe("Optional description of the group's purpose"),
|
|
71296
|
+
member_count: zod_default.number().int().describe("Number of accepted members in the group"),
|
|
71297
|
+
invitation_count: zod_default.number().int().describe("Number of pending invitations pre-granted membership")
|
|
71298
|
+
});
|
|
71299
|
+
var PUBLIC_PRINCIPAL_ID = "public";
|
|
71300
|
+
var principalSchema = zod_default.discriminatedUnion("type", [
|
|
71301
|
+
zod_default.object({
|
|
71302
|
+
type: zod_default.literal("member").describe("Principal type: individual member"),
|
|
71303
|
+
id: zod_default.string().describe("Member ID")
|
|
71304
|
+
}),
|
|
71305
|
+
zod_default.object({
|
|
71306
|
+
type: zod_default.literal("member_group").describe("Principal type: group of members"),
|
|
71307
|
+
id: zod_default.string().describe("Member group ID")
|
|
71308
|
+
}),
|
|
71309
|
+
zod_default.object({
|
|
71310
|
+
type: zod_default.literal("organization").describe("Principal type: all members in organization"),
|
|
71311
|
+
id: zod_default.string().describe("Organization ID")
|
|
71312
|
+
}),
|
|
71313
|
+
zod_default.object({
|
|
71314
|
+
type: zod_default.literal("public").describe("Principal type: anyone, including unauthenticated visitors"),
|
|
71315
|
+
id: zod_default.literal(PUBLIC_PRINCIPAL_ID).describe("Always the `public` sentinel \u2014 no entity")
|
|
71316
|
+
}),
|
|
71317
|
+
// Pending invitation as principal: lets admins pre-grant group membership and
|
|
71318
|
+
// resource access before the invitee accepts. Never resolved as a Subject —
|
|
71319
|
+
// a pending invitee cannot authenticate, so these bindings stay dormant until
|
|
71320
|
+
// accept-time migration rewrites them to type:"member".
|
|
71321
|
+
zod_default.object({
|
|
71322
|
+
type: zod_default.literal("invitation").describe("Principal type: pending invitation (not yet accepted)"),
|
|
71323
|
+
id: zod_default.string().describe("Invitation ID")
|
|
71324
|
+
})
|
|
71325
|
+
]);
|
|
71326
|
+
var subjectSchema = zod_default.discriminatedUnion("type", [
|
|
71327
|
+
zod_default.object({
|
|
71328
|
+
type: zod_default.literal("member").describe("Subject type: authenticated member"),
|
|
71329
|
+
id: zod_default.string().describe("Member ID")
|
|
71330
|
+
}),
|
|
71331
|
+
zod_default.object({
|
|
71332
|
+
type: zod_default.literal("public").describe("Subject type: unauthenticated visitor")
|
|
71333
|
+
})
|
|
71334
|
+
]);
|
|
71335
|
+
var resourceTypeSchema = zod_default.enum(["table", "table_view", "app", "automation", "skill", "document_template", "instruction", "knowledge_doc"]);
|
|
71336
|
+
var resourceRoleBindingSchema = zod_default.object({
|
|
71337
|
+
id: zod_default.string().describe("Unique identifier for the role binding"),
|
|
71338
|
+
principal: principalSchema.describe(
|
|
71339
|
+
"Who this role binding applies to (member, group, or organization)"
|
|
71340
|
+
),
|
|
71341
|
+
resource_type: resourceTypeSchema.describe("Type of resource being accessed"),
|
|
71342
|
+
resource_id: zod_default.string().describe("ID of the specific resource"),
|
|
71343
|
+
role: zod_default.string().describe("Role name (e.g., 'viewer', 'editor', 'manager', 'user')")
|
|
71344
|
+
});
|
|
71345
|
+
|
|
71346
|
+
// ../shared/src/schemas/table_records.ts
|
|
71347
|
+
var tableWorkflowEventSchema = zod_default.enum([
|
|
71348
|
+
"before_create",
|
|
71349
|
+
"after_create",
|
|
71350
|
+
"before_update",
|
|
71351
|
+
"after_update",
|
|
71352
|
+
"before_delete",
|
|
71353
|
+
"after_delete"
|
|
71354
|
+
]);
|
|
71355
|
+
var tableWorkflowSchema = zod_default.object({
|
|
71356
|
+
id: zod_default.string().describe("Unique table-workflow binding ID (tbw_ prefix)"),
|
|
71357
|
+
name: zod_default.string().describe("Human-readable name"),
|
|
71358
|
+
description: zod_default.string().describe("Description of what this workflow does"),
|
|
71359
|
+
enabled: zod_default.boolean().describe("Whether this workflow is active"),
|
|
71360
|
+
event: tableWorkflowEventSchema.describe(
|
|
71361
|
+
"Lifecycle event that fires this workflow. before_* runs synchronously and may reject the mutation; after_* runs after commit and does not block."
|
|
71362
|
+
),
|
|
71363
|
+
workflow_id: zod_default.string().describe(
|
|
71364
|
+
"ID of the workflow row that owns this binding's steps. The workflow's steps_v2 is the source of truth for the AST."
|
|
71365
|
+
),
|
|
71366
|
+
// Recursive v2 expression AST. Lazy schema would crash the OpenAPI walker;
|
|
71367
|
+
// runtime is `unknown` and the casted Zod type preserves the compile-time
|
|
71368
|
+
// signature for callers. Write paths re-parse with the strict schema before
|
|
71369
|
+
// storage.
|
|
71370
|
+
if: zod_default.unknown().nullable().optional().describe(
|
|
71371
|
+
"Optional pre-execution gate. Evaluated against the trigger context (record / prev_record / changes / runtime); the workflow fires only when truthy. Skip gating means the workflow always fires."
|
|
71372
|
+
),
|
|
71373
|
+
created_at: zod_default.string().describe("When the binding was created"),
|
|
71374
|
+
updated_at: zod_default.string().describe("When the binding was last modified"),
|
|
71375
|
+
archived_at: zod_default.string().nullable().optional().describe(
|
|
71376
|
+
"Set when the binding was removed (soft-delete). An archived binding never fires and is hidden from active listings, but is restorable; null/absent = active."
|
|
71377
|
+
)
|
|
71378
|
+
});
|
|
71379
|
+
var tableWorkflowMessageSchema = zod_default.object({
|
|
71380
|
+
table_workflow_id: zod_default.string().describe("tbw_* binding that emitted the message."),
|
|
71381
|
+
workflow_name: zod_default.string().describe("Human name of the workflow at execution time."),
|
|
71382
|
+
event: tableWorkflowEventSchema.describe(
|
|
71383
|
+
"Lifecycle event that produced the message. Only before_* events can surface here."
|
|
71384
|
+
),
|
|
71385
|
+
record_id: zod_default.string().describe(
|
|
71386
|
+
"Record that triggered the workflow. Lets the UI scope the message to a specific row in bulk responses."
|
|
71387
|
+
),
|
|
71388
|
+
message: zod_default.string().describe("Author-provided text from the workflow's return.message.")
|
|
71389
|
+
});
|
|
71390
|
+
var tableSchema = zod_default.object({
|
|
71391
|
+
id: zod_default.string().describe("Unique identifier for the table"),
|
|
71392
|
+
workspace_id: zod_default.string().describe("ID of the workspace this table belongs to"),
|
|
71393
|
+
name: zod_default.string().describe("Display name of the table"),
|
|
71394
|
+
description: zod_default.string().describe("Description of the table's purpose"),
|
|
71395
|
+
position: zod_default.number().int().optional().nullable().describe("Display ordering index for the table. Lower numbers are shown first. "),
|
|
71396
|
+
fields: tableFieldsSchema.describe("Array of field definitions for this table"),
|
|
71397
|
+
workflows: zod_default.array(tableWorkflowSchema).optional().describe(
|
|
71398
|
+
"Workflows attached to this table that fire around record mutations. before_* run synchronously and may reject; after_* run after commit and do not block."
|
|
71399
|
+
),
|
|
71400
|
+
private_filters: tableRecordFiltersGroupNodeSchema.nullable().optional().describe("Row-level private filters AND'd to every query as a security boundary (admin bypass)"),
|
|
71401
|
+
colors: tableRecordColorsSchema.nullable().optional().describe("Color rules for styling records based on filter conditions"),
|
|
71402
|
+
approvers: zod_default.array(principalSchema).nullable().optional().describe(
|
|
71403
|
+
"Principals (members, groups, or the organization) who review locked-record change requests on this table. Null/empty = organization admins review. The requester never reviews their own request."
|
|
71404
|
+
),
|
|
71405
|
+
created_at: zod_default.string().describe("Timestamp when table was created")
|
|
71406
|
+
});
|
|
71407
|
+
var recordDataTemplateSchema = zod_default.object({
|
|
71408
|
+
id: zod_default.string().describe("Unique identifier for the record data template"),
|
|
71409
|
+
name: zod_default.string().describe("Display name of the record data template"),
|
|
71410
|
+
description: zod_default.string().describe("Description of the record data template"),
|
|
71411
|
+
table_id: zod_default.string().describe("ID of the table this record template belongs to"),
|
|
71412
|
+
data: zod_default.record(zod_default.string(), zod_default.unknown()).describe("The data of the record template. The key is the Field key.")
|
|
71413
|
+
});
|
|
71414
|
+
var tableRecordSchema = zod_default.object({
|
|
71415
|
+
id: zod_default.string().describe("Unique identifier for the record"),
|
|
71416
|
+
table_id: zod_default.string().describe("ID of the table this record belongs to"),
|
|
71417
|
+
workspace_id: zod_default.string().describe("ID of the workspace this record belongs to"),
|
|
71418
|
+
data: zod_default.record(zod_default.string(), zod_default.unknown()).describe("The data of the record. The key is the Field key."),
|
|
71419
|
+
locked: zod_default.boolean().optional().describe("Whether the entire record is locked from editing"),
|
|
71420
|
+
draft: zod_default.boolean().optional().describe("Whether the record is an unsubmitted draft \u2014 UI-only in-progress state, not yet a real row. Row-visibility scoping is enforced at submit, not while a draft is being filled in."),
|
|
71421
|
+
updated_at: zod_default.string().describe("Timestamp of last update"),
|
|
71422
|
+
created_at: zod_default.string().describe("Timestamp when record was created")
|
|
71423
|
+
});
|
|
71424
|
+
var viewSummaryEntrySchema = zod_default.object({
|
|
71425
|
+
operation: zod_default.string().describe("Operation to perform on the field"),
|
|
71426
|
+
field_key: zod_default.string().describe("Field key to display in the summary row")
|
|
71427
|
+
});
|
|
71428
|
+
var viewSummarySchema = zod_default.record(zod_default.string(), viewSummaryEntrySchema.nullable().optional()).nullable().optional().describe("Map of field keys to summary operations.");
|
|
71429
|
+
var visibleToEntrySchema = zod_default.object({
|
|
71430
|
+
type: zod_default.enum(["member", "group"]).describe("Principal kind that may see the view: an individual member or a member group"),
|
|
71431
|
+
id: zod_default.string().describe("Member ID (type=member) or member-group ID (type=group)")
|
|
71432
|
+
});
|
|
71433
|
+
var visibleToSchema = zod_default.array(visibleToEntrySchema).nullable();
|
|
71434
|
+
var tableViewSchema = zod_default.object({
|
|
71435
|
+
id: zod_default.string().describe("Unique identifier for the view"),
|
|
71436
|
+
table_id: zod_default.string().describe("ID of the table this view displays"),
|
|
71437
|
+
workspace_id: zod_default.string().describe("ID of the workspace this view belongs to"),
|
|
71438
|
+
name: zod_default.string().describe("Display name of the view"),
|
|
71439
|
+
description: zod_default.string().describe("Description of the view's purpose"),
|
|
71440
|
+
visible_to: visibleToSchema.optional().describe(
|
|
71441
|
+
"Sidebar declutter list (NOT access control). null/absent = every member with access to the parent table sees this view; a non-empty list of members/groups restricts who sees it in the explorer. [] is normalized to null on write."
|
|
71442
|
+
),
|
|
71443
|
+
position: zod_default.number().int().nullable().describe(
|
|
71444
|
+
"Display ordering index for the view. Lower numbers are shown first. Use incremental values with gaps (100, 200, 300) instead of consecutive numbers (1, 2, 3) to enable efficient reordering without updating multiple records. Example: To insert between 100 and 200, use 150."
|
|
71445
|
+
),
|
|
71446
|
+
frozen_columns: zod_default.number().int().nullable().optional().describe("Number of columns to freeze. Frozen columns are not scrollable."),
|
|
71447
|
+
summary: viewSummarySchema,
|
|
71448
|
+
default_record_data_template_id: zod_default.string().nullable().optional().describe("ID of the record template to use as the default record initial data"),
|
|
71449
|
+
field_config: zod_default.array(fieldConfigEntrySchema).describe(
|
|
71450
|
+
"Ordered array of field config entries. Order = display order, visibility = per-entry. Fields not listed are hidden."
|
|
71451
|
+
),
|
|
71452
|
+
sort: tableRecordSortSchema.nullable().describe("Sorting configuration for records in this view"),
|
|
71453
|
+
filters: tableRecordFiltersGroupNodeSchema.nullable().describe("Filter conditions applied to records in this view"),
|
|
71454
|
+
created_at: zod_default.string().describe("Timestamp when view was created")
|
|
71455
|
+
});
|
|
71456
|
+
var tableWithViewsSchema = tableSchema.extend({
|
|
71457
|
+
views: zod_default.array(tableViewSchema).describe("Array of views for this table")
|
|
71458
|
+
});
|
|
71459
|
+
var explorerViewSchema = zod_default.object({
|
|
71460
|
+
id: zod_default.string(),
|
|
71461
|
+
name: zod_default.string(),
|
|
71462
|
+
owner_member_id: zod_default.string(),
|
|
71463
|
+
// Per-view sidebar declutter list (NOT access control). null = every member
|
|
71464
|
+
// with table access sees this view; a non-empty member/group list restricts
|
|
71465
|
+
// it. Surfaced here so the table share dialog can render and edit each view's
|
|
71466
|
+
// audience without a second round-trip.
|
|
71467
|
+
visible_to: visibleToSchema.optional(),
|
|
71468
|
+
// Per-requesting-member sidebar preference: true if this member has hidden
|
|
71469
|
+
// the view. Hiding is UX-only — it never affects access or other members.
|
|
71470
|
+
hidden: zod_default.boolean()
|
|
71471
|
+
});
|
|
71472
|
+
var explorerTableSchema = zod_default.object({
|
|
71473
|
+
id: zod_default.string(),
|
|
71474
|
+
name: zod_default.string(),
|
|
71475
|
+
position: zod_default.number().int().nullable().optional(),
|
|
71476
|
+
views: zod_default.array(explorerViewSchema),
|
|
71477
|
+
owner_member_id: zod_default.string(),
|
|
71478
|
+
// Active package installations whose binding includes this table — the
|
|
71479
|
+
// sidebar marks these so members see the structure is app-managed before
|
|
71480
|
+
// they try to change it. Absent for unbound tables.
|
|
71481
|
+
package_apps: zod_default.array(zod_default.object({ id: zod_default.string(), name: zod_default.string() })).optional()
|
|
71482
|
+
});
|
|
71483
|
+
var documentTemplateTypeSchema = zod_default.enum(["html", "pdf-form", "excel", "word", "email"]).describe("Template type: 'html' for HTML templates, 'pdf-form' for fillable PDF forms, 'excel' for Excel templates, 'word' for Word templates, 'email' for email HTML templates");
|
|
71484
|
+
var documentTemplateSchema = zod_default.object({
|
|
71485
|
+
id: zod_default.string().describe("Unique identifier for the document template"),
|
|
71486
|
+
workspace_id: zod_default.string().describe("ID of the workspace this template belongs to"),
|
|
71487
|
+
name: zod_default.string().describe("Display name of the template"),
|
|
71488
|
+
type: documentTemplateTypeSchema,
|
|
71489
|
+
template: zod_default.string().describe("Template content with variable placeholders (e.g., {{customer_name}})"),
|
|
71490
|
+
format: zod_default.string().describe("Supported document formats.").optional(),
|
|
71491
|
+
orientation: zod_default.enum(["portrait", "landscape"]).describe("Page orientation for PDF generation").optional(),
|
|
71492
|
+
variables: zod_default.record(zod_default.string(), zod_default.unknown()).describe("Data to pass to the template."),
|
|
71493
|
+
current_version: zod_default.number().describe("Current version number of the template"),
|
|
71494
|
+
created_at: zod_default.string().describe("Timestamp when template was created"),
|
|
71495
|
+
template_url: zod_default.string().nullable().describe("Signed URL to download the template file (pdf-form/excel only)")
|
|
71496
|
+
});
|
|
71497
|
+
|
|
71498
|
+
// ../shared/src/schemas/packages.ts
|
|
71499
|
+
var contractAliasSchema = zod_default.string().regex(
|
|
71500
|
+
/^[a-z][a-z0-9_]*$/,
|
|
71501
|
+
"alias must be a lowercase slug: start with a letter, then letters/digits/underscores"
|
|
71502
|
+
);
|
|
71503
|
+
var runtimeAliasSchema = zod_default.string().min(1).max(200);
|
|
71504
|
+
var contractFieldBaseSchema = zod_default.object({
|
|
71505
|
+
alias: contractAliasSchema.describe("Stable local alias, unique within the entity"),
|
|
71506
|
+
// No braces: scaffold translates formula expressions from `{alias}` to the
|
|
71507
|
+
// platform's `{Field Label}` reference form, so a brace inside a label would
|
|
71508
|
+
// corrupt every formula that references the field.
|
|
71509
|
+
label: zod_default.string().min(1).regex(/^[^{}]*$/, "field labels cannot contain { or }").describe("Display label used as the field name at scaffold time"),
|
|
71510
|
+
description: zod_default.string().optional(),
|
|
71511
|
+
required: zod_default.boolean().optional().describe(
|
|
71512
|
+
"Advisory only: marks the field required for app-form/workflow UX. The table data model has no required constraint, so scaffold does NOT enforce it at the schema level \u2014 validation lives in the app/workflow layer."
|
|
71513
|
+
)
|
|
71514
|
+
});
|
|
71515
|
+
var contractSelectOptionSchema = zod_default.object({
|
|
71516
|
+
alias: contractAliasSchema.describe("Stable local alias, unique within the field"),
|
|
71517
|
+
label: zod_default.string().min(1).describe("Display label for the option"),
|
|
71518
|
+
color: optionColorSchema
|
|
71519
|
+
});
|
|
71520
|
+
var contractAutonumberConfigSchema = tableAutonumberFieldSchema.pick({
|
|
71521
|
+
prefix: true,
|
|
71522
|
+
padding: true,
|
|
71523
|
+
template: true
|
|
71524
|
+
});
|
|
71525
|
+
var contractTextFieldSchema = contractFieldBaseSchema.extend({
|
|
71526
|
+
type: zod_default.literal("text"),
|
|
71527
|
+
unique: zod_default.boolean().optional().describe("Unique values required"),
|
|
71528
|
+
format: textFormatSchema.optional()
|
|
71529
|
+
});
|
|
71530
|
+
var contractNumberFieldSchema = contractFieldBaseSchema.extend({
|
|
71531
|
+
type: zod_default.literal("number"),
|
|
71532
|
+
format: numberFormatSchema.optional(),
|
|
71533
|
+
currency: zod_default.string().optional().describe("ISO 4217 code")
|
|
71534
|
+
});
|
|
71535
|
+
var contractDateFieldSchema = contractFieldBaseSchema.extend({
|
|
71536
|
+
type: zod_default.literal("date"),
|
|
71537
|
+
format: dateFormatSchema.optional(),
|
|
71538
|
+
timezone: zod_default.string().optional().describe("IANA timezone"),
|
|
71539
|
+
derive_from: zod_default.enum(["created_at", "updated_at"]).optional().describe("Auto-populate from the row's system timestamp; the field becomes read-only.")
|
|
71540
|
+
});
|
|
71541
|
+
var contractBooleanFieldSchema = contractFieldBaseSchema.extend({
|
|
71542
|
+
type: zod_default.literal("boolean")
|
|
71543
|
+
});
|
|
71544
|
+
var contractSelectFieldSchema = contractFieldBaseSchema.extend({
|
|
71545
|
+
type: zod_default.literal("select"),
|
|
71546
|
+
options: zod_default.array(contractSelectOptionSchema).min(1),
|
|
71547
|
+
multi: zod_default.boolean().optional().describe("Allow multiple selections")
|
|
71548
|
+
});
|
|
71549
|
+
var contractSelectMemberFieldSchema = contractFieldBaseSchema.extend({
|
|
71550
|
+
type: zod_default.literal("select_member"),
|
|
71551
|
+
multi: zod_default.boolean().optional().describe("Allow multiple selections")
|
|
71552
|
+
});
|
|
71553
|
+
var contractSelectRecordLinkFieldSchema = contractFieldBaseSchema.extend({
|
|
71554
|
+
type: zod_default.literal("select_record_link"),
|
|
71555
|
+
target_entity: contractAliasSchema.describe("Alias of the entity this field links to"),
|
|
71556
|
+
sync_both_ways: zod_default.boolean().optional().describe("Create a paired link field on the target entity for bidirectional sync"),
|
|
71557
|
+
paired_field_alias: contractAliasSchema.optional().describe(
|
|
71558
|
+
"The pair edge of a bidirectional link: the field alias ON THE TARGET ENTITY that is this link's sync partner. Both sides of a pair carry it, each naming the other. Scaffold creates whichever side it reaches first WITH the pairing (the platform auto-creates the partner) and binds the partner alias to the auto-created field \u2014 without this edge the two contract fields would be created independently and collide with the auto-created partner."
|
|
71559
|
+
),
|
|
71560
|
+
cardinality: zod_default.enum(["one", "many"]).optional().describe("How many linked records this field holds. Default 'many'."),
|
|
71561
|
+
display_field_aliases: zod_default.array(contractAliasSchema).optional().describe("Field aliases on the target entity shown as the link's display text / picker columns")
|
|
71562
|
+
});
|
|
71563
|
+
var contractFilesFieldSchema = contractFieldBaseSchema.extend({
|
|
71564
|
+
type: zod_default.literal("files")
|
|
71565
|
+
});
|
|
71566
|
+
var contractFormulaFieldSchema = contractFieldBaseSchema.extend({
|
|
71567
|
+
type: zod_default.literal("formula"),
|
|
71568
|
+
formula: formulaInputSchema.describe(
|
|
71569
|
+
"Formula config. The expression references other fields on the SAME entity by alias in braces, e.g. `{quantity} * {unit_price}`."
|
|
71570
|
+
)
|
|
71571
|
+
});
|
|
71572
|
+
var contractRollupFieldSchema = contractFieldBaseSchema.extend({
|
|
71573
|
+
type: zod_default.literal("rollup"),
|
|
71574
|
+
source_field_alias: contractAliasSchema.describe(
|
|
71575
|
+
"Alias of a select_record_link field on this entity to roll up from"
|
|
71576
|
+
),
|
|
71577
|
+
aggregate_option: aggregateOptionSchema.describe(
|
|
71578
|
+
"Aggregation operation. Its `field_key` names a field alias on the linked entity."
|
|
71579
|
+
)
|
|
71580
|
+
});
|
|
71581
|
+
var contractLookupFieldSchema = contractFieldBaseSchema.extend({
|
|
71582
|
+
type: zod_default.literal("lookup"),
|
|
71583
|
+
source_field_alias: contractAliasSchema.describe(
|
|
71584
|
+
"Alias of a select_record_link field on this entity to look up through"
|
|
71585
|
+
),
|
|
71586
|
+
lookup_field_alias: contractAliasSchema.describe(
|
|
71587
|
+
"Alias of the field on the linked entity to display"
|
|
71588
|
+
),
|
|
71589
|
+
order_by: lookupOrderBySchema.optional().describe("Ordered lookup. Its `field_key` names a field alias on the linked entity.")
|
|
71590
|
+
});
|
|
71591
|
+
var contractAutonumberFieldSchema = contractFieldBaseSchema.extend({
|
|
71592
|
+
type: zod_default.literal("autonumber"),
|
|
71593
|
+
...contractAutonumberConfigSchema.shape
|
|
71594
|
+
});
|
|
71595
|
+
var contractFieldSchema = zod_default.discriminatedUnion("type", [
|
|
71596
|
+
contractTextFieldSchema,
|
|
71597
|
+
contractNumberFieldSchema,
|
|
71598
|
+
contractDateFieldSchema,
|
|
71599
|
+
contractBooleanFieldSchema,
|
|
71600
|
+
contractSelectFieldSchema,
|
|
71601
|
+
contractSelectMemberFieldSchema,
|
|
71602
|
+
contractSelectRecordLinkFieldSchema,
|
|
71603
|
+
contractFilesFieldSchema,
|
|
71604
|
+
contractFormulaFieldSchema,
|
|
71605
|
+
contractRollupFieldSchema,
|
|
71606
|
+
contractLookupFieldSchema,
|
|
71607
|
+
contractAutonumberFieldSchema
|
|
71608
|
+
]);
|
|
71609
|
+
var contractEntitySchema = zod_default.object({
|
|
71610
|
+
alias: contractAliasSchema.describe("Stable entity alias, unique within the contract"),
|
|
71611
|
+
label: zod_default.string().min(1).describe("Display label used as the table name at scaffold time"),
|
|
71612
|
+
description: zod_default.string().optional(),
|
|
71613
|
+
fields: zod_default.array(contractFieldSchema).min(1)
|
|
71614
|
+
});
|
|
71615
|
+
var contractRoleSchema = zod_default.object({
|
|
71616
|
+
alias: contractAliasSchema.describe("Stable role alias, bound to a workspace group at install"),
|
|
71617
|
+
label: zod_default.string().min(1)
|
|
71618
|
+
});
|
|
71619
|
+
var contractTemplateBaseSchema = zod_default.object({
|
|
71620
|
+
alias: contractAliasSchema.describe("Stable template alias, unique within the contract"),
|
|
71621
|
+
label: zod_default.string().min(1),
|
|
71622
|
+
content_sha256: zod_default.string().optional().describe(
|
|
71623
|
+
"sha256 (64-char lowercase hex) of the template content \u2014 inline: the utf-8 content string; file-backed: the bytes_ref bytes. The modified-detection reference. Optional in the schema so contracts published before template sha still parse; REQUIRED at publish (validatePackageContract)."
|
|
71624
|
+
)
|
|
71625
|
+
});
|
|
71626
|
+
var contractInlineTemplateSchema = (templateType) => contractTemplateBaseSchema.extend({
|
|
71627
|
+
type: zod_default.literal(templateType),
|
|
71628
|
+
content: zod_default.string().min(1).describe("Inline template content; placeholders reference field aliases")
|
|
71629
|
+
});
|
|
71630
|
+
var contractFileTemplateSchema = (templateType) => contractTemplateBaseSchema.extend({
|
|
71631
|
+
type: zod_default.literal(templateType),
|
|
71632
|
+
bytes_ref: zod_default.string().min(1).describe("Path of the backing file within the package bundle; markers reference field aliases")
|
|
71633
|
+
});
|
|
71634
|
+
var contractTemplateSchema = zod_default.discriminatedUnion("type", [
|
|
71635
|
+
contractInlineTemplateSchema("html"),
|
|
71636
|
+
contractInlineTemplateSchema("email"),
|
|
71637
|
+
contractFileTemplateSchema("excel"),
|
|
71638
|
+
contractFileTemplateSchema("word"),
|
|
71639
|
+
contractFileTemplateSchema("pdf-form")
|
|
71640
|
+
]);
|
|
71641
|
+
var contractFromTableNodeSchema = zod_default.object({
|
|
71642
|
+
kind: zod_default.literal("from_table"),
|
|
71643
|
+
from_entity: contractAliasSchema.describe("Entity alias this query reads from"),
|
|
71644
|
+
filter: tableRecordFiltersSchema.optional(),
|
|
71645
|
+
search: zod_default.string().optional(),
|
|
71646
|
+
sort: tableRecordSortSchema.optional(),
|
|
71647
|
+
limit: zod_default.number().optional()
|
|
71648
|
+
});
|
|
71649
|
+
var contractProjectNodeSchema = zod_default.object({
|
|
71650
|
+
kind: zod_default.literal("project"),
|
|
71651
|
+
from: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71652
|
+
columns: zod_default.array(queryProjectionColumnSchema).min(1)
|
|
71653
|
+
});
|
|
71654
|
+
var contractFilterNodeSchema = zod_default.object({
|
|
71655
|
+
kind: zod_default.literal("filter"),
|
|
71656
|
+
from: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71657
|
+
predicate: tableRecordFiltersSchema
|
|
71658
|
+
});
|
|
71659
|
+
var contractJoinNodeSchema = zod_default.object({
|
|
71660
|
+
kind: zod_default.literal("join"),
|
|
71661
|
+
left: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71662
|
+
right: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71663
|
+
on: queryJoinPredicateSchema,
|
|
71664
|
+
type: zod_default.enum(["inner", "left"])
|
|
71665
|
+
});
|
|
71666
|
+
var contractUnionNodeSchema = zod_default.object({
|
|
71667
|
+
kind: zod_default.literal("union"),
|
|
71668
|
+
sources: zod_default.array(zod_default.lazy(() => contractQueryNodeSchema)).min(2)
|
|
71669
|
+
});
|
|
71670
|
+
var contractGroupNodeSchema = zod_default.object({
|
|
71671
|
+
kind: zod_default.literal("group"),
|
|
71672
|
+
from: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71673
|
+
by: zod_default.array(zod_default.string()),
|
|
71674
|
+
aggregates: zod_default.array(queryAggregateColumnSchema).min(1)
|
|
71675
|
+
});
|
|
71676
|
+
var contractWindowNodeSchema = zod_default.object({
|
|
71677
|
+
kind: zod_default.literal("window"),
|
|
71678
|
+
from: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71679
|
+
partition_by: zod_default.array(zod_default.string()),
|
|
71680
|
+
order_by: tableRecordSortSchema,
|
|
71681
|
+
frame: queryWindowFrameSchema.optional(),
|
|
71682
|
+
aggregates: zod_default.array(queryAggregateColumnSchema).optional(),
|
|
71683
|
+
functions: zod_default.array(queryWindowFunctionColumnSchema).optional()
|
|
71684
|
+
});
|
|
71685
|
+
var contractSortNodeSchema = zod_default.object({
|
|
71686
|
+
kind: zod_default.literal("sort"),
|
|
71687
|
+
from: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71688
|
+
by: tableRecordSortSchema
|
|
71689
|
+
});
|
|
71690
|
+
var contractLimitNodeSchema = zod_default.object({
|
|
71691
|
+
kind: zod_default.literal("limit"),
|
|
71692
|
+
from: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71693
|
+
n: zod_default.number().int().positive(),
|
|
71694
|
+
offset: zod_default.number().int().nonnegative().optional()
|
|
71695
|
+
});
|
|
71696
|
+
var contractUnpivotNodeSchema = zod_default.object({
|
|
71697
|
+
kind: zod_default.literal("unpivot"),
|
|
71698
|
+
from: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71699
|
+
passthrough: zod_default.array(queryUnpivotPassthroughColumnSchema),
|
|
71700
|
+
row_columns: zod_default.array(queryUnpivotRowColumnSchema).min(1),
|
|
71701
|
+
rows: zod_default.array(zod_default.record(zod_default.string(), querySourceSchema)).min(1)
|
|
71702
|
+
});
|
|
71703
|
+
var contractUnnestNodeSchema = zod_default.object({
|
|
71704
|
+
kind: zod_default.literal("unnest"),
|
|
71705
|
+
from: zod_default.lazy(() => contractQueryNodeSchema),
|
|
71706
|
+
source: zod_default.string(),
|
|
71707
|
+
output: zod_default.string(),
|
|
71708
|
+
display_output: zod_default.string().optional(),
|
|
71709
|
+
keep_empty: zod_default.boolean().optional()
|
|
71710
|
+
});
|
|
71711
|
+
var contractQueryNodeSchema = zod_default.lazy(
|
|
71712
|
+
() => zod_default.discriminatedUnion("kind", [
|
|
71713
|
+
contractFromTableNodeSchema,
|
|
71714
|
+
contractProjectNodeSchema,
|
|
71715
|
+
contractFilterNodeSchema,
|
|
71716
|
+
contractJoinNodeSchema,
|
|
71717
|
+
contractUnionNodeSchema,
|
|
71718
|
+
contractGroupNodeSchema,
|
|
71719
|
+
contractWindowNodeSchema,
|
|
71720
|
+
contractSortNodeSchema,
|
|
71721
|
+
contractLimitNodeSchema,
|
|
71722
|
+
contractUnpivotNodeSchema,
|
|
71723
|
+
contractUnnestNodeSchema
|
|
71724
|
+
])
|
|
71725
|
+
);
|
|
71726
|
+
var contractQuerySchema = zod_default.object({
|
|
71727
|
+
alias: runtimeAliasSchema.describe(
|
|
71728
|
+
"Stable query alias, unique within the contract \u2014 carried verbatim from the app (source invokes it at runtime)"
|
|
71729
|
+
),
|
|
71730
|
+
params: zod_default.record(zod_default.string(), appWorkflowInputSchema).optional().describe("Typed param schema. Keys are param names referenced as {{params.<name>}} in the ast."),
|
|
71731
|
+
ast: contractQueryNodeSchema
|
|
71732
|
+
});
|
|
71733
|
+
var contractLifecycleEventSchema = tableWorkflowEventSchema;
|
|
71734
|
+
var contractWorkflowTriggerSchema = zod_default.discriminatedUnion("type", [
|
|
71735
|
+
zod_default.object({ type: zod_default.literal("app") }),
|
|
71736
|
+
zod_default.object({
|
|
71737
|
+
type: zod_default.literal("entity_lifecycle"),
|
|
71738
|
+
entity: contractAliasSchema.describe("Alias of the entity whose lifecycle fires this workflow"),
|
|
71739
|
+
event: contractLifecycleEventSchema
|
|
71740
|
+
})
|
|
71741
|
+
]);
|
|
71742
|
+
var contractWorkflowSchema = zod_default.object({
|
|
71743
|
+
alias: runtimeAliasSchema.describe(
|
|
71744
|
+
"Stable workflow alias, unique within the contract \u2014 app-trigger aliases are carried verbatim from the app (source invokes them at runtime)"
|
|
71745
|
+
),
|
|
71746
|
+
trigger: contractWorkflowTriggerSchema,
|
|
71747
|
+
inputs: zod_default.record(zod_default.string(), appWorkflowInputSchema).optional().describe("Typed inputs. record_link `table_id` names an entity alias; member `group` a role alias."),
|
|
71748
|
+
outputs: zod_default.record(zod_default.string(), appWorkflowOutputSchema).optional().describe("Typed outputs. record_link `table_id` names an entity alias."),
|
|
71749
|
+
body: zod_default.string().min(1).describe("Alias-form JS-subset workflow source. Identifiers are resolved against the binding at materialize time.")
|
|
71750
|
+
});
|
|
71751
|
+
var contractAgentSchema = appAgentDeclarationSchema.extend({
|
|
71752
|
+
alias: runtimeAliasSchema.describe(
|
|
71753
|
+
"Stable agent alias, unique within the contract \u2014 carried verbatim from the app (source invokes it at runtime)"
|
|
71754
|
+
),
|
|
71755
|
+
knowledge_expects: zod_default.array(zod_default.string().min(1)).optional().describe(
|
|
71756
|
+
"Doc NAMES this agent must read that the package does NOT own \u2014 the installer's own docs. Resolved by name against the installing workspace: exactly one non-archived match binds, zero or several bind nothing and surface as an install warning, because doc names are not unique and picking one would be a guess. The agent installs either way."
|
|
71757
|
+
),
|
|
71758
|
+
knowledge_aliases: zod_default.array(contractAliasSchema).optional().describe(
|
|
71759
|
+
"Package knowledge docs this agent may read, by contract alias. Materialize resolves each against `binding.knowledge` to the installing workspace's own doc id and writes the agent's `knowledge_doc_ids`. Omit for an agent that reads no package knowledge \u2014 an agent whose declared set does not travel can read NOTHING, since a declared set bounds every read."
|
|
71760
|
+
)
|
|
71761
|
+
});
|
|
71762
|
+
var contractConfigBaseSchema = zod_default.object({
|
|
71763
|
+
alias: contractAliasSchema.describe("Stable config alias, unique within the contract"),
|
|
71764
|
+
label: zod_default.string().min(1),
|
|
71765
|
+
description: zod_default.string().optional()
|
|
71766
|
+
});
|
|
71767
|
+
var contractTextConfigSchema = contractConfigBaseSchema.extend({
|
|
71768
|
+
type: zod_default.literal("text"),
|
|
71769
|
+
default: zod_default.string()
|
|
71770
|
+
});
|
|
71771
|
+
var contractBooleanConfigSchema = contractConfigBaseSchema.extend({
|
|
71772
|
+
type: zod_default.literal("boolean"),
|
|
71773
|
+
default: zod_default.boolean()
|
|
71774
|
+
});
|
|
71775
|
+
var contractColorConfigSchema = contractConfigBaseSchema.extend({
|
|
71776
|
+
type: zod_default.literal("color"),
|
|
71777
|
+
default: optionColorSchema
|
|
71778
|
+
});
|
|
71779
|
+
var contractNumberConfigSchema = contractConfigBaseSchema.extend({
|
|
71780
|
+
type: zod_default.literal("number"),
|
|
71781
|
+
default: zod_default.number()
|
|
71782
|
+
});
|
|
71783
|
+
var contractSelectConfigSchema = contractConfigBaseSchema.extend({
|
|
71784
|
+
type: zod_default.literal("select"),
|
|
71785
|
+
options: zod_default.array(zod_default.object({ value: zod_default.string(), label: zod_default.string().min(1) })).min(1),
|
|
71786
|
+
default: zod_default.string()
|
|
71787
|
+
});
|
|
71788
|
+
var contractConfigEntrySchema = zod_default.discriminatedUnion("type", [
|
|
71789
|
+
contractTextConfigSchema,
|
|
71790
|
+
contractBooleanConfigSchema,
|
|
71791
|
+
contractColorConfigSchema,
|
|
71792
|
+
contractNumberConfigSchema,
|
|
71793
|
+
contractSelectConfigSchema
|
|
71794
|
+
]);
|
|
71795
|
+
var packageKindSchema = zod_default.enum(["app", "content"]);
|
|
71796
|
+
var contractKnowledgeEntrySchema = zod_default.object({
|
|
71797
|
+
name: zod_default.string().min(1).describe(
|
|
71798
|
+
"Display name \u2014 the runtime routing key an agent resolves the doc by; unique across the contract's knowledge"
|
|
71799
|
+
),
|
|
71800
|
+
description: zod_default.string().describe("Doc description (may be empty)"),
|
|
71801
|
+
// Optional so contracts published before folders still parse; absent means
|
|
71802
|
+
// root. A curated corpus is exactly the case where organization is authored
|
|
71803
|
+
// deliberately, so install and upgrade have to carry it — otherwise every
|
|
71804
|
+
// installed corpus lands flat and the customer re-files it by hand.
|
|
71805
|
+
path: zod_default.string().optional().describe("Folder the doc is filed under; omitted means root"),
|
|
71806
|
+
content_ref: zod_default.string().min(1).describe("Path of the content file within the bundle \u2014 must be `knowledge/<alias>.md`"),
|
|
71807
|
+
content_sha256: zod_default.string().describe("sha256 (64-char lowercase hex) of the content bytes \u2014 the modified-detection reference")
|
|
71808
|
+
});
|
|
71809
|
+
var contractKnowledgeSchema = zod_default.record(contractAliasSchema, contractKnowledgeEntrySchema);
|
|
71810
|
+
var packageContractSchema = zod_default.object({
|
|
71811
|
+
entities: zod_default.array(contractEntitySchema).default([]),
|
|
71812
|
+
roles: zod_default.array(contractRoleSchema).default([]),
|
|
71813
|
+
templates: zod_default.array(contractTemplateSchema).default([]),
|
|
71814
|
+
queries: zod_default.array(contractQuerySchema).default([]),
|
|
71815
|
+
workflows: zod_default.array(contractWorkflowSchema).default([]),
|
|
71816
|
+
agents: zod_default.array(contractAgentSchema).default([]),
|
|
71817
|
+
config: zod_default.array(contractConfigEntrySchema).default([]),
|
|
71818
|
+
// Package-managed knowledge docs (alias → metadata + content sha). Defaults to
|
|
71819
|
+
// {} so contracts published before knowledge packaging still parse.
|
|
71820
|
+
knowledge: contractKnowledgeSchema.default({}),
|
|
71821
|
+
// Doc NAMES the package's agents route to but the package does not own —
|
|
71822
|
+
// install/health WARN (advisory) when a name has no doc in the workspace.
|
|
71823
|
+
// The first instance of the general cross-package "expects" contract.
|
|
71824
|
+
knowledge_expects: zod_default.array(zod_default.string()).default([])
|
|
71825
|
+
});
|
|
71826
|
+
var bindingMapSchema = zod_default.record(zod_default.string().min(1), zod_default.string().min(1));
|
|
71827
|
+
var bindingSchema = zod_default.object({
|
|
71828
|
+
entities: bindingMapSchema.default({}),
|
|
71829
|
+
fields: bindingMapSchema.default({}),
|
|
71830
|
+
options: bindingMapSchema.default({}),
|
|
71831
|
+
templates: bindingMapSchema.default({}),
|
|
71832
|
+
roles: bindingMapSchema.default({}),
|
|
71833
|
+
// Artifact registry, not a schema binding: the package-owned table-workflow
|
|
71834
|
+
// ROW id per entity_lifecycle workflow alias. Materialize matches/updates by
|
|
71835
|
+
// this id (a display name is forgeable and renameable), upgrade prunes by
|
|
71836
|
+
// it, and hashes look rows up through it. Excluded from BINDING_NAMESPACES:
|
|
71837
|
+
// a deleted row is a modified-core finding (fingerprints), never binding
|
|
71838
|
+
// drift, so validateBinding/applyDriftResolutions ignore it.
|
|
71839
|
+
workflows: bindingMapSchema.default({}),
|
|
71840
|
+
// The app's BUNDLED knowledge corpus: contract knowledge alias → the
|
|
71841
|
+
// workspace's concrete `kdc_` id. One row, one pin — the app installation IS
|
|
71842
|
+
// the anchor for its bundled docs (`package_content_installations` rows are
|
|
71843
|
+
// standalone content packages only). Excluded from BINDING_NAMESPACES: a
|
|
71844
|
+
// gone/edited doc is detected by the knowledge upgrade preview (live doc +
|
|
71845
|
+
// content-sha reads), never by validateBinding's live-id sweep.
|
|
71846
|
+
knowledge: bindingMapSchema.default({})
|
|
71847
|
+
});
|
|
71848
|
+
var BINDING_NAMESPACES = ["entities", "fields", "options", "templates", "roles"];
|
|
71849
|
+
var contentBindingMapSchema = zod_default.record(zod_default.string().min(1), zod_default.string().min(1));
|
|
71850
|
+
var packageContentBindingSchema = zod_default.object({
|
|
71851
|
+
knowledge: contentBindingMapSchema.default({}),
|
|
71852
|
+
templates: contentBindingMapSchema.default({})
|
|
71853
|
+
});
|
|
71854
|
+
var bindingDriftSchema = zod_default.object({
|
|
71855
|
+
namespace: zod_default.enum(BINDING_NAMESPACES),
|
|
71856
|
+
alias: zod_default.string(),
|
|
71857
|
+
id: zod_default.string().describe("The stale concrete id the alias was bound to")
|
|
71858
|
+
});
|
|
71859
|
+
var driftResolutionSchema = zod_default.union([
|
|
71860
|
+
zod_default.literal("recreate"),
|
|
71861
|
+
zod_default.object({ bind_to: zod_default.string().min(1) })
|
|
71862
|
+
]);
|
|
71863
|
+
var MODIFIED_ARTIFACT_KINDS = ["queries", "workflows", "agents", "template"];
|
|
71864
|
+
var modifiedArtifactSchema = zod_default.object({
|
|
71865
|
+
kind: zod_default.enum(MODIFIED_ARTIFACT_KINDS),
|
|
71866
|
+
alias: zod_default.string(),
|
|
71867
|
+
// Templates only: the OLD pinned contract carried no content_sha256, so the
|
|
71868
|
+
// preview cannot attribute the divergence from the target to a local edit vs.
|
|
71869
|
+
// the older upstream content — a one-time consent, converging once a
|
|
71870
|
+
// sha-carrying version is pinned. Surfaces can say "can't verify local edits
|
|
71871
|
+
// (older package version)".
|
|
71872
|
+
baseline_unknown: zod_default.boolean().optional()
|
|
71873
|
+
});
|
|
71874
|
+
var packageArtifactHashesSchema = zod_default.object({
|
|
71875
|
+
queries: zod_default.record(zod_default.string(), zod_default.string()),
|
|
71876
|
+
workflows: zod_default.record(zod_default.string(), zod_default.string()),
|
|
71877
|
+
agents: zod_default.record(zod_default.string(), zod_default.string())
|
|
71878
|
+
});
|
|
71879
|
+
var modificationResolutionSchema = zod_default.union([zod_default.literal("revert"), zod_default.literal("keep")]);
|
|
71880
|
+
var KNOWLEDGE_UPGRADE_CHANGES = ["added", "changed", "removed", "drifted"];
|
|
71881
|
+
var knowledgeUpgradeEntrySchema = zod_default.object({
|
|
71882
|
+
alias: zod_default.string(),
|
|
71883
|
+
name: zod_default.string().describe("The doc's display name \u2014 the target contract's name, or the live name for a drifted doc"),
|
|
71884
|
+
change: zod_default.enum(KNOWLEDGE_UPGRADE_CHANGES),
|
|
71885
|
+
/** `changed`/`removed` only: the live doc's content diverged from the OLD pinned sha. */
|
|
71886
|
+
modified: zod_default.boolean(),
|
|
71887
|
+
/** The bound live doc id; null for `added`, or for a `drifted` doc that is gone. */
|
|
71888
|
+
doc_id: zod_default.string().nullable()
|
|
71889
|
+
});
|
|
71890
|
+
function knowledgeEntryNeedsConsent(entry) {
|
|
71891
|
+
if (entry.change === "drifted") return true;
|
|
71892
|
+
if (entry.change === "changed" || entry.change === "removed") return entry.modified;
|
|
71893
|
+
return false;
|
|
71894
|
+
}
|
|
71895
|
+
var knowledgeResolutionSchema = zod_default.enum(["apply", "keep", "archive", "recreate", "unbind"]);
|
|
71896
|
+
var upgradeResolutionsSchema = zod_default.record(
|
|
71897
|
+
zod_default.string(),
|
|
71898
|
+
zod_default.union([driftResolutionSchema, modificationResolutionSchema, knowledgeResolutionSchema])
|
|
71899
|
+
);
|
|
71900
|
+
var knowledgeBindConsentSchema = zod_default.record(zod_default.string(), zod_default.string());
|
|
71901
|
+
var knowledgeUpgradeResolutionsSchema = zod_default.object({
|
|
71902
|
+
resolutions: zod_default.record(zod_default.string(), knowledgeResolutionSchema).default({}),
|
|
71903
|
+
bind_to: knowledgeBindConsentSchema.default({})
|
|
71904
|
+
});
|
|
71905
|
+
var knowledgeBoundRefSchema = zod_default.object({
|
|
71906
|
+
alias: zod_default.string(),
|
|
71907
|
+
name: zod_default.string(),
|
|
71908
|
+
/** The bound doc id; null when the bound doc is gone/archived (drift). */
|
|
71909
|
+
doc_id: zod_default.string().nullable()
|
|
71910
|
+
});
|
|
71911
|
+
var appInstallationConfigValueSchema = zod_default.union([zod_default.string(), zod_default.number(), zod_default.boolean()]);
|
|
71912
|
+
var appInstallationConfigSchema = zod_default.record(
|
|
71913
|
+
contractAliasSchema,
|
|
71914
|
+
appInstallationConfigValueSchema
|
|
71915
|
+
);
|
|
71916
|
+
var appInstallationProvenanceSchema = zod_default.enum(["install", "adopt"]);
|
|
71917
|
+
|
|
70460
71918
|
// ../shared/src/agent_instructions.ts
|
|
70461
71919
|
function agentFilePath(alias) {
|
|
70462
71920
|
return `src/agents/${alias}.md`;
|
|
@@ -70564,7 +72022,7 @@ function syncedEntry(entry) {
|
|
|
70564
72022
|
function readSynced(projectDir) {
|
|
70565
72023
|
try {
|
|
70566
72024
|
const pkg2 = JSON.parse(
|
|
70567
|
-
|
|
72025
|
+
fs8.readFileSync(path9.join(projectDir, "package.json"), "utf-8")
|
|
70568
72026
|
);
|
|
70569
72027
|
const raw = pkg2.lotics?.synced ?? {};
|
|
70570
72028
|
return {
|
|
@@ -70585,16 +72043,16 @@ function normalizeSyncedMap(map3) {
|
|
|
70585
72043
|
);
|
|
70586
72044
|
}
|
|
70587
72045
|
function writeSynced(projectDir, kind, alias, entry) {
|
|
70588
|
-
const pkgPath2 =
|
|
70589
|
-
const pkg2 = JSON.parse(
|
|
72046
|
+
const pkgPath2 = path9.join(projectDir, "package.json");
|
|
72047
|
+
const pkg2 = JSON.parse(fs8.readFileSync(pkgPath2, "utf-8"));
|
|
70590
72048
|
if (!pkg2.lotics) return;
|
|
70591
72049
|
pkg2.lotics.synced ??= {};
|
|
70592
72050
|
pkg2.lotics.synced[kind] = { ...pkg2.lotics.synced[kind], [alias]: entry };
|
|
70593
|
-
|
|
72051
|
+
fs8.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
70594
72052
|
}
|
|
70595
|
-
var WORKFLOWS_DIR =
|
|
70596
|
-
var WORKFLOW_GLOBALS_DIR =
|
|
70597
|
-
var AGENTS_DIR =
|
|
72053
|
+
var WORKFLOWS_DIR = path9.join("src", "workflows");
|
|
72054
|
+
var WORKFLOW_GLOBALS_DIR = path9.join(".lotics", "workflows");
|
|
72055
|
+
var AGENTS_DIR = path9.join("src", "agents");
|
|
70598
72056
|
var WORKFLOW_TSCONFIG_EXCLUDES = ["src/workflows", ".lotics/workflows"];
|
|
70599
72057
|
var LOTICS_INCLUDE_GLOB = ".lotics/**/*";
|
|
70600
72058
|
var STALE_LOTICS_INCLUDES = /* @__PURE__ */ new Set([".lotics", "./.lotics", ".lotics/"]);
|
|
@@ -70605,7 +72063,7 @@ function isMissingWorkflowBodyError(error52) {
|
|
|
70605
72063
|
return /has no step source|cannot be rendered|unsupported step/i.test(error52);
|
|
70606
72064
|
}
|
|
70607
72065
|
function workflowFileHeader(alias) {
|
|
70608
|
-
const refPath =
|
|
72066
|
+
const refPath = path9.join("..", "..", WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`).split(path9.sep).join("/");
|
|
70609
72067
|
return `/// <reference path="${refPath}" />
|
|
70610
72068
|
// Auto-pulled workflow body for "${alias}". Edit the BODY between the wrapper
|
|
70611
72069
|
// lines below, then check + push with:
|
|
@@ -70619,35 +72077,35 @@ export {};
|
|
|
70619
72077
|
`;
|
|
70620
72078
|
}
|
|
70621
72079
|
function workflowFilePath(projectDir, alias) {
|
|
70622
|
-
return
|
|
72080
|
+
return path9.join(projectDir, WORKFLOWS_DIR, `${alias}.ts`);
|
|
70623
72081
|
}
|
|
70624
72082
|
var GLOBALS_SUFFIX = ".globals.d.ts";
|
|
70625
72083
|
function workflowGlobalsPath(projectDir, alias) {
|
|
70626
|
-
return
|
|
72084
|
+
return path9.join(projectDir, WORKFLOW_GLOBALS_DIR, `${alias}${GLOBALS_SUFFIX}`);
|
|
70627
72085
|
}
|
|
70628
72086
|
function pruneOrphanWorkflowGlobals(projectDir, declared) {
|
|
70629
|
-
const dir =
|
|
70630
|
-
if (!
|
|
72087
|
+
const dir = path9.join(projectDir, WORKFLOW_GLOBALS_DIR);
|
|
72088
|
+
if (!fs8.existsSync(dir)) return [];
|
|
70631
72089
|
const removed = [];
|
|
70632
|
-
for (const entry of
|
|
72090
|
+
for (const entry of fs8.readdirSync(dir)) {
|
|
70633
72091
|
if (!entry.endsWith(GLOBALS_SUFFIX)) continue;
|
|
70634
72092
|
const alias = entry.slice(0, -GLOBALS_SUFFIX.length);
|
|
70635
72093
|
if (declared.has(alias)) continue;
|
|
70636
|
-
|
|
72094
|
+
fs8.unlinkSync(path9.join(dir, entry));
|
|
70637
72095
|
removed.push(alias);
|
|
70638
72096
|
}
|
|
70639
72097
|
return removed.sort();
|
|
70640
72098
|
}
|
|
70641
72099
|
function orphanWorkflowBodies(projectDir, declared) {
|
|
70642
|
-
const dir =
|
|
70643
|
-
if (!
|
|
70644
|
-
return
|
|
72100
|
+
const dir = path9.join(projectDir, WORKFLOWS_DIR);
|
|
72101
|
+
if (!fs8.existsSync(dir)) return [];
|
|
72102
|
+
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();
|
|
70645
72103
|
}
|
|
70646
72104
|
function writeWorkflowGlobals(projectDir, alias, dts) {
|
|
70647
|
-
const dir =
|
|
70648
|
-
|
|
72105
|
+
const dir = path9.join(projectDir, WORKFLOW_GLOBALS_DIR);
|
|
72106
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
70649
72107
|
const file2 = workflowGlobalsPath(projectDir, alias);
|
|
70650
|
-
|
|
72108
|
+
fs8.writeFileSync(file2, `${dts.replace(/\s+$/, "")}
|
|
70651
72109
|
`);
|
|
70652
72110
|
return file2;
|
|
70653
72111
|
}
|
|
@@ -70655,26 +72113,26 @@ function normalizeWorkflowBody(source) {
|
|
|
70655
72113
|
return source.replace(/\s+$/, "");
|
|
70656
72114
|
}
|
|
70657
72115
|
function writeWorkflowFile(projectDir, alias, source, envelope = { prefix: WORKFLOW_ENVELOPE_PREFIX, suffix: WORKFLOW_ENVELOPE_SUFFIX }) {
|
|
70658
|
-
const dir =
|
|
70659
|
-
|
|
72116
|
+
const dir = path9.join(projectDir, WORKFLOWS_DIR);
|
|
72117
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
70660
72118
|
const file2 = workflowFilePath(projectDir, alias);
|
|
70661
72119
|
const body = normalizeWorkflowBody(source);
|
|
70662
|
-
|
|
72120
|
+
fs8.writeFileSync(file2, `${workflowFileHeader(alias)}
|
|
70663
72121
|
${envelope.prefix}${body}${envelope.suffix}
|
|
70664
72122
|
`);
|
|
70665
72123
|
return file2;
|
|
70666
72124
|
}
|
|
70667
72125
|
function agentFilePath2(projectDir, alias) {
|
|
70668
|
-
return
|
|
72126
|
+
return path9.join(projectDir, ...agentFilePath(alias).split("/"));
|
|
70669
72127
|
}
|
|
70670
72128
|
var CLI_AGENT_NOTES = [
|
|
70671
72129
|
"Pulled from the LIVE app row; edit here, then: lotics app agent set <alias>",
|
|
70672
72130
|
"The typed fields (inputs/outputs/tool_names/model_tier) live in package.json#lotics.agents"
|
|
70673
72131
|
];
|
|
70674
72132
|
function writeAgentFile(projectDir, alias, instructions) {
|
|
70675
|
-
|
|
72133
|
+
fs8.mkdirSync(path9.join(projectDir, AGENTS_DIR), { recursive: true });
|
|
70676
72134
|
const file2 = agentFilePath2(projectDir, alias);
|
|
70677
|
-
|
|
72135
|
+
fs8.writeFileSync(
|
|
70678
72136
|
file2,
|
|
70679
72137
|
wrapAgentFile({ alias, instructions, notes: CLI_AGENT_NOTES.map((n) => n.replace("<alias>", alias)) })
|
|
70680
72138
|
);
|
|
@@ -70699,20 +72157,20 @@ function writeAgentFiles(projectDir, agents, opts) {
|
|
|
70699
72157
|
}
|
|
70700
72158
|
function localPromptUnpushed(projectDir, alias) {
|
|
70701
72159
|
const file2 = agentFilePath2(projectDir, alias);
|
|
70702
|
-
if (!
|
|
72160
|
+
if (!fs8.existsSync(file2)) return false;
|
|
70703
72161
|
const baseline = readSynced(projectDir).agents[alias]?.content;
|
|
70704
72162
|
if (baseline === void 0) return true;
|
|
70705
|
-
return contentSha(stripAgentHeader(
|
|
72163
|
+
return contentSha(stripAgentHeader(fs8.readFileSync(file2, "utf-8"))) !== baseline;
|
|
70706
72164
|
}
|
|
70707
72165
|
function generatedWorkflowDescription(appName, alias) {
|
|
70708
72166
|
return `Workflow invoked by app "${appName}" via useWorkflow("${alias}").`;
|
|
70709
72167
|
}
|
|
70710
72168
|
function localBodyUnpushed(projectDir, alias) {
|
|
70711
72169
|
const file2 = workflowFilePath(projectDir, alias);
|
|
70712
|
-
if (!
|
|
72170
|
+
if (!fs8.existsSync(file2)) return false;
|
|
70713
72171
|
const baseline = readSynced(projectDir).workflows[alias]?.content;
|
|
70714
72172
|
if (baseline === void 0) return true;
|
|
70715
|
-
return contentSha(stripWorkflowHeader(
|
|
72173
|
+
return contentSha(stripWorkflowHeader(fs8.readFileSync(file2, "utf-8"))) !== baseline;
|
|
70716
72174
|
}
|
|
70717
72175
|
async function writeWorkflowFiles(client, projectDir, app_id, appName, workflows, opts) {
|
|
70718
72176
|
const written = [];
|
|
@@ -70767,12 +72225,12 @@ async function writeWorkflowFiles(client, projectDir, app_id, appName, workflows
|
|
|
70767
72225
|
return written;
|
|
70768
72226
|
}
|
|
70769
72227
|
function writeWorkflowDescription(projectDir, alias, description) {
|
|
70770
|
-
const pkgPath2 =
|
|
70771
|
-
const pkg2 = JSON.parse(
|
|
72228
|
+
const pkgPath2 = path9.join(projectDir, "package.json");
|
|
72229
|
+
const pkg2 = JSON.parse(fs8.readFileSync(pkgPath2, "utf-8"));
|
|
70772
72230
|
const declaration = pkg2.lotics?.workflows?.[alias];
|
|
70773
72231
|
if (!declaration) return;
|
|
70774
72232
|
declaration.description = description;
|
|
70775
|
-
|
|
72233
|
+
fs8.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
70776
72234
|
}
|
|
70777
72235
|
async function fetchWorkflowGlobals(client, projectDir, app_id, alias, declaration) {
|
|
70778
72236
|
try {
|
|
@@ -70822,20 +72280,20 @@ function runNpm(args, cwd) {
|
|
|
70822
72280
|
}
|
|
70823
72281
|
function readAppWorkspaceId(projectDir) {
|
|
70824
72282
|
try {
|
|
70825
|
-
const pkgPath2 =
|
|
70826
|
-
if (!
|
|
70827
|
-
const pkg2 = JSON.parse(
|
|
72283
|
+
const pkgPath2 = path9.join(projectDir, "package.json");
|
|
72284
|
+
if (!fs8.existsSync(pkgPath2)) return null;
|
|
72285
|
+
const pkg2 = JSON.parse(fs8.readFileSync(pkgPath2, "utf-8"));
|
|
70828
72286
|
return pkg2.lotics?.workspace_id ?? null;
|
|
70829
72287
|
} catch {
|
|
70830
72288
|
return null;
|
|
70831
72289
|
}
|
|
70832
72290
|
}
|
|
70833
72291
|
function readAppMeta(projectDir) {
|
|
70834
|
-
const pkgPath2 =
|
|
70835
|
-
if (!
|
|
72292
|
+
const pkgPath2 = path9.join(projectDir, "package.json");
|
|
72293
|
+
if (!fs8.existsSync(pkgPath2)) {
|
|
70836
72294
|
throw new Error(`No package.json found at ${projectDir}. Run 'lotics app create' first.`);
|
|
70837
72295
|
}
|
|
70838
|
-
const pkg2 = JSON.parse(
|
|
72296
|
+
const pkg2 = JSON.parse(fs8.readFileSync(pkgPath2, "utf-8"));
|
|
70839
72297
|
if (!pkg2.lotics?.app_id || !pkg2.lotics.workspace_id) {
|
|
70840
72298
|
throw new Error(
|
|
70841
72299
|
`package.json is missing the 'lotics' field with app_id and workspace_id. Was this folder created with 'lotics app create'?`
|
|
@@ -70854,8 +72312,8 @@ function readAppMeta(projectDir) {
|
|
|
70854
72312
|
};
|
|
70855
72313
|
}
|
|
70856
72314
|
function writeAppMeta(projectDir, meta3) {
|
|
70857
|
-
const pkgPath2 =
|
|
70858
|
-
const pkg2 = JSON.parse(
|
|
72315
|
+
const pkgPath2 = path9.join(projectDir, "package.json");
|
|
72316
|
+
const pkg2 = JSON.parse(fs8.readFileSync(pkgPath2, "utf-8"));
|
|
70859
72317
|
const existing = pkg2.lotics && typeof pkg2.lotics === "object" ? pkg2.lotics : {};
|
|
70860
72318
|
const supplied = new Set(
|
|
70861
72319
|
Object.entries(meta3).filter(([, value2]) => value2 !== void 0).map(([key]) => key)
|
|
@@ -70865,11 +72323,11 @@ function writeAppMeta(projectDir, meta3) {
|
|
|
70865
72323
|
if (!supplied.has(key)) preserved[key] = value2;
|
|
70866
72324
|
}
|
|
70867
72325
|
pkg2.lotics = { ...meta3, ...preserved };
|
|
70868
|
-
|
|
72326
|
+
fs8.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
70869
72327
|
}
|
|
70870
72328
|
function writeWorkflowOutputs(projectDir, alias, outputs) {
|
|
70871
|
-
const pkgPath2 =
|
|
70872
|
-
const pkg2 = JSON.parse(
|
|
72329
|
+
const pkgPath2 = path9.join(projectDir, "package.json");
|
|
72330
|
+
const pkg2 = JSON.parse(fs8.readFileSync(pkgPath2, "utf-8"));
|
|
70873
72331
|
const declaration = pkg2.lotics?.workflows?.[alias];
|
|
70874
72332
|
if (!declaration) {
|
|
70875
72333
|
throw new Error(
|
|
@@ -70877,7 +72335,7 @@ function writeWorkflowOutputs(projectDir, alias, outputs) {
|
|
|
70877
72335
|
);
|
|
70878
72336
|
}
|
|
70879
72337
|
declaration.outputs = outputs;
|
|
70880
|
-
|
|
72338
|
+
fs8.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
70881
72339
|
}
|
|
70882
72340
|
function workflowBodyDrift(projectDir, workflows, synced = {}) {
|
|
70883
72341
|
const drifted = [];
|
|
@@ -70885,16 +72343,16 @@ function workflowBodyDrift(projectDir, workflows, synced = {}) {
|
|
|
70885
72343
|
const baseline = syncedEntry(synced[alias])?.content;
|
|
70886
72344
|
if (baseline === void 0) continue;
|
|
70887
72345
|
const file2 = workflowFilePath(projectDir, alias);
|
|
70888
|
-
if (!
|
|
70889
|
-
const source = stripWorkflowHeader(
|
|
72346
|
+
if (!fs8.existsSync(file2)) continue;
|
|
72347
|
+
const source = stripWorkflowHeader(fs8.readFileSync(file2, "utf-8"));
|
|
70890
72348
|
if (source.trim() === "" || contentSha(source) === baseline) continue;
|
|
70891
72349
|
drifted.push(alias);
|
|
70892
72350
|
}
|
|
70893
72351
|
return drifted;
|
|
70894
72352
|
}
|
|
70895
72353
|
function ensureAppTsconfig(projectDir) {
|
|
70896
|
-
const tsconfigPath =
|
|
70897
|
-
if (!
|
|
72354
|
+
const tsconfigPath = path9.join(projectDir, "tsconfig.json");
|
|
72355
|
+
if (!fs8.existsSync(tsconfigPath)) {
|
|
70898
72356
|
console.error(
|
|
70899
72357
|
`\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(", ")}.`
|
|
70900
72358
|
);
|
|
@@ -70902,7 +72360,7 @@ function ensureAppTsconfig(projectDir) {
|
|
|
70902
72360
|
}
|
|
70903
72361
|
let parsed;
|
|
70904
72362
|
try {
|
|
70905
|
-
parsed = JSON.parse(
|
|
72363
|
+
parsed = JSON.parse(fs8.readFileSync(tsconfigPath, "utf-8"));
|
|
70906
72364
|
} catch (err2) {
|
|
70907
72365
|
console.error(
|
|
70908
72366
|
`\u26A0 Could not parse tsconfig.json (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 ensure "include" has "${LOTICS_INCLUDE_GLOB}" and "exclude" has ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")} manually.`
|
|
@@ -70935,7 +72393,7 @@ function ensureAppTsconfig(projectDir) {
|
|
|
70935
72393
|
);
|
|
70936
72394
|
}
|
|
70937
72395
|
if (changes.length === 0) return;
|
|
70938
|
-
|
|
72396
|
+
fs8.writeFileSync(tsconfigPath, JSON.stringify(parsed, null, 2) + "\n");
|
|
70939
72397
|
console.error(`Patched tsconfig.json: ${changes.join("; ")}.`);
|
|
70940
72398
|
}
|
|
70941
72399
|
var LINK_TSCONFIG = ".lotics/tsconfig.link.json";
|
|
@@ -70945,15 +72403,15 @@ function writeDevLinkTsconfig(projectDir) {
|
|
|
70945
72403
|
if (uiSrc) {
|
|
70946
72404
|
paths["@lotics/ui/*"] = [`${uiSrc}/*`];
|
|
70947
72405
|
for (const peer of readKitPeerNames(projectDir)) {
|
|
70948
|
-
const typesDir =
|
|
70949
|
-
const runtimeDir =
|
|
70950
|
-
const target =
|
|
72406
|
+
const typesDir = path9.join(projectDir, "node_modules", typesPackageFor(peer));
|
|
72407
|
+
const runtimeDir = path9.join(projectDir, "node_modules", peer);
|
|
72408
|
+
const target = fs8.existsSync(typesDir) ? `../node_modules/${typesPackageFor(peer)}` : fs8.existsSync(runtimeDir) ? `../node_modules/${peer}` : null;
|
|
70951
72409
|
if (!target) continue;
|
|
70952
72410
|
paths[peer] = [target];
|
|
70953
72411
|
paths[`${peer}/*`] = [`${target}/*`];
|
|
70954
72412
|
}
|
|
70955
72413
|
}
|
|
70956
|
-
const file2 =
|
|
72414
|
+
const file2 = path9.join(projectDir, ".lotics", "tsconfig.link.json");
|
|
70957
72415
|
const header = uiSrc ? `// GENERATED by \`lotics app codegen\` \u2014 do not edit.
|
|
70958
72416
|
// LOTICS_UI_SRC is set, so @lotics/ui resolves to your working copy for tsc,
|
|
70959
72417
|
// vitest, eslint and your editor \u2014 the same copy Vite is bundling. The peer
|
|
@@ -70964,45 +72422,45 @@ function writeDevLinkTsconfig(projectDir) {
|
|
|
70964
72422
|
// LOTICS_UI_SRC is not set, so this is inert and @lotics/ui resolves from
|
|
70965
72423
|
// node_modules as normal.
|
|
70966
72424
|
`;
|
|
70967
|
-
|
|
72425
|
+
fs8.writeFileSync(file2, `${header}${JSON.stringify({ compilerOptions: { paths } }, null, 2)}
|
|
70968
72426
|
`);
|
|
70969
72427
|
return file2;
|
|
70970
72428
|
}
|
|
70971
72429
|
function writeKitTypeAugmentation(projectDir) {
|
|
70972
72430
|
const uiSrc = process.env.LOTICS_UI_SRC;
|
|
70973
|
-
const source = uiSrc ?
|
|
70974
|
-
const target =
|
|
70975
|
-
if (!
|
|
70976
|
-
if (
|
|
72431
|
+
const source = uiSrc ? path9.join(uiSrc, "react_native.d.ts") : path9.join(projectDir, "node_modules", "@lotics", "ui", "src", "react_native.d.ts");
|
|
72432
|
+
const target = path9.join(projectDir, ".lotics", "react_native.d.ts");
|
|
72433
|
+
if (!fs8.existsSync(source)) {
|
|
72434
|
+
if (fs8.existsSync(target)) fs8.rmSync(target);
|
|
70977
72435
|
return;
|
|
70978
72436
|
}
|
|
70979
|
-
|
|
72437
|
+
fs8.writeFileSync(
|
|
70980
72438
|
target,
|
|
70981
72439
|
`// GENERATED by \`lotics app codegen\` from @lotics/ui \u2014 do not edit.
|
|
70982
72440
|
// The kit's web-only ViewStyle/TextStyle properties, which react-native does
|
|
70983
72441
|
// not model. Delete any hand-copied src/react_native.d.ts; this replaces it.
|
|
70984
|
-
` +
|
|
72442
|
+
` + fs8.readFileSync(source, "utf-8")
|
|
70985
72443
|
);
|
|
70986
72444
|
}
|
|
70987
72445
|
function typesPackageFor(peer) {
|
|
70988
72446
|
return peer.startsWith("@") ? `@types/${peer.slice(1).replace("/", "__")}` : `@types/${peer}`;
|
|
70989
72447
|
}
|
|
70990
72448
|
function readKitPeerNames(projectDir) {
|
|
70991
|
-
const kitPkg =
|
|
70992
|
-
if (!
|
|
70993
|
-
const parsed = JSON.parse(
|
|
72449
|
+
const kitPkg = path9.join(projectDir, "node_modules", "@lotics", "ui", "package.json");
|
|
72450
|
+
if (!fs8.existsSync(kitPkg)) return [];
|
|
72451
|
+
const parsed = JSON.parse(fs8.readFileSync(kitPkg, "utf-8"));
|
|
70994
72452
|
const peers = parsed.peerDependencies;
|
|
70995
72453
|
return peers && typeof peers === "object" ? Object.keys(peers) : [];
|
|
70996
72454
|
}
|
|
70997
72455
|
function writeAppDts(projectDir, manifest) {
|
|
70998
|
-
const dotLotics =
|
|
70999
|
-
|
|
72456
|
+
const dotLotics = path9.join(projectDir, ".lotics");
|
|
72457
|
+
fs8.mkdirSync(dotLotics, { recursive: true });
|
|
71000
72458
|
const written = [
|
|
71001
|
-
[
|
|
71002
|
-
[
|
|
71003
|
-
[
|
|
72459
|
+
[path9.join(dotLotics, "app_workflows.d.ts"), generateAppWorkflowsDts(manifest.workflows)],
|
|
72460
|
+
[path9.join(dotLotics, "app_queries.d.ts"), generateAppQueriesDts(manifest.queries)],
|
|
72461
|
+
[path9.join(dotLotics, "app_agents.d.ts"), generateAppAgentsDts(manifest.agents)]
|
|
71004
72462
|
];
|
|
71005
|
-
for (const [file2, content] of written)
|
|
72463
|
+
for (const [file2, content] of written) fs8.writeFileSync(file2, content);
|
|
71006
72464
|
writeDevLinkTsconfig(projectDir);
|
|
71007
72465
|
writeKitTypeAugmentation(projectDir);
|
|
71008
72466
|
ensureAppTsconfig(projectDir);
|
|
@@ -71010,7 +72468,7 @@ function writeAppDts(projectDir, manifest) {
|
|
|
71010
72468
|
return written.map(([file2]) => file2);
|
|
71011
72469
|
}
|
|
71012
72470
|
function readCodegenTablesAllowlist(projectDir) {
|
|
71013
|
-
const pkg2 = JSON.parse(
|
|
72471
|
+
const pkg2 = JSON.parse(fs8.readFileSync(path9.join(projectDir, "package.json"), "utf-8"));
|
|
71014
72472
|
const tables = pkg2.lotics?.codegen?.tables;
|
|
71015
72473
|
return Array.isArray(tables) ? tables.filter((t) => typeof t === "string") : [];
|
|
71016
72474
|
}
|
|
@@ -71023,17 +72481,17 @@ function resolveCodegenTableIds(projectDir, queries) {
|
|
|
71023
72481
|
return [...ids];
|
|
71024
72482
|
}
|
|
71025
72483
|
function writeAppFields(projectDir, tables) {
|
|
71026
|
-
const dotLotics =
|
|
71027
|
-
|
|
71028
|
-
const file2 =
|
|
71029
|
-
|
|
72484
|
+
const dotLotics = path9.join(projectDir, ".lotics");
|
|
72485
|
+
fs8.mkdirSync(dotLotics, { recursive: true });
|
|
72486
|
+
const file2 = path9.join(dotLotics, "app_fields.ts");
|
|
72487
|
+
fs8.writeFileSync(file2, generateAppFields(tables));
|
|
71030
72488
|
return file2;
|
|
71031
72489
|
}
|
|
71032
72490
|
function writeBindingAppFields(projectDir, binding) {
|
|
71033
|
-
const dotLotics =
|
|
71034
|
-
|
|
71035
|
-
const file2 =
|
|
71036
|
-
|
|
72491
|
+
const dotLotics = path9.join(projectDir, ".lotics");
|
|
72492
|
+
fs8.mkdirSync(dotLotics, { recursive: true });
|
|
72493
|
+
const file2 = path9.join(dotLotics, "app_fields.ts");
|
|
72494
|
+
fs8.writeFileSync(file2, generatePackageAppFields(binding));
|
|
71037
72495
|
return file2;
|
|
71038
72496
|
}
|
|
71039
72497
|
async function writeGeneratedAppFields(client, projectDir, app, queries) {
|
|
@@ -71074,7 +72532,7 @@ async function writeGeneratedAppFields(client, projectDir, app, queries) {
|
|
|
71074
72532
|
}
|
|
71075
72533
|
function warnAppFieldsUnwritten(projectDir, err2) {
|
|
71076
72534
|
const reason = err2 instanceof Error ? err2.message : String(err2);
|
|
71077
|
-
if (
|
|
72535
|
+
if (fs8.existsSync(path9.join(projectDir, ".lotics", "app_fields.ts"))) {
|
|
71078
72536
|
console.error(`\u26A0 Could not regenerate .lotics/app_fields.ts (${reason}). Kept the existing file.`);
|
|
71079
72537
|
return;
|
|
71080
72538
|
}
|
|
@@ -71085,8 +72543,8 @@ function warnAppFieldsUnwritten(projectDir, err2) {
|
|
|
71085
72543
|
function warnAboutDevLink(projectDir, command) {
|
|
71086
72544
|
const uiSrc = process.env.LOTICS_UI_SRC;
|
|
71087
72545
|
if (!uiSrc) return;
|
|
71088
|
-
const viteConfigPath =
|
|
71089
|
-
const config2 =
|
|
72546
|
+
const viteConfigPath = path9.join(projectDir, "vite.config.ts");
|
|
72547
|
+
const config2 = fs8.existsSync(viteConfigPath) ? fs8.readFileSync(viteConfigPath, "utf-8") : "";
|
|
71090
72548
|
const linked = config2.includes("loticsResolve") || config2.includes("LOTICS_UI_SRC");
|
|
71091
72549
|
if (!linked) {
|
|
71092
72550
|
console.error(
|
|
@@ -71104,19 +72562,19 @@ function warnAboutDevLink(projectDir, command) {
|
|
|
71104
72562
|
}
|
|
71105
72563
|
}
|
|
71106
72564
|
function ensureAppVitestSetup(projectDir) {
|
|
71107
|
-
const setupPath =
|
|
71108
|
-
if (!
|
|
71109
|
-
|
|
72565
|
+
const setupPath = path9.join(projectDir, VITEST_SETUP_FILENAME);
|
|
72566
|
+
if (!fs8.existsSync(setupPath)) {
|
|
72567
|
+
fs8.writeFileSync(setupPath, VITEST_SETUP_CONTENT);
|
|
71110
72568
|
console.error(`Wrote ${VITEST_SETUP_FILENAME} (stubs getAppBinding so \`npm test\` collects).`);
|
|
71111
|
-
} else if (!
|
|
72569
|
+
} else if (!fs8.readFileSync(setupPath, "utf-8").includes("getAppBinding")) {
|
|
71112
72570
|
console.error(
|
|
71113
72571
|
`\u26A0 ${VITEST_SETUP_FILENAME} exists but does not stub getAppBinding \u2014 \`npm test\` will fail to collect any test that imports the app graph (the binding-form .lotics/app_fields.ts awaits a network call). Add the stub to it:
|
|
71114
72572
|
${VITEST_SETUP_CONTENT}`
|
|
71115
72573
|
);
|
|
71116
72574
|
}
|
|
71117
|
-
const viteConfigPath =
|
|
71118
|
-
if (!
|
|
71119
|
-
const viteConfig =
|
|
72575
|
+
const viteConfigPath = path9.join(projectDir, "vite.config.ts");
|
|
72576
|
+
if (!fs8.existsSync(viteConfigPath)) return;
|
|
72577
|
+
const viteConfig = fs8.readFileSync(viteConfigPath, "utf-8");
|
|
71120
72578
|
if (/setupFiles\s*:/.test(viteConfig) && viteConfig.includes(VITEST_SETUP_FILENAME)) return;
|
|
71121
72579
|
console.error(
|
|
71122
72580
|
`\u26A0 vite.config.ts does not wire ${VITEST_SETUP_FILENAME} \u2014 \`npm test\` will fail to collect any test that imports the app graph (the binding-form .lotics/app_fields.ts awaits a network call). Add it to the \`test\` block:
|
|
@@ -71124,7 +72582,7 @@ ${VITEST_SETUP_CONTENT}`
|
|
|
71124
72582
|
);
|
|
71125
72583
|
}
|
|
71126
72584
|
async function appCodegen(args) {
|
|
71127
|
-
const projectDir =
|
|
72585
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
71128
72586
|
const meta3 = readAppMeta(projectDir);
|
|
71129
72587
|
const dtsPaths = writeAppDts(projectDir, {
|
|
71130
72588
|
workflows: meta3.workflows,
|
|
@@ -71138,7 +72596,7 @@ async function appCodegen(args) {
|
|
|
71138
72596
|
}
|
|
71139
72597
|
for (const alias of orphanWorkflowBodies(projectDir, declared)) {
|
|
71140
72598
|
console.error(
|
|
71141
|
-
`\u26A0 ${
|
|
72599
|
+
`\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.`
|
|
71142
72600
|
);
|
|
71143
72601
|
}
|
|
71144
72602
|
if (!args.client) {
|
|
@@ -71189,8 +72647,8 @@ async function refreshWorkflowGlobals(client, projectDir, app_id, workflows) {
|
|
|
71189
72647
|
}
|
|
71190
72648
|
async function refreshWorkflowTypes(client, projectDir, app_id, alias, declaration) {
|
|
71191
72649
|
const file2 = workflowFilePath(projectDir, alias);
|
|
71192
|
-
if (!
|
|
71193
|
-
const body = stripWorkflowHeader(
|
|
72650
|
+
if (!fs8.existsSync(file2)) return false;
|
|
72651
|
+
const body = stripWorkflowHeader(fs8.readFileSync(file2, "utf-8"));
|
|
71194
72652
|
if (body.trim() === "") return false;
|
|
71195
72653
|
const envelope = await fetchWorkflowGlobals(client, projectDir, app_id, alias, declaration);
|
|
71196
72654
|
writeWorkflowFile(projectDir, alias, body, envelope);
|
|
@@ -71220,21 +72678,21 @@ async function downloadToFile(url2, destPath) {
|
|
|
71220
72678
|
throw new Error(`Failed to download ${url2}: ${response.status}`);
|
|
71221
72679
|
}
|
|
71222
72680
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
71223
|
-
|
|
72681
|
+
fs8.writeFileSync(destPath, buffer);
|
|
71224
72682
|
}
|
|
71225
72683
|
function appDirName(name2) {
|
|
71226
72684
|
const cleaned = name2.replace(/[/\\]+/g, "-").replace(/[<>:"|?*]/g, "").replace(/\s+/g, " ").trim().replace(/^[.\s-]+|[.\s-]+$/g, "");
|
|
71227
72685
|
return cleaned || "app";
|
|
71228
72686
|
}
|
|
71229
72687
|
async function appCreate(client, args) {
|
|
71230
|
-
const targetPath =
|
|
71231
|
-
if (
|
|
71232
|
-
const entries2 =
|
|
72688
|
+
const targetPath = path9.resolve(args.targetPath ?? appDirName(args.name));
|
|
72689
|
+
if (fs8.existsSync(targetPath)) {
|
|
72690
|
+
const entries2 = fs8.readdirSync(targetPath);
|
|
71233
72691
|
if (entries2.length > 0) {
|
|
71234
72692
|
throw new Error(`Target directory ${targetPath} is not empty.`);
|
|
71235
72693
|
}
|
|
71236
72694
|
}
|
|
71237
|
-
|
|
72695
|
+
fs8.mkdirSync(targetPath, { recursive: true });
|
|
71238
72696
|
const [uiLatest, sdkLatest] = await Promise.all([
|
|
71239
72697
|
requireLatestNpmVersion("@lotics/ui"),
|
|
71240
72698
|
requireLatestNpmVersion("@lotics/app-sdk")
|
|
@@ -71249,9 +72707,9 @@ async function appCreate(client, args) {
|
|
|
71249
72707
|
sdk_version: `^${sdkLatest}`
|
|
71250
72708
|
});
|
|
71251
72709
|
for (const file2 of files) {
|
|
71252
|
-
const fullPath =
|
|
71253
|
-
|
|
71254
|
-
|
|
72710
|
+
const fullPath = path9.join(targetPath, file2.path);
|
|
72711
|
+
fs8.mkdirSync(path9.dirname(fullPath), { recursive: true });
|
|
72712
|
+
fs8.writeFileSync(fullPath, file2.content);
|
|
71255
72713
|
}
|
|
71256
72714
|
console.error(`Scaffolded ${files.length} files into ${targetPath}`);
|
|
71257
72715
|
writeAppDts(targetPath, {});
|
|
@@ -71264,8 +72722,10 @@ async function appCreate(client, args) {
|
|
|
71264
72722
|
});
|
|
71265
72723
|
console.error(`
|
|
71266
72724
|
Ready. Next steps:`);
|
|
71267
|
-
console.error(` cd ${
|
|
72725
|
+
console.error(` cd ${path9.relative(process.cwd(), targetPath) || "."}`);
|
|
72726
|
+
console.error(` lotics docs # the contracts, at the versions installed here`);
|
|
71268
72727
|
console.error(` # edit src/App.tsx, then:`);
|
|
72728
|
+
console.error(` lotics app check # every pre-flight a deploy runs`);
|
|
71269
72729
|
console.error(` lotics app deploy`);
|
|
71270
72730
|
}
|
|
71271
72731
|
async function appSetSubdomain(client, args) {
|
|
@@ -71321,11 +72781,11 @@ async function appVersions(client, args) {
|
|
|
71321
72781
|
}
|
|
71322
72782
|
}
|
|
71323
72783
|
function defaultPullTarget(appId, appName) {
|
|
71324
|
-
const cwdPkgPath =
|
|
71325
|
-
if (
|
|
72784
|
+
const cwdPkgPath = path9.join(process.cwd(), "package.json");
|
|
72785
|
+
if (fs8.existsSync(cwdPkgPath)) {
|
|
71326
72786
|
let pkg2 = null;
|
|
71327
72787
|
try {
|
|
71328
|
-
pkg2 = JSON.parse(
|
|
72788
|
+
pkg2 = JSON.parse(fs8.readFileSync(cwdPkgPath, "utf-8"));
|
|
71329
72789
|
} catch (err2) {
|
|
71330
72790
|
console.error(
|
|
71331
72791
|
`\u26A0 Could not parse ${cwdPkgPath} (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 pulling into a fresh ${appDirName(appName)}/ subdir.`
|
|
@@ -71346,20 +72806,20 @@ async function appPull(client, args) {
|
|
|
71346
72806
|
if (!versionId) throw new Error(`App ${app.id} has no version to pull.`);
|
|
71347
72807
|
const version2 = await client.getAppVersion(app.id, versionId);
|
|
71348
72808
|
const sourceUrl = await client.getAppVersionSourceUrl(app.id, version2.id);
|
|
71349
|
-
const targetPath =
|
|
71350
|
-
|
|
71351
|
-
const tmpFile =
|
|
72809
|
+
const targetPath = path9.resolve(args.targetPath ?? defaultPullTarget(app.id, app.name));
|
|
72810
|
+
fs8.mkdirSync(targetPath, { recursive: true });
|
|
72811
|
+
const tmpFile = path9.join(tmpdir(), `lotics-app-${app.id}-${Date.now()}.tar.gz`);
|
|
71352
72812
|
console.error(`Downloading source archive...`);
|
|
71353
72813
|
await downloadToFile(sourceUrl, tmpFile);
|
|
71354
72814
|
const keptLocal = [];
|
|
71355
|
-
const stagingDir =
|
|
72815
|
+
const stagingDir = fs8.mkdtempSync(path9.join(tmpdir(), `lotics-pull-${app.id}-`));
|
|
71356
72816
|
try {
|
|
71357
72817
|
await runTar(["-xzf", tmpFile, "-C", stagingDir], stagingDir);
|
|
71358
72818
|
console.error(`Extracting to ${targetPath}...`);
|
|
71359
72819
|
keptLocal.push(...copyTree(stagingDir, targetPath, { overwrite: args.force === true }));
|
|
71360
72820
|
} finally {
|
|
71361
|
-
if (
|
|
71362
|
-
|
|
72821
|
+
if (fs8.existsSync(tmpFile)) fs8.unlinkSync(tmpFile);
|
|
72822
|
+
fs8.rmSync(stagingDir, { recursive: true, force: true });
|
|
71363
72823
|
}
|
|
71364
72824
|
stampPulledManifest(targetPath, {
|
|
71365
72825
|
app_id: app.id,
|
|
@@ -71419,26 +72879,28 @@ async function appPull(client, args) {
|
|
|
71419
72879
|
reportKeptLocalFiles(keptLocal, app.id);
|
|
71420
72880
|
console.error(`
|
|
71421
72881
|
Ready. Next steps:`);
|
|
71422
|
-
console.error(` cd ${
|
|
72882
|
+
console.error(` cd ${path9.relative(process.cwd(), targetPath) || "."}`);
|
|
71423
72883
|
console.error(` # edit src/App.tsx`);
|
|
71424
72884
|
console.error(` lotics app deploy`);
|
|
71425
72885
|
}
|
|
71426
72886
|
function readAppSourceText(projectDir) {
|
|
71427
|
-
const srcDir =
|
|
71428
|
-
if (!
|
|
72887
|
+
const srcDir = path9.join(projectDir, "src");
|
|
72888
|
+
if (!fs8.existsSync(srcDir)) return "";
|
|
71429
72889
|
const parts = [];
|
|
71430
72890
|
const walk2 = (dir) => {
|
|
71431
|
-
for (const entry of
|
|
71432
|
-
const full =
|
|
72891
|
+
for (const entry of fs8.readdirSync(dir, { withFileTypes: true })) {
|
|
72892
|
+
const full = path9.join(dir, entry.name);
|
|
71433
72893
|
if (entry.isDirectory()) walk2(full);
|
|
71434
|
-
else if (
|
|
72894
|
+
else if (isAppSourcePath(path9.relative(projectDir, full))) {
|
|
72895
|
+
parts.push(fs8.readFileSync(full, "utf8"));
|
|
72896
|
+
}
|
|
71435
72897
|
}
|
|
71436
72898
|
};
|
|
71437
72899
|
walk2(srcDir);
|
|
71438
72900
|
return parts.join("\n");
|
|
71439
72901
|
}
|
|
71440
72902
|
async function appDeploy(client, args) {
|
|
71441
|
-
const projectDir =
|
|
72903
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
71442
72904
|
const meta3 = readAppMeta(projectDir);
|
|
71443
72905
|
warnAboutDevLink(projectDir, "deploy");
|
|
71444
72906
|
const liveApp = await client.getApp(meta3.app_id);
|
|
@@ -71455,6 +72917,7 @@ async function appDeploy(client, args) {
|
|
|
71455
72917
|
const called = calledAppAliases(sourceText);
|
|
71456
72918
|
warnIfDynamicAliases(called);
|
|
71457
72919
|
warnIfUndeclaredCapabilities(sourceText, meta3.capabilities);
|
|
72920
|
+
warnIfProjectFootguns(projectDir, sourceText);
|
|
71458
72921
|
writeAppDts(projectDir, { workflows: meta3.workflows, queries: meta3.queries, agents: meta3.agents });
|
|
71459
72922
|
try {
|
|
71460
72923
|
await writeGeneratedAppFields(
|
|
@@ -71471,14 +72934,14 @@ async function appDeploy(client, args) {
|
|
|
71471
72934
|
}
|
|
71472
72935
|
console.error("Building...");
|
|
71473
72936
|
await runNpm(["run", "build"], projectDir);
|
|
71474
|
-
const distDir =
|
|
71475
|
-
if (!
|
|
72937
|
+
const distDir = path9.join(projectDir, "dist");
|
|
72938
|
+
if (!fs8.existsSync(distDir)) {
|
|
71476
72939
|
throw new Error(
|
|
71477
72940
|
`Build did not produce a dist/ directory in ${projectDir}. Check that 'npm run build' is configured correctly (Vite/etc. defaults to dist/).`
|
|
71478
72941
|
);
|
|
71479
72942
|
}
|
|
71480
|
-
const tmpSource =
|
|
71481
|
-
const tmpDist =
|
|
72943
|
+
const tmpSource = path9.join(tmpdir(), `lotics-source-${Date.now()}.tar.gz`);
|
|
72944
|
+
const tmpDist = path9.join(tmpdir(), `lotics-dist-${Date.now()}.tar.gz`);
|
|
71482
72945
|
try {
|
|
71483
72946
|
console.error("Packaging source...");
|
|
71484
72947
|
await runTar(
|
|
@@ -71502,8 +72965,8 @@ async function appDeploy(client, args) {
|
|
|
71502
72965
|
const result = await client.deployAppVersion({
|
|
71503
72966
|
queries: liveQueries,
|
|
71504
72967
|
app_id: meta3.app_id,
|
|
71505
|
-
source_archive:
|
|
71506
|
-
dist_archive:
|
|
72968
|
+
source_archive: fs8.readFileSync(tmpSource),
|
|
72969
|
+
dist_archive: fs8.readFileSync(tmpDist),
|
|
71507
72970
|
prev_version_id: meta3.current_version_id,
|
|
71508
72971
|
message: args.message ?? derivedDeployMessage(pending),
|
|
71509
72972
|
// Capabilities ARE manifest-authoritative: always send,
|
|
@@ -71511,6 +72974,14 @@ async function appDeploy(client, args) {
|
|
|
71511
72974
|
// `capabilities` block turns every capability OFF on the next deploy
|
|
71512
72975
|
// (fail-safe; the declaration is the grant).
|
|
71513
72976
|
capabilities: meta3.capabilities ?? {},
|
|
72977
|
+
// The three alias sets below are IGNORED by a current server, which derives
|
|
72978
|
+
// them from the source archive this same request uploads — the client that
|
|
72979
|
+
// acts on the set cannot also be the one that reports it. They are still
|
|
72980
|
+
// sent because a server that predates that change DOES read them, and reads
|
|
72981
|
+
// an absent field as `[]`, which switches the unbind guard off for every
|
|
72982
|
+
// version deployed during a rollback window. Drop them once no such server
|
|
72983
|
+
// is a rollback target — the same reasoning as the `queries` echo above.
|
|
72984
|
+
//
|
|
71514
72985
|
// Workflow BINDINGS are NOT a deploy concern — set_app_workflow /
|
|
71515
72986
|
// remove_app_workflow own apps.workflows. What IS sent is the set of
|
|
71516
72987
|
// aliases this bundle CALLS (never the bindings), so remove_app_workflow
|
|
@@ -71539,6 +73010,7 @@ async function appDeploy(client, args) {
|
|
|
71539
73010
|
if (liveAfter) {
|
|
71540
73011
|
warnIfUnbranded(liveAfter);
|
|
71541
73012
|
warnIfUnboundAliases(liveAfter, called);
|
|
73013
|
+
warnIfInertAgentTools(liveAfter);
|
|
71542
73014
|
}
|
|
71543
73015
|
if (liveAfter) {
|
|
71544
73016
|
await pruneOrphanedBindings(
|
|
@@ -71559,8 +73031,8 @@ async function appDeploy(client, args) {
|
|
|
71559
73031
|
throw err2;
|
|
71560
73032
|
}
|
|
71561
73033
|
} finally {
|
|
71562
|
-
if (
|
|
71563
|
-
if (
|
|
73034
|
+
if (fs8.existsSync(tmpSource)) fs8.unlinkSync(tmpSource);
|
|
73035
|
+
if (fs8.existsSync(tmpDist)) fs8.unlinkSync(tmpDist);
|
|
71564
73036
|
}
|
|
71565
73037
|
}
|
|
71566
73038
|
function warnIfUnbranded(app) {
|
|
@@ -71587,8 +73059,82 @@ async function readLiveQueries(client, appId) {
|
|
|
71587
73059
|
process.exit(1);
|
|
71588
73060
|
}
|
|
71589
73061
|
}
|
|
73062
|
+
async function installCommand(client, args) {
|
|
73063
|
+
const res = await client.installPackage(args.packageId, {});
|
|
73064
|
+
if (res.kind === "app") {
|
|
73065
|
+
const { app } = res;
|
|
73066
|
+
console.error(
|
|
73067
|
+
`Installed "${app.name}" (${app.id})` + (app.package_version !== null ? ` at v${app.package_version}` : "") + `.
|
|
73068
|
+
Open it from the workspace's app launcher.
|
|
73069
|
+
To work on it locally: lotics app pull ${app.id}
|
|
73070
|
+
To give it an address: lotics app subdomain <slug> (from inside that project)`
|
|
73071
|
+
);
|
|
73072
|
+
reportKnowledgeWarnings(res.knowledge_warnings);
|
|
73073
|
+
return;
|
|
73074
|
+
}
|
|
73075
|
+
console.error(
|
|
73076
|
+
`Installed content package (${res.installation.id}).
|
|
73077
|
+
Its documents and templates are now in this workspace.`
|
|
73078
|
+
);
|
|
73079
|
+
reportKnowledgeWarnings(res.warnings);
|
|
73080
|
+
}
|
|
73081
|
+
function reportKnowledgeWarnings(warnings) {
|
|
73082
|
+
const missing = warnings.missing_expected_docs;
|
|
73083
|
+
if (missing.length === 0) return;
|
|
73084
|
+
console.error(
|
|
73085
|
+
`
|
|
73086
|
+
\u26A0 ${missing.length} expected knowledge doc(s) are missing from this workspace:
|
|
73087
|
+
` + missing.map((name2) => ` \u2022 ${name2}`).join("\n") + `
|
|
73088
|
+
An agent declaring one of these reads nothing from it \u2014 the run still completes,
|
|
73089
|
+
answering from nowhere. Create them, then re-run the install.`
|
|
73090
|
+
);
|
|
73091
|
+
}
|
|
73092
|
+
async function upgradeCommand(client, args) {
|
|
73093
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
73094
|
+
const meta3 = readAppMeta(projectDir);
|
|
73095
|
+
const plan = await client.previewPackageUpgrade(meta3.app_id, {});
|
|
73096
|
+
if (plan.from_version === plan.to_version) {
|
|
73097
|
+
console.error(`Already on v${plan.from_version} \u2014 nothing to take.`);
|
|
73098
|
+
return;
|
|
73099
|
+
}
|
|
73100
|
+
const blockers = [
|
|
73101
|
+
...plan.diff.breaking.map(
|
|
73102
|
+
(b) => ` \u2022 breaking: ${b.entity}.${b.alias} ${b.kind} ${b.from} \u2192 ${b.to}`
|
|
73103
|
+
),
|
|
73104
|
+
...plan.modified.map(
|
|
73105
|
+
(m) => ` \u2022 locally modified: ${m.kind} "${m.alias}"` + (m.baseline_unknown === true ? " (no baseline recorded \u2014 cannot tell what changed)" : "")
|
|
73106
|
+
),
|
|
73107
|
+
...plan.drift.map((d) => ` \u2022 drifted: ${d.namespace} "${d.alias}"`),
|
|
73108
|
+
// The FOURTH refusal source, and the one this originally missed. The server
|
|
73109
|
+
// throws a BadRequestError for every entry `knowledgeEntryNeedsConsent`
|
|
73110
|
+
// accepts, so leaving it out did not make those upgrades work — it swapped
|
|
73111
|
+
// the carefully-framed refusal for a raw wire 400. Read the canonical
|
|
73112
|
+
// predicate rather than re-deriving the rule: a hand-listed subset of a
|
|
73113
|
+
// server-side decision is how three of four got covered in the first place.
|
|
73114
|
+
...plan.knowledge.filter(knowledgeEntryNeedsConsent).map(
|
|
73115
|
+
(k) => ` \u2022 knowledge: "${k.alias}" (${k.change}${k.modified ? ", locally edited" : ""})`
|
|
73116
|
+
)
|
|
73117
|
+
];
|
|
73118
|
+
if (blockers.length > 0) {
|
|
73119
|
+
console.error(
|
|
73120
|
+
`v${plan.from_version} \u2192 v${plan.to_version} needs decisions this command will not make for you:
|
|
73121
|
+
` + blockers.join("\n") + `
|
|
73122
|
+
|
|
73123
|
+
Each one resolves by choosing what to KEEP, and guessing would discard
|
|
73124
|
+
work nobody asked to lose. Resolve them, or ask an operator to run the
|
|
73125
|
+
upgrade with explicit resolutions.`
|
|
73126
|
+
);
|
|
73127
|
+
process.exit(1);
|
|
73128
|
+
}
|
|
73129
|
+
const applied = await client.upgradePackage(meta3.app_id, { version: plan.to_version });
|
|
73130
|
+
console.error(
|
|
73131
|
+
`Upgraded to v${applied.package_version ?? plan.to_version}.` + (plan.changelog ? `
|
|
73132
|
+
${plan.changelog}` : "") + `
|
|
73133
|
+
Run \`lotics app pull\` to bring this checkout in step.`
|
|
73134
|
+
);
|
|
73135
|
+
}
|
|
71590
73136
|
async function appCheck(client, args = {}) {
|
|
71591
|
-
const projectDir =
|
|
73137
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
71592
73138
|
const meta3 = readAppMeta(projectDir);
|
|
71593
73139
|
const app = await client.getApp(meta3.app_id);
|
|
71594
73140
|
const sourceText = readAppSourceText(projectDir);
|
|
@@ -71605,6 +73151,8 @@ async function appCheck(client, args = {}) {
|
|
|
71605
73151
|
warnIfDynamicAliases(called);
|
|
71606
73152
|
warnIfUndeclaredCapabilities(sourceText, meta3.capabilities);
|
|
71607
73153
|
warnIfUnboundAliases(app, called);
|
|
73154
|
+
warnIfInertAgentTools(app);
|
|
73155
|
+
warnIfProjectFootguns(projectDir, sourceText);
|
|
71608
73156
|
warnIfUnbranded(app);
|
|
71609
73157
|
if (!nothingPending(pending)) {
|
|
71610
73158
|
process.exit(1);
|
|
@@ -71692,8 +73240,8 @@ function driftedAgentAliases(projectDir, liveAgents) {
|
|
|
71692
73240
|
const drifted = [];
|
|
71693
73241
|
for (const [alias, live] of Object.entries(liveAgents ?? {})) {
|
|
71694
73242
|
const file2 = agentFilePath2(projectDir, alias);
|
|
71695
|
-
if (!
|
|
71696
|
-
const local = stripAgentHeader(
|
|
73243
|
+
if (!fs8.existsSync(file2)) continue;
|
|
73244
|
+
const local = stripAgentHeader(fs8.readFileSync(file2, "utf-8"));
|
|
71697
73245
|
if (local === "" || local === (live.instructions ?? "")) continue;
|
|
71698
73246
|
drifted.push(alias);
|
|
71699
73247
|
}
|
|
@@ -71796,21 +73344,21 @@ function derivedDeployMessage(pending) {
|
|
|
71796
73344
|
}
|
|
71797
73345
|
function copyTree(from, to, opts, relative = "") {
|
|
71798
73346
|
const kept = [];
|
|
71799
|
-
for (const entry of
|
|
71800
|
-
const src =
|
|
71801
|
-
const dest =
|
|
71802
|
-
const rel =
|
|
73347
|
+
for (const entry of fs8.readdirSync(from, { withFileTypes: true })) {
|
|
73348
|
+
const src = path9.join(from, entry.name);
|
|
73349
|
+
const dest = path9.join(to, entry.name);
|
|
73350
|
+
const rel = path9.join(relative, entry.name);
|
|
71803
73351
|
if (entry.isDirectory()) {
|
|
71804
|
-
|
|
73352
|
+
fs8.mkdirSync(dest, { recursive: true });
|
|
71805
73353
|
kept.push(...copyTree(src, dest, opts, rel));
|
|
71806
73354
|
continue;
|
|
71807
73355
|
}
|
|
71808
|
-
if (!opts.overwrite &&
|
|
71809
|
-
if (
|
|
73356
|
+
if (!opts.overwrite && fs8.existsSync(dest)) {
|
|
73357
|
+
if (fs8.readFileSync(src).equals(fs8.readFileSync(dest))) continue;
|
|
71810
73358
|
kept.push(rel);
|
|
71811
73359
|
continue;
|
|
71812
73360
|
}
|
|
71813
|
-
|
|
73361
|
+
fs8.copyFileSync(src, dest);
|
|
71814
73362
|
}
|
|
71815
73363
|
return kept;
|
|
71816
73364
|
}
|
|
@@ -71846,6 +73394,151 @@ function warnIfUndeclaredCapabilities(sourceText, capabilities) {
|
|
|
71846
73394
|
Add to package.json#lotics.capabilities: ${block}`
|
|
71847
73395
|
);
|
|
71848
73396
|
}
|
|
73397
|
+
var VITE_CONFIG_NAMES = [
|
|
73398
|
+
"vite.config.ts",
|
|
73399
|
+
"vite.config.mts",
|
|
73400
|
+
"vite.config.cts",
|
|
73401
|
+
"vite.config.js",
|
|
73402
|
+
"vite.config.mjs",
|
|
73403
|
+
"vite.config.cjs"
|
|
73404
|
+
];
|
|
73405
|
+
function codeOnly(source) {
|
|
73406
|
+
let out = "";
|
|
73407
|
+
let i2 = 0;
|
|
73408
|
+
while (i2 < source.length) {
|
|
73409
|
+
const two = source.slice(i2, i2 + 2);
|
|
73410
|
+
if (two === "//") {
|
|
73411
|
+
while (i2 < source.length && source[i2] !== "\n") {
|
|
73412
|
+
out += " ";
|
|
73413
|
+
i2++;
|
|
73414
|
+
}
|
|
73415
|
+
continue;
|
|
73416
|
+
}
|
|
73417
|
+
if (two === "/*") {
|
|
73418
|
+
while (i2 < source.length && source.slice(i2, i2 + 2) !== "*/") {
|
|
73419
|
+
out += source[i2] === "\n" ? "\n" : " ";
|
|
73420
|
+
i2++;
|
|
73421
|
+
}
|
|
73422
|
+
out += " ";
|
|
73423
|
+
i2 += 2;
|
|
73424
|
+
continue;
|
|
73425
|
+
}
|
|
73426
|
+
const quote = source[i2];
|
|
73427
|
+
if (quote === '"' || quote === "'" || quote === "`") {
|
|
73428
|
+
out += " ";
|
|
73429
|
+
i2++;
|
|
73430
|
+
while (i2 < source.length && source[i2] !== quote) {
|
|
73431
|
+
if (source[i2] === "\\") {
|
|
73432
|
+
out += " ";
|
|
73433
|
+
i2 += 2;
|
|
73434
|
+
continue;
|
|
73435
|
+
}
|
|
73436
|
+
out += source[i2] === "\n" ? "\n" : " ";
|
|
73437
|
+
i2++;
|
|
73438
|
+
}
|
|
73439
|
+
out += " ";
|
|
73440
|
+
i2++;
|
|
73441
|
+
continue;
|
|
73442
|
+
}
|
|
73443
|
+
out += source[i2];
|
|
73444
|
+
i2++;
|
|
73445
|
+
}
|
|
73446
|
+
return out;
|
|
73447
|
+
}
|
|
73448
|
+
function defineBlockKeys(config2) {
|
|
73449
|
+
const code = codeOnly(config2);
|
|
73450
|
+
const keys3 = /* @__PURE__ */ new Set();
|
|
73451
|
+
for (const opener of code.matchAll(/\bdefine\s*:\s*\{/g)) {
|
|
73452
|
+
let depth = 1;
|
|
73453
|
+
let i2 = opener.index + opener[0].length;
|
|
73454
|
+
const start = i2;
|
|
73455
|
+
while (i2 < code.length && depth > 0) {
|
|
73456
|
+
if (code[i2] === "{") depth++;
|
|
73457
|
+
else if (code[i2] === "}") depth--;
|
|
73458
|
+
i2++;
|
|
73459
|
+
}
|
|
73460
|
+
for (const key of code.slice(start, i2).matchAll(/(?:^|[{,])\s*([A-Za-z_$][\w$]*)\s*:/g)) {
|
|
73461
|
+
keys3.add(key[1]);
|
|
73462
|
+
}
|
|
73463
|
+
}
|
|
73464
|
+
return keys3;
|
|
73465
|
+
}
|
|
73466
|
+
function warnIfProjectFootguns(projectDir, sourceText) {
|
|
73467
|
+
const lines = [];
|
|
73468
|
+
const configName = VITE_CONFIG_NAMES.find((name2) => fs8.existsSync(path9.join(projectDir, name2)));
|
|
73469
|
+
if (configName !== void 0) {
|
|
73470
|
+
const config2 = fs8.readFileSync(path9.join(projectDir, configName), "utf-8");
|
|
73471
|
+
const defined = defineBlockKeys(config2);
|
|
73472
|
+
const missing = ["global", "__DEV__"].filter((name2) => !defined.has(name2));
|
|
73473
|
+
if (missing.length > 0) {
|
|
73474
|
+
lines.push(
|
|
73475
|
+
[
|
|
73476
|
+
` \u2022 ${configName} does not define ${missing.join(" or ")} \u2014 react-native-web reads`,
|
|
73477
|
+
" `global.cancelAnimationFrame` and `__DEV__` as free variables, so the DEPLOYED",
|
|
73478
|
+
" app throws while dev, build and typecheck all pass.",
|
|
73479
|
+
' define: { __DEV__: "false", global: "globalThis" } (top level AND optimizeDeps.esbuildOptions)'
|
|
73480
|
+
].join("\n")
|
|
73481
|
+
);
|
|
73482
|
+
}
|
|
73483
|
+
}
|
|
73484
|
+
if (/\bwindow\.open\s*\(/.test(sourceText)) {
|
|
73485
|
+
lines.push(
|
|
73486
|
+
[
|
|
73487
|
+
" \u2022 src calls window.open \u2014 the app runs in a sandboxed iframe, which drops it",
|
|
73488
|
+
" silently: no error, no navigation.",
|
|
73489
|
+
' import { openExternal } from "@lotics/app-sdk"'
|
|
73490
|
+
].join("\n")
|
|
73491
|
+
);
|
|
73492
|
+
}
|
|
73493
|
+
if (lines.length === 0) return;
|
|
73494
|
+
console.error(
|
|
73495
|
+
["\n\u26A0 This project has a footgun that only shows up once deployed:", ...lines].join("\n")
|
|
73496
|
+
);
|
|
73497
|
+
}
|
|
73498
|
+
var DECLARATION_BOUND_TOOLS = [
|
|
73499
|
+
{ tool: "run_app_query", field: "query_aliases", noun: "read nothing", placeholder: "<alias>" },
|
|
73500
|
+
{ tool: "run_app_workflow", field: "workflow_aliases", noun: "write nothing", placeholder: "<alias>" },
|
|
73501
|
+
{ tool: "grep_knowledge", field: "knowledge_doc_ids", noun: "search nothing", placeholder: "kdc_\u2026" },
|
|
73502
|
+
{ tool: "read_knowledge", field: "knowledge_doc_ids", noun: "read nothing", placeholder: "kdc_\u2026" },
|
|
73503
|
+
{ tool: "list_knowledge", field: "knowledge_doc_ids", noun: "list nothing", placeholder: "kdc_\u2026" }
|
|
73504
|
+
];
|
|
73505
|
+
function warnIfInertAgentTools(app) {
|
|
73506
|
+
const lines = [];
|
|
73507
|
+
for (const [alias, agent] of Object.entries(app.agents ?? {})) {
|
|
73508
|
+
const decl = agent;
|
|
73509
|
+
const tools = decl.tool_names ?? [];
|
|
73510
|
+
for (const { tool, field, noun, placeholder } of DECLARATION_BOUND_TOOLS) {
|
|
73511
|
+
const granted = decl[field];
|
|
73512
|
+
const hasReach = Array.isArray(granted) && granted.length > 0;
|
|
73513
|
+
const hasTool = tools.includes(tool);
|
|
73514
|
+
if (hasTool && !hasReach) {
|
|
73515
|
+
lines.push(
|
|
73516
|
+
` \u2022 agent "${alias}" holds ${tool} with no ${field} \u2014 it can ${noun}.
|
|
73517
|
+
lotics run set_app_agent '{"app_id":"${app.id}","alias":"${alias}","${field}":["${placeholder}"]}'`
|
|
73518
|
+
);
|
|
73519
|
+
}
|
|
73520
|
+
if (!hasTool && hasReach && !anyToolReaches(tools, field)) {
|
|
73521
|
+
lines.push(
|
|
73522
|
+
` \u2022 agent "${alias}" declares ${field} but holds no tool that reads it \u2014 nothing can reach them.
|
|
73523
|
+
lotics run set_app_agent '{"app_id":"${app.id}","alias":"${alias}","tool_names":${JSON.stringify([...tools, tool])}}'`
|
|
73524
|
+
);
|
|
73525
|
+
}
|
|
73526
|
+
}
|
|
73527
|
+
}
|
|
73528
|
+
if (lines.length === 0) return;
|
|
73529
|
+
console.error(
|
|
73530
|
+
[
|
|
73531
|
+
"\n\u26A0 An agent's capability and its reach disagree. The tool is the capability;",
|
|
73532
|
+
" the declared list is the reach \u2014 either half alone means the call is refused",
|
|
73533
|
+
" or never made, and the run still completes, so this shows up as a prompt problem.",
|
|
73534
|
+
...lines,
|
|
73535
|
+
" Then `lotics app pull` to bring the manifest back in step."
|
|
73536
|
+
].join("\n")
|
|
73537
|
+
);
|
|
73538
|
+
}
|
|
73539
|
+
function anyToolReaches(tools, field) {
|
|
73540
|
+
return DECLARATION_BOUND_TOOLS.some((g) => g.field === field && tools.includes(g.tool));
|
|
73541
|
+
}
|
|
71849
73542
|
function warnIfUnboundAliases(app, called) {
|
|
71850
73543
|
const {
|
|
71851
73544
|
queries: unboundQueries,
|
|
@@ -71870,7 +73563,7 @@ function warnIfUnboundAliases(app, called) {
|
|
|
71870
73563
|
console.error(lines.join("\n"));
|
|
71871
73564
|
}
|
|
71872
73565
|
async function appDev(client, args) {
|
|
71873
|
-
const projectDir =
|
|
73566
|
+
const projectDir = path9.resolve(args.projectDir ?? process.cwd());
|
|
71874
73567
|
const meta3 = readAppMeta(projectDir);
|
|
71875
73568
|
warnAboutDevLink(projectDir, "dev");
|
|
71876
73569
|
writeAppDts(projectDir, { workflows: meta3.workflows, queries: meta3.queries, agents: meta3.agents });
|
|
@@ -72099,7 +73792,7 @@ async function appAgentSet(client, args) {
|
|
|
72099
73792
|
const declared = meta3.agents?.[args.alias];
|
|
72100
73793
|
const hasDeclaration = declared?.inputs !== void 0 || declared?.outputs !== void 0;
|
|
72101
73794
|
const file2 = agentFilePath2(projectDir, args.alias);
|
|
72102
|
-
const hasProse =
|
|
73795
|
+
const hasProse = fs8.existsSync(file2);
|
|
72103
73796
|
if (!hasProse) {
|
|
72104
73797
|
if (isNew) {
|
|
72105
73798
|
console.error(
|
|
@@ -72110,16 +73803,16 @@ async function appAgentSet(client, args) {
|
|
|
72110
73803
|
}
|
|
72111
73804
|
if (!hasDeclaration) {
|
|
72112
73805
|
console.error(
|
|
72113
|
-
`No instructions at ${
|
|
73806
|
+
`No instructions at ${path9.relative(projectDir, file2)}, and nothing declared in package.json#lotics.agents.${args.alias} to push instead.
|
|
72114
73807
|
Run 'lotics app pull ${meta3.app_id}' to write ${AGENTS_DIR}/${args.alias}.md, then edit it.`
|
|
72115
73808
|
);
|
|
72116
73809
|
process.exit(1);
|
|
72117
73810
|
}
|
|
72118
73811
|
}
|
|
72119
|
-
const instructions = hasProse ? stripAgentHeader(
|
|
73812
|
+
const instructions = hasProse ? stripAgentHeader(fs8.readFileSync(file2, "utf-8")) : void 0;
|
|
72120
73813
|
if (instructions === "") {
|
|
72121
73814
|
console.error(
|
|
72122
|
-
`${
|
|
73815
|
+
`${path9.relative(projectDir, file2)} is empty after stripping the header \u2014 refusing to push an empty prompt.`
|
|
72123
73816
|
);
|
|
72124
73817
|
process.exit(1);
|
|
72125
73818
|
}
|
|
@@ -72151,6 +73844,27 @@ async function appAgentSet(client, args) {
|
|
|
72151
73844
|
// The verb is the one line that says which of the two just happened.
|
|
72152
73845
|
`${isNew ? "Created" : "Set"} agent "${args.alias}" (${pushed.join(", ")}` + (live?.model_tier ? `, ${live.model_tier}` : "") + (isNew ? `). Nothing else is declared yet \u2014 set tool_names / knowledge_doc_ids / query_aliases with set_app_agent.` : `). Everything else left as it is.`)
|
|
72153
73846
|
);
|
|
73847
|
+
const UNSENT = [
|
|
73848
|
+
"tool_names",
|
|
73849
|
+
"query_aliases",
|
|
73850
|
+
"workflow_aliases",
|
|
73851
|
+
"knowledge_doc_ids",
|
|
73852
|
+
"model_tier",
|
|
73853
|
+
"effort_level"
|
|
73854
|
+
];
|
|
73855
|
+
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
73856
|
+
const liveFields = { ...live };
|
|
73857
|
+
const carried = UNSENT.filter(
|
|
73858
|
+
(f) => declared?.[f] !== void 0 && !same(declared[f], liveFields[f])
|
|
73859
|
+
);
|
|
73860
|
+
if (!isNew && carried.length > 0) {
|
|
73861
|
+
console.error(
|
|
73862
|
+
` Not sent: ${carried.join(", ")} \u2014 this command pushes prose, inputs and outputs only.
|
|
73863
|
+
Edit one of those in package.json and nothing moves. To change it:
|
|
73864
|
+
lotics run set_app_agent '{"app_id":"${meta3.app_id}","alias":"${args.alias}","<field>":\u2026}'
|
|
73865
|
+
then \`lotics app pull\`.`
|
|
73866
|
+
);
|
|
73867
|
+
}
|
|
72154
73868
|
}
|
|
72155
73869
|
async function appWorkflowSet(client, args) {
|
|
72156
73870
|
const projectDir = args.projectDir ?? process.cwd();
|
|
@@ -72163,18 +73877,18 @@ async function appWorkflowSet(client, args) {
|
|
|
72163
73877
|
process.exit(1);
|
|
72164
73878
|
}
|
|
72165
73879
|
const file2 = workflowFilePath(projectDir, args.alias);
|
|
72166
|
-
if (!
|
|
73880
|
+
if (!fs8.existsSync(file2)) {
|
|
72167
73881
|
console.error(
|
|
72168
|
-
`No workflow body at ${
|
|
73882
|
+
`No workflow body at ${path9.relative(projectDir, file2)}.
|
|
72169
73883
|
If "${args.alias}" is already bound: lotics app pull ${meta3.app_id} (writes the body)
|
|
72170
73884
|
If it is a NEW alias you declared: create that file yourself, then re-run this.`
|
|
72171
73885
|
);
|
|
72172
73886
|
process.exit(1);
|
|
72173
73887
|
}
|
|
72174
73888
|
noteScope({ alias: args.alias });
|
|
72175
|
-
const source = stripWorkflowHeader(
|
|
73889
|
+
const source = stripWorkflowHeader(fs8.readFileSync(file2, "utf-8"));
|
|
72176
73890
|
if (source.trim() === "") {
|
|
72177
|
-
console.error(`Workflow body ${
|
|
73891
|
+
console.error(`Workflow body ${path9.relative(projectDir, file2)} is empty after stripping the header.`);
|
|
72178
73892
|
process.exit(1);
|
|
72179
73893
|
}
|
|
72180
73894
|
const res = await client.setAppWorkflow(meta3.app_id, args.alias, {
|
|
@@ -72307,15 +74021,15 @@ async function appWorkflowCheck(args) {
|
|
|
72307
74021
|
for (const alias of aliases) {
|
|
72308
74022
|
const bodyPath = workflowFilePath(projectDir, alias);
|
|
72309
74023
|
const globalsPath = workflowGlobalsPath(projectDir, alias);
|
|
72310
|
-
if (!
|
|
74024
|
+
if (!fs8.existsSync(bodyPath)) {
|
|
72311
74025
|
console.error(
|
|
72312
|
-
`\u26A0 Skipped "${alias}" \u2014 no body at ${
|
|
74026
|
+
`\u26A0 Skipped "${alias}" \u2014 no body at ${path9.relative(projectDir, bodyPath)}. Run 'lotics app workflow pull' to write it.`
|
|
72313
74027
|
);
|
|
72314
74028
|
continue;
|
|
72315
74029
|
}
|
|
72316
|
-
if (!
|
|
74030
|
+
if (!fs8.existsSync(globalsPath)) {
|
|
72317
74031
|
console.error(
|
|
72318
|
-
`Cannot check "${alias}" \u2014 missing types at ${
|
|
74032
|
+
`Cannot check "${alias}" \u2014 missing types at ${path9.relative(projectDir, globalsPath)}. Run 'lotics app workflow pull' (or 'lotics app codegen') to fetch them.`
|
|
72319
74033
|
);
|
|
72320
74034
|
process.exit(1);
|
|
72321
74035
|
}
|
|
@@ -72334,7 +74048,7 @@ async function appWorkflowCheck(args) {
|
|
|
72334
74048
|
function printWorkflowCheckResults(projectDir, results) {
|
|
72335
74049
|
let totalErrors = 0;
|
|
72336
74050
|
for (const r of results) {
|
|
72337
|
-
const rel =
|
|
74051
|
+
const rel = path9.relative(projectDir, r.bodyPath);
|
|
72338
74052
|
if (r.issues.length === 0) {
|
|
72339
74053
|
console.error(`\u2713 ${r.alias} (${rel}) \u2014 clean`);
|
|
72340
74054
|
continue;
|
|
@@ -72546,11 +74260,11 @@ async function validateOrgWorkspacePin(client, orgId, profile) {
|
|
|
72546
74260
|
}
|
|
72547
74261
|
|
|
72548
74262
|
// src/xlsx.ts
|
|
72549
|
-
import
|
|
74263
|
+
import fs10 from "node:fs";
|
|
72550
74264
|
|
|
72551
74265
|
// src/file_command_io.ts
|
|
72552
|
-
import
|
|
72553
|
-
import
|
|
74266
|
+
import fs9 from "node:fs";
|
|
74267
|
+
import path10 from "node:path";
|
|
72554
74268
|
var CliError = class extends Error {
|
|
72555
74269
|
constructor(message2) {
|
|
72556
74270
|
super(message2);
|
|
@@ -72571,14 +74285,14 @@ function rejectExtraArgs(rest2, arity, usage) {
|
|
|
72571
74285
|
fail2(`${usage} takes ${arity} argument${arity === 1 ? "" : "s"} after <file>, got ${rest2.length}. Unused: ${rest2.slice(arity).join(" ")}`);
|
|
72572
74286
|
}
|
|
72573
74287
|
function writeFileAtomic(filePath, bytes) {
|
|
72574
|
-
const dir =
|
|
72575
|
-
const tmp =
|
|
72576
|
-
|
|
74288
|
+
const dir = path10.dirname(path10.resolve(filePath));
|
|
74289
|
+
const tmp = path10.join(dir, `.${path10.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
|
|
74290
|
+
fs9.writeFileSync(tmp, bytes);
|
|
72577
74291
|
try {
|
|
72578
|
-
|
|
74292
|
+
fs9.renameSync(tmp, filePath);
|
|
72579
74293
|
} catch (error52) {
|
|
72580
74294
|
try {
|
|
72581
|
-
|
|
74295
|
+
fs9.unlinkSync(tmp);
|
|
72582
74296
|
} catch {
|
|
72583
74297
|
}
|
|
72584
74298
|
throw error52;
|
|
@@ -75375,16 +77089,16 @@ var MatcherView = class {
|
|
|
75375
77089
|
* @returns {string|undefined}
|
|
75376
77090
|
*/
|
|
75377
77091
|
getCurrentTag() {
|
|
75378
|
-
const
|
|
75379
|
-
return
|
|
77092
|
+
const path12 = this._matcher.path;
|
|
77093
|
+
return path12.length > 0 ? path12[path12.length - 1].tag : void 0;
|
|
75380
77094
|
}
|
|
75381
77095
|
/**
|
|
75382
77096
|
* Get current namespace.
|
|
75383
77097
|
* @returns {string|undefined}
|
|
75384
77098
|
*/
|
|
75385
77099
|
getCurrentNamespace() {
|
|
75386
|
-
const
|
|
75387
|
-
return
|
|
77100
|
+
const path12 = this._matcher.path;
|
|
77101
|
+
return path12.length > 0 ? path12[path12.length - 1].namespace : void 0;
|
|
75388
77102
|
}
|
|
75389
77103
|
/**
|
|
75390
77104
|
* Get current node's attribute value.
|
|
@@ -75392,9 +77106,9 @@ var MatcherView = class {
|
|
|
75392
77106
|
* @returns {*}
|
|
75393
77107
|
*/
|
|
75394
77108
|
getAttrValue(attrName) {
|
|
75395
|
-
const
|
|
75396
|
-
if (
|
|
75397
|
-
return
|
|
77109
|
+
const path12 = this._matcher.path;
|
|
77110
|
+
if (path12.length === 0) return void 0;
|
|
77111
|
+
return path12[path12.length - 1].values?.[attrName];
|
|
75398
77112
|
}
|
|
75399
77113
|
/**
|
|
75400
77114
|
* Check if current node has an attribute.
|
|
@@ -75402,9 +77116,9 @@ var MatcherView = class {
|
|
|
75402
77116
|
* @returns {boolean}
|
|
75403
77117
|
*/
|
|
75404
77118
|
hasAttr(attrName) {
|
|
75405
|
-
const
|
|
75406
|
-
if (
|
|
75407
|
-
const current =
|
|
77119
|
+
const path12 = this._matcher.path;
|
|
77120
|
+
if (path12.length === 0) return false;
|
|
77121
|
+
const current = path12[path12.length - 1];
|
|
75408
77122
|
return current.values !== void 0 && attrName in current.values;
|
|
75409
77123
|
}
|
|
75410
77124
|
/**
|
|
@@ -75430,18 +77144,18 @@ var MatcherView = class {
|
|
|
75430
77144
|
* @returns {number}
|
|
75431
77145
|
*/
|
|
75432
77146
|
getPosition() {
|
|
75433
|
-
const
|
|
75434
|
-
if (
|
|
75435
|
-
return
|
|
77147
|
+
const path12 = this._matcher.path;
|
|
77148
|
+
if (path12.length === 0) return -1;
|
|
77149
|
+
return path12[path12.length - 1].position ?? 0;
|
|
75436
77150
|
}
|
|
75437
77151
|
/**
|
|
75438
77152
|
* Get current node's repeat counter (occurrence count of this tag name).
|
|
75439
77153
|
* @returns {number}
|
|
75440
77154
|
*/
|
|
75441
77155
|
getCounter() {
|
|
75442
|
-
const
|
|
75443
|
-
if (
|
|
75444
|
-
return
|
|
77156
|
+
const path12 = this._matcher.path;
|
|
77157
|
+
if (path12.length === 0) return -1;
|
|
77158
|
+
return path12[path12.length - 1].counter ?? 0;
|
|
75445
77159
|
}
|
|
75446
77160
|
/**
|
|
75447
77161
|
* Get current node's sibling index (alias for getPosition).
|
|
@@ -81099,10 +82813,10 @@ function resolveRelativePath(basePath, relativePath) {
|
|
|
81099
82813
|
}
|
|
81100
82814
|
return resolved.join("/");
|
|
81101
82815
|
}
|
|
81102
|
-
function findZipEntry(zipEntries,
|
|
81103
|
-
if (zipEntries[
|
|
81104
|
-
if (zipEntries[`xl/${
|
|
81105
|
-
const noSlash =
|
|
82816
|
+
function findZipEntry(zipEntries, path12) {
|
|
82817
|
+
if (zipEntries[path12]) return zipEntries[path12];
|
|
82818
|
+
if (zipEntries[`xl/${path12}`]) return zipEntries[`xl/${path12}`];
|
|
82819
|
+
const noSlash = path12.replace(/^\//, "");
|
|
81106
82820
|
if (zipEntries[noSlash]) return zipEntries[noSlash];
|
|
81107
82821
|
return void 0;
|
|
81108
82822
|
}
|
|
@@ -82734,9 +84448,9 @@ function parseExcelFromZip(zip, options) {
|
|
|
82734
84448
|
}
|
|
82735
84449
|
return result;
|
|
82736
84450
|
}
|
|
82737
|
-
function findEntry(zip,
|
|
82738
|
-
if (zip[
|
|
82739
|
-
const lower2 =
|
|
84451
|
+
function findEntry(zip, path12) {
|
|
84452
|
+
if (zip[path12]) return zip[path12];
|
|
84453
|
+
const lower2 = path12.toLowerCase();
|
|
82740
84454
|
for (const key of Object.keys(zip)) {
|
|
82741
84455
|
if (key.toLowerCase() === lower2) return zip[key];
|
|
82742
84456
|
}
|
|
@@ -83373,12 +85087,12 @@ function extractPivotRoundTripInfo(originalZip) {
|
|
|
83373
85087
|
if (paths.length > 0) pivotTablesBySheetIndex.set(i2, paths);
|
|
83374
85088
|
}
|
|
83375
85089
|
const pivotXmlPaths = [];
|
|
83376
|
-
for (const
|
|
83377
|
-
if (
|
|
83378
|
-
pivotXmlPaths.push(
|
|
85090
|
+
for (const path12 of Object.keys(originalZip)) {
|
|
85091
|
+
if (path12.startsWith("xl/pivotTables/") && path12.endsWith(".xml")) {
|
|
85092
|
+
pivotXmlPaths.push(path12);
|
|
83379
85093
|
}
|
|
83380
|
-
if (
|
|
83381
|
-
pivotXmlPaths.push(
|
|
85094
|
+
if (path12.startsWith("xl/pivotCache/") && path12.endsWith(".xml")) {
|
|
85095
|
+
pivotXmlPaths.push(path12);
|
|
83382
85096
|
}
|
|
83383
85097
|
}
|
|
83384
85098
|
return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths };
|
|
@@ -83386,15 +85100,15 @@ function extractPivotRoundTripInfo(originalZip) {
|
|
|
83386
85100
|
function decode3(bytes) {
|
|
83387
85101
|
return new TextDecoder().decode(bytes);
|
|
83388
85102
|
}
|
|
83389
|
-
function pivotContentTypeFor(
|
|
83390
|
-
if (
|
|
83391
|
-
return `<Override PartName="/${
|
|
85103
|
+
function pivotContentTypeFor(path12) {
|
|
85104
|
+
if (path12.startsWith("xl/pivotTables/") && path12.endsWith(".xml")) {
|
|
85105
|
+
return `<Override PartName="/${path12}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
|
|
83392
85106
|
}
|
|
83393
|
-
if (
|
|
83394
|
-
return `<Override PartName="/${
|
|
85107
|
+
if (path12.includes("/pivotCacheDefinition") && path12.endsWith(".xml")) {
|
|
85108
|
+
return `<Override PartName="/${path12}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
|
|
83395
85109
|
}
|
|
83396
|
-
if (
|
|
83397
|
-
return `<Override PartName="/${
|
|
85110
|
+
if (path12.includes("/pivotCacheRecords") && path12.endsWith(".xml")) {
|
|
85111
|
+
return `<Override PartName="/${path12}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
|
|
83398
85112
|
}
|
|
83399
85113
|
return void 0;
|
|
83400
85114
|
}
|
|
@@ -83467,16 +85181,16 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
83467
85181
|
regeneratedPaths.add(`xl/worksheets/sheet${i2 + 1}.xml`);
|
|
83468
85182
|
regeneratedPaths.add(`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`);
|
|
83469
85183
|
}
|
|
83470
|
-
for (const
|
|
83471
|
-
if (
|
|
83472
|
-
regeneratedPaths.add(
|
|
85184
|
+
for (const path12 of Object.keys(originalZip)) {
|
|
85185
|
+
if (path12.startsWith("xl/drawings/") || path12.startsWith("xl/charts/") || path12.startsWith("xl/tables/") || path12.startsWith("xl/media/")) {
|
|
85186
|
+
regeneratedPaths.add(path12);
|
|
83473
85187
|
}
|
|
83474
85188
|
}
|
|
83475
|
-
for (const [
|
|
83476
|
-
if (regeneratedPaths.has(
|
|
83477
|
-
const ext =
|
|
85189
|
+
for (const [path12, data2] of Object.entries(originalZip)) {
|
|
85190
|
+
if (regeneratedPaths.has(path12)) continue;
|
|
85191
|
+
const ext = path12.slice(path12.lastIndexOf(".") + 1).toLowerCase();
|
|
83478
85192
|
if (!DECLARED_EXTENSIONS.includes(ext)) continue;
|
|
83479
|
-
entries2[
|
|
85193
|
+
entries2[path12] = data2;
|
|
83480
85194
|
}
|
|
83481
85195
|
}
|
|
83482
85196
|
const sharedStrings = buildSharedStrings(workbook);
|
|
@@ -83492,8 +85206,8 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
83492
85206
|
buildWorkbookRels(workbook, pivotInfo)
|
|
83493
85207
|
);
|
|
83494
85208
|
const extraContentTypes = [];
|
|
83495
|
-
for (const
|
|
83496
|
-
const ct = pivotContentTypeFor(
|
|
85209
|
+
for (const path12 of pivotInfo.pivotXmlPaths) {
|
|
85210
|
+
const ct = pivotContentTypeFor(path12);
|
|
83497
85211
|
if (ct) extraContentTypes.push(ct);
|
|
83498
85212
|
}
|
|
83499
85213
|
let globalChartIndex = 1;
|
|
@@ -92518,14 +94232,14 @@ var DependencyGraph = class {
|
|
|
92518
94232
|
stack.push({ cell: p, path: [cell, p] });
|
|
92519
94233
|
}
|
|
92520
94234
|
while (stack.length > 0) {
|
|
92521
|
-
const { cell: current, path:
|
|
92522
|
-
if (current === cell) return
|
|
94235
|
+
const { cell: current, path: path12 } = stack.pop();
|
|
94236
|
+
if (current === cell) return path12;
|
|
92523
94237
|
if (visited.has(current)) continue;
|
|
92524
94238
|
visited.add(current);
|
|
92525
94239
|
const nextPrec = this.precedents.get(current);
|
|
92526
94240
|
if (!nextPrec) continue;
|
|
92527
94241
|
for (const p of nextPrec) {
|
|
92528
|
-
stack.push({ cell: p, path: [...
|
|
94242
|
+
stack.push({ cell: p, path: [...path12, p] });
|
|
92529
94243
|
}
|
|
92530
94244
|
}
|
|
92531
94245
|
return null;
|
|
@@ -93737,8 +95451,8 @@ var SIMPLE_SHEET_KEYS = /* @__PURE__ */ new Set(["name", "cells", "merges", "fre
|
|
|
93737
95451
|
var MAX_COLUMN = 16384;
|
|
93738
95452
|
var MAX_ROW = 1048576;
|
|
93739
95453
|
function loadFile(filePath) {
|
|
93740
|
-
if (!
|
|
93741
|
-
const buffer =
|
|
95454
|
+
if (!fs10.existsSync(filePath)) fail2(`File not found: ${filePath}`);
|
|
95455
|
+
const buffer = fs10.readFileSync(filePath);
|
|
93742
95456
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
93743
95457
|
const originalZip = unzipXlsx(arrayBuffer);
|
|
93744
95458
|
const parsed = parseExcelBuffer(arrayBuffer);
|
|
@@ -93788,7 +95502,7 @@ function lazyEngine(workbook) {
|
|
|
93788
95502
|
};
|
|
93789
95503
|
}
|
|
93790
95504
|
function readToJson(filePath, filter3, opts) {
|
|
93791
|
-
const buffer =
|
|
95505
|
+
const buffer = fs10.readFileSync(filePath);
|
|
93792
95506
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
93793
95507
|
const parsed = parseExcelBuffer(arrayBuffer);
|
|
93794
95508
|
let sheets = parsed.sheets;
|
|
@@ -94301,7 +96015,7 @@ async function runXlsxCommand(subcommand, toolArgs, restArgs) {
|
|
|
94301
96015
|
}
|
|
94302
96016
|
|
|
94303
96017
|
// src/docx.ts
|
|
94304
|
-
import
|
|
96018
|
+
import fs11 from "node:fs";
|
|
94305
96019
|
|
|
94306
96020
|
// ../ooxml/src/doc/errors.ts
|
|
94307
96021
|
var DocParseError = class extends Error {
|
|
@@ -98917,8 +100631,8 @@ async function docModelToDocx(model) {
|
|
|
98917
100631
|
// ../ooxml/src/opc.ts
|
|
98918
100632
|
var import_jszip = __toESM(require_lib4(), 1);
|
|
98919
100633
|
function dropFolderEntries(zip) {
|
|
98920
|
-
for (const [
|
|
98921
|
-
if (entry.dir) delete zip.files[
|
|
100634
|
+
for (const [path12, entry] of Object.entries(zip.files)) {
|
|
100635
|
+
if (entry.dir) delete zip.files[path12];
|
|
98922
100636
|
}
|
|
98923
100637
|
}
|
|
98924
100638
|
|
|
@@ -99150,11 +100864,11 @@ async function parseDocx(buffer) {
|
|
|
99150
100864
|
const zip = await import_jszip3.default.loadAsync(buffer);
|
|
99151
100865
|
const parts = /* @__PURE__ */ new Map();
|
|
99152
100866
|
const filePromises = [];
|
|
99153
|
-
zip.forEach((
|
|
100867
|
+
zip.forEach((path12, file2) => {
|
|
99154
100868
|
if (file2.dir) return;
|
|
99155
100869
|
filePromises.push(
|
|
99156
100870
|
file2.async("uint8array").then((bytes) => {
|
|
99157
|
-
parts.set(
|
|
100871
|
+
parts.set(path12, bytes);
|
|
99158
100872
|
})
|
|
99159
100873
|
);
|
|
99160
100874
|
});
|
|
@@ -99386,9 +101100,9 @@ var DEFAULT_PARTS = [
|
|
|
99386
101100
|
["word/theme/theme1.xml", () => encoder.encode(THEME_XML)]
|
|
99387
101101
|
];
|
|
99388
101102
|
function fillDefaultParts(parts) {
|
|
99389
|
-
for (const [
|
|
99390
|
-
if (!parts.has(
|
|
99391
|
-
parts.set(
|
|
101103
|
+
for (const [path12, makeBytes] of DEFAULT_PARTS) {
|
|
101104
|
+
if (!parts.has(path12)) {
|
|
101105
|
+
parts.set(path12, makeBytes());
|
|
99392
101106
|
}
|
|
99393
101107
|
}
|
|
99394
101108
|
return parts;
|
|
@@ -99398,9 +101112,9 @@ function fillDefaultParts(parts) {
|
|
|
99398
101112
|
async function serializeDocx(doc) {
|
|
99399
101113
|
const zip = new import_jszip4.default();
|
|
99400
101114
|
const parts = fillDefaultParts(new Map(doc.parts));
|
|
99401
|
-
for (const [
|
|
99402
|
-
if (
|
|
99403
|
-
zip.file(
|
|
101115
|
+
for (const [path12, bytes] of parts) {
|
|
101116
|
+
if (path12 === "word/document.xml") continue;
|
|
101117
|
+
zip.file(path12, bytes);
|
|
99404
101118
|
}
|
|
99405
101119
|
const documentXml = serializeDocumentXml(doc);
|
|
99406
101120
|
zip.file("word/document.xml", documentXml);
|
|
@@ -99487,8 +101201,8 @@ var DEFAULT_DOC_ATTRS = {
|
|
|
99487
101201
|
"@_xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
|
99488
101202
|
};
|
|
99489
101203
|
async function loadFile2(filePath) {
|
|
99490
|
-
if (!
|
|
99491
|
-
const bytes =
|
|
101204
|
+
if (!fs11.existsSync(filePath)) fail2(`File not found: ${filePath}`);
|
|
101205
|
+
const bytes = fs11.readFileSync(filePath);
|
|
99492
101206
|
if (isLegacyDoc(bytes)) {
|
|
99493
101207
|
const upgraded = await saveDocxToBuffer(await loadDocxFromBuffer(bytes));
|
|
99494
101208
|
return parseDocx(new Uint8Array(upgraded));
|
|
@@ -99973,10 +101687,10 @@ async function runDocxCommand(subcommand, toolArgs, restArgs) {
|
|
|
99973
101687
|
}
|
|
99974
101688
|
|
|
99975
101689
|
// src/knowledge.ts
|
|
99976
|
-
import
|
|
101690
|
+
import fs12 from "node:fs";
|
|
99977
101691
|
function readBodyFile(filePath) {
|
|
99978
|
-
if (!
|
|
99979
|
-
return
|
|
101692
|
+
if (!fs12.existsSync(filePath)) fail2(`File not found: ${filePath}`);
|
|
101693
|
+
return fs12.readFileSync(filePath, "utf-8");
|
|
99980
101694
|
}
|
|
99981
101695
|
function resolveBody(flags, required2) {
|
|
99982
101696
|
if (flags.from !== void 0 && flags.content !== void 0) {
|
|
@@ -100120,9 +101834,9 @@ import { createServer } from "node:http";
|
|
|
100120
101834
|
import { readFileSync as readFileSync2, writeFileSync, existsSync, mkdtempSync, rmSync, readdirSync } from "node:fs";
|
|
100121
101835
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
100122
101836
|
import { join as join2, dirname, resolve, extname, basename } from "node:path";
|
|
100123
|
-
import { fileURLToPath as
|
|
101837
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
100124
101838
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
100125
|
-
var HERE = dirname(
|
|
101839
|
+
var HERE = dirname(fileURLToPath3(import.meta.url));
|
|
100126
101840
|
function fail3(msg) {
|
|
100127
101841
|
console.error(msg);
|
|
100128
101842
|
process.exit(1);
|
|
@@ -100353,84 +102067,7 @@ USAGE
|
|
|
100353
102067
|
Query tools return IDs used as arguments to other tools.
|
|
100354
102068
|
|
|
100355
102069
|
COMMANDS
|
|
100356
|
-
|
|
100357
|
-
lotics org use <name|id> [--local] Switch active org (--local pins this dir)
|
|
100358
|
-
lotics workspace List workspaces in the active org (marks current)
|
|
100359
|
-
lotics workspace select <id> Switch to a different workspace
|
|
100360
|
-
lotics workspace create <name> Create a new workspace (admin only)
|
|
100361
|
-
lotics workspace delete <id> --yes Delete a workspace (admin only; soft delete, recoverable)
|
|
100362
|
-
lotics workspace doctor Report dangling schema references (admin only)
|
|
100363
|
-
lotics tools List all available tools
|
|
100364
|
-
lotics tools <name> Show tool description and input schema
|
|
100365
|
-
lotics run <tool> '<json>' Execute a tool
|
|
100366
|
-
lotics run <tool> @args.json Read JSON args from a file (large payloads)
|
|
100367
|
-
cat args.json | lotics run <tool> Read JSON args from stdin (large payloads)
|
|
100368
|
-
lotics app create <name> [path] Create a new custom-code app + scaffold locally
|
|
100369
|
-
lotics app pull <app_id> [path] Bootstrap full local env (source + npm install + types)
|
|
100370
|
-
lotics app deploy -m <message> Build + upload current dir as a new version \u2014 COMMIT
|
|
100371
|
-
(-m is required \u2014 it's the version's audit trail;
|
|
100372
|
-
carries code + queries only \u2014 workflow bindings are
|
|
100373
|
-
managed by set_app_workflow / remove_app_workflow)
|
|
100374
|
-
lotics app versions [app_id] Show deploy history newest-first (version,
|
|
100375
|
-
timestamp, deployer, build status, -m message;
|
|
100376
|
-
* marks the currently served version)
|
|
100377
|
-
lotics app codegen [path] Regenerate .lotics/* (types + field/option ids)
|
|
100378
|
-
from the manifest + workspace schema \u2014 no deploy
|
|
100379
|
-
lotics app check Run every deploy pre-flight WITHOUT building or
|
|
100380
|
-
shipping: agent schemas vs the live app, workflow
|
|
100381
|
-
declarations and BODIES vs what is live, aliases
|
|
100382
|
-
the code calls but nothing bound, undeclared
|
|
100383
|
-
capabilities, query drift. Exits 1 on what a
|
|
100384
|
-
deploy would refuse, so CI can gate on it
|
|
100385
|
-
lotics app workflow run <alias> '<json>' Execute a bound app workflow end-to-end
|
|
100386
|
-
(inputs: inline JSON, @file, or stdin;
|
|
100387
|
-
--print-created reports created records +
|
|
100388
|
-
a paste-ready cleanup plan; --cleanup also
|
|
100389
|
-
deletes those records \u2014 NOT a rollback)
|
|
100390
|
-
lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body
|
|
100391
|
-
through set_app_workflow (server verifies)
|
|
100392
|
-
lotics app workflow pull Rewrite src/workflows/*.ts from the server
|
|
100393
|
-
lotics app workflow check [alias] Typecheck src/workflows bodies locally (one
|
|
100394
|
-
isolated program per alias; the app's own tsc)
|
|
100395
|
-
lotics app query set <alias> Push package.json#lotics.queries.<alias> to
|
|
100396
|
-
apps.queries via set_app_query (no deploy;
|
|
100397
|
-
re-synced by the next deploy from the manifest)
|
|
100398
|
-
lotics app agent run <app_id> <alias> '<json>' Run a bound app agent end-to-end
|
|
100399
|
-
(inputs: inline JSON, @file, or stdin; streams
|
|
100400
|
-
progress to stderr, reports the settled run;
|
|
100401
|
-
--session <id> continues a thread; --json)
|
|
100402
|
-
lotics app agent set <alias> Push the edited src/agents/<alias>.md instructions,
|
|
100403
|
-
and ONLY those \u2014 the server merges, so the typed
|
|
100404
|
-
fields keep whatever is bound (a manifest is a
|
|
100405
|
-
snapshot; replaying it would revert them). Change
|
|
100406
|
-
those with set_app_agent, then pull.
|
|
100407
|
-
lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address
|
|
100408
|
-
lotics app rename "<new name>" Rename the app's display name (launcher title)
|
|
100409
|
-
lotics app dev [path] Run the app locally with HMR (RPC forwarded to prod)
|
|
100410
|
-
lotics knowledge list List knowledge docs (id, name, description)
|
|
100411
|
-
lotics knowledge create --name <n> [--description <d>] --from <file.md>
|
|
100412
|
-
Create a doc from a file (or --content <str>);
|
|
100413
|
-
prints the new id
|
|
100414
|
-
lotics knowledge get <id> [-o <file.md>]
|
|
100415
|
-
Fetch a doc's content (to a file, or stdout;
|
|
100416
|
-
--json for the full doc)
|
|
100417
|
-
lotics knowledge update <id> [--from <file.md> | --content <str>] [--name <n>] [--description <d>]
|
|
100418
|
-
Update a doc \u2014 sends only the fields you pass
|
|
100419
|
-
lotics knowledge rm <id> Archive a doc
|
|
100420
|
-
lotics xlsx <subcommand> ... Read/write/edit .xlsx files on your local filesystem
|
|
100421
|
-
(uses the bundled Lotics xlsx engine; prefer over
|
|
100422
|
-
npm xlsx/exceljs for round-trip fidelity)
|
|
100423
|
-
lotics docx <subcommand> ... Read/write/edit .docx files on your local filesystem
|
|
100424
|
-
(uses the bundled Lotics OOXML engine; preserves
|
|
100425
|
-
tables, images, and unknown markup verbatim)
|
|
100426
|
-
lotics file upload <file|dir...> Upload files (alias: lotics upload)
|
|
100427
|
-
lotics file download <file_id> Download a file by ID (alias: lotics download)
|
|
100428
|
-
lotics file download record <record_id> <field_key>
|
|
100429
|
-
Download all files on a record file field
|
|
100430
|
-
lotics file preview <file|fil_id> [-o png]
|
|
100431
|
-
Render a .docx/.xlsx to a PNG \u2014 a local path OR a
|
|
100432
|
-
stored file id (downloaded first). Frontend engines;
|
|
100433
|
-
needs a Chrome/Chromium on the machine
|
|
102070
|
+
${renderCommandsHelp()}
|
|
100434
102071
|
|
|
100435
102072
|
FLAGS
|
|
100436
102073
|
--json Full JSON output (default is human-readable text)
|
|
@@ -100527,8 +102164,8 @@ function prompt(question) {
|
|
|
100527
102164
|
});
|
|
100528
102165
|
});
|
|
100529
102166
|
}
|
|
100530
|
-
async function publicPost(
|
|
100531
|
-
const response = await fetch(`${API_BASE_URL}${
|
|
102167
|
+
async function publicPost(path12, body) {
|
|
102168
|
+
const response = await fetch(`${API_BASE_URL}${path12}`, {
|
|
100532
102169
|
method: "POST",
|
|
100533
102170
|
headers: { "Content-Type": "application/json" },
|
|
100534
102171
|
body: JSON.stringify(body)
|
|
@@ -100653,7 +102290,7 @@ function announceTarget(ctx, workspaceId) {
|
|
|
100653
102290
|
console.error(`lotics \u2192 ${org} / ${workspaceId}`);
|
|
100654
102291
|
}
|
|
100655
102292
|
function appManifestWorkspaceId(command, subcommand, pathArg, flags) {
|
|
100656
|
-
if (command !== "app") return void 0;
|
|
102293
|
+
if (command !== "app" && command !== "upgrade") return void 0;
|
|
100657
102294
|
if (flags.workspace || process.env.LOTICS_WORKSPACE) return void 0;
|
|
100658
102295
|
if (subcommand === "create" || subcommand === "pull") return void 0;
|
|
100659
102296
|
const dir = pathArg && !pathArg.startsWith("-") ? pathArg : process.cwd();
|
|
@@ -100696,13 +102333,13 @@ async function resolveWorkspace(client, ctx) {
|
|
|
100696
102333
|
function resolveUploadPaths(rawPaths) {
|
|
100697
102334
|
const result = [];
|
|
100698
102335
|
for (const p of rawPaths) {
|
|
100699
|
-
const resolved =
|
|
100700
|
-
const stat =
|
|
102336
|
+
const resolved = path11.resolve(p);
|
|
102337
|
+
const stat = fs13.statSync(resolved);
|
|
100701
102338
|
if (stat.isDirectory()) {
|
|
100702
|
-
const entries2 =
|
|
102339
|
+
const entries2 = fs13.readdirSync(resolved, { withFileTypes: true });
|
|
100703
102340
|
for (const entry of entries2) {
|
|
100704
102341
|
if (entry.isFile()) {
|
|
100705
|
-
result.push(
|
|
102342
|
+
result.push(path11.join(resolved, entry.name));
|
|
100706
102343
|
}
|
|
100707
102344
|
}
|
|
100708
102345
|
} else {
|
|
@@ -100726,14 +102363,90 @@ async function main() {
|
|
|
100726
102363
|
subcommand = toolArgs;
|
|
100727
102364
|
toolArgs = restArgs.shift();
|
|
100728
102365
|
}
|
|
102366
|
+
if (flags.help && command === "report") {
|
|
102367
|
+
console.error(REPORT_USAGE);
|
|
102368
|
+
return;
|
|
102369
|
+
}
|
|
100729
102370
|
if (flags.help || !command && !flags.version) {
|
|
100730
102371
|
printHelp();
|
|
100731
102372
|
return;
|
|
100732
102373
|
}
|
|
102374
|
+
if (flags.version && command !== void 0) {
|
|
102375
|
+
console.error(
|
|
102376
|
+
`--version prints this CLI's version and takes no argument; it cannot be combined with a command.
|
|
102377
|
+
The CLI version: lotics --version
|
|
102378
|
+
A package version to take: operator-only for now \u2014 \`lotics upgrade\` takes the next release.`
|
|
102379
|
+
);
|
|
102380
|
+
process.exit(1);
|
|
102381
|
+
}
|
|
100733
102382
|
if (flags.version) {
|
|
100734
102383
|
console.log(VERSION);
|
|
100735
102384
|
return;
|
|
100736
102385
|
}
|
|
102386
|
+
if (command === "install") {
|
|
102387
|
+
if (!subcommand) {
|
|
102388
|
+
console.error("Usage: lotics install <package_id>");
|
|
102389
|
+
console.error(" Materializes a published package into the current workspace.");
|
|
102390
|
+
process.exit(1);
|
|
102391
|
+
}
|
|
102392
|
+
const { client: client2, ctx: ctx2 } = requireClient(flags);
|
|
102393
|
+
await resolveWorkspace(client2, ctx2);
|
|
102394
|
+
await installCommand(client2, { packageId: subcommand });
|
|
102395
|
+
return;
|
|
102396
|
+
}
|
|
102397
|
+
if (command === "upgrade") {
|
|
102398
|
+
const { client: client2, ctx: ctx2 } = requireClient(flags);
|
|
102399
|
+
applyAppManifestWorkspace(ctx2, command, subcommand, void 0, flags);
|
|
102400
|
+
await resolveWorkspace(client2, ctx2);
|
|
102401
|
+
await upgradeCommand(client2, {});
|
|
102402
|
+
return;
|
|
102403
|
+
}
|
|
102404
|
+
if (command === "docs") {
|
|
102405
|
+
docsCommand({ area: subcommand });
|
|
102406
|
+
return;
|
|
102407
|
+
}
|
|
102408
|
+
if (command === "report") {
|
|
102409
|
+
let input = subcommand ?? "";
|
|
102410
|
+
if (input.startsWith("@")) {
|
|
102411
|
+
const file2 = input.slice(1);
|
|
102412
|
+
if (!fs13.existsSync(file2)) {
|
|
102413
|
+
console.error(`No such file: ${file2}`);
|
|
102414
|
+
process.exit(1);
|
|
102415
|
+
}
|
|
102416
|
+
input = fs13.readFileSync(file2, "utf-8");
|
|
102417
|
+
} else if (input === "-") {
|
|
102418
|
+
input = await readStdin();
|
|
102419
|
+
}
|
|
102420
|
+
if (input.trim() === "") {
|
|
102421
|
+
console.error(REPORT_USAGE);
|
|
102422
|
+
process.exit(1);
|
|
102423
|
+
}
|
|
102424
|
+
const parsed2 = parseReport(input);
|
|
102425
|
+
if ("error" in parsed2) {
|
|
102426
|
+
console.error(`${parsed2.error}
|
|
102427
|
+
`);
|
|
102428
|
+
console.error(REPORT_USAGE);
|
|
102429
|
+
process.exit(1);
|
|
102430
|
+
}
|
|
102431
|
+
const reportCtx = resolveContext(flags);
|
|
102432
|
+
if (!reportCtx) {
|
|
102433
|
+
console.error(
|
|
102434
|
+
'Not authenticated, so this could not be sent. Run "lotics auth signup", "lotics auth api-key <key>", or set LOTICS_API_KEY.'
|
|
102435
|
+
);
|
|
102436
|
+
echoReport(parsed2.report);
|
|
102437
|
+
process.exit(1);
|
|
102438
|
+
}
|
|
102439
|
+
noteScope({ org_id: reportCtx.orgId ?? void 0, workspace_id: reportCtx.workspaceId });
|
|
102440
|
+
await reportCommand(
|
|
102441
|
+
new LoticsClient({ apiKey: reportCtx.apiKey, workspaceId: reportCtx.workspaceId }),
|
|
102442
|
+
{
|
|
102443
|
+
report: parsed2.report,
|
|
102444
|
+
version: VERSION,
|
|
102445
|
+
workspaceId: reportCtx.workspaceId
|
|
102446
|
+
}
|
|
102447
|
+
);
|
|
102448
|
+
return;
|
|
102449
|
+
}
|
|
100737
102450
|
if (command === "auth") {
|
|
100738
102451
|
if (subcommand === "signup") {
|
|
100739
102452
|
await handleSignup(toolArgs, flags);
|
|
@@ -100827,13 +102540,13 @@ async function main() {
|
|
|
100827
102540
|
if (command === "preview") {
|
|
100828
102541
|
if (subcommand && isStoredFileId(subcommand)) {
|
|
100829
102542
|
const { client: client2 } = requireClient(flags);
|
|
100830
|
-
const tmpDir =
|
|
102543
|
+
const tmpDir = fs13.mkdtempSync(path11.join(os4.tmpdir(), "lotics-preview-"));
|
|
100831
102544
|
try {
|
|
100832
102545
|
const { path: localPath, filename } = await client2.downloadFileById(subcommand, tmpDir);
|
|
100833
102546
|
const output = flags.output ?? defaultPreviewOutputPath(filename, process.cwd());
|
|
100834
102547
|
await runPreviewCommand(localPath, { output });
|
|
100835
102548
|
} finally {
|
|
100836
|
-
|
|
102549
|
+
fs13.rmSync(tmpDir, { recursive: true, force: true });
|
|
100837
102550
|
}
|
|
100838
102551
|
return;
|
|
100839
102552
|
}
|
|
@@ -100916,9 +102629,12 @@ async function main() {
|
|
|
100916
102629
|
}
|
|
100917
102630
|
return;
|
|
100918
102631
|
}
|
|
100919
|
-
if (command
|
|
102632
|
+
if (!knownVerbs().has(command ?? "")) {
|
|
100920
102633
|
console.error(`Unknown command: ${command}`);
|
|
100921
|
-
console.error('Run "lotics --help" for usage.');
|
|
102634
|
+
console.error('Run "lotics --help" for usage \u2014 read \xA7 COMMANDS whole, not a grep.');
|
|
102635
|
+
console.error(
|
|
102636
|
+
`If Lotics genuinely cannot do this yet, say so \u2014 run \`lotics report\` for the frame.`
|
|
102637
|
+
);
|
|
100922
102638
|
process.exit(1);
|
|
100923
102639
|
}
|
|
100924
102640
|
if (command === "app" && !subcommand) {
|
|
@@ -101172,7 +102888,7 @@ Available workspaces:`);
|
|
|
101172
102888
|
const ingested = await ingestJsonArgs({
|
|
101173
102889
|
rawArg: restArgs[1],
|
|
101174
102890
|
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
101175
|
-
readFile: (p) =>
|
|
102891
|
+
readFile: (p) => fs13.readFileSync(p, "utf-8"),
|
|
101176
102892
|
readStdin
|
|
101177
102893
|
});
|
|
101178
102894
|
if (ingested.kind === "error") {
|
|
@@ -101223,7 +102939,7 @@ Available workspaces:`);
|
|
|
101223
102939
|
const ingested = await ingestJsonArgs({
|
|
101224
102940
|
rawArg: restArgs[2],
|
|
101225
102941
|
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
101226
|
-
readFile: (p) =>
|
|
102942
|
+
readFile: (p) => fs13.readFileSync(p, "utf-8"),
|
|
101227
102943
|
readStdin
|
|
101228
102944
|
});
|
|
101229
102945
|
if (ingested.kind === "error") {
|
|
@@ -101379,7 +103095,7 @@ ${JSON.stringify(info.input_schema, null, 2)}`);
|
|
|
101379
103095
|
const ingested = await ingestJsonArgs({
|
|
101380
103096
|
rawArg: toolArgs,
|
|
101381
103097
|
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
101382
|
-
readFile: (p) =>
|
|
103098
|
+
readFile: (p) => fs13.readFileSync(p, "utf-8"),
|
|
101383
103099
|
readStdin
|
|
101384
103100
|
});
|
|
101385
103101
|
if (ingested.kind === "error") {
|