@lotics/cli 0.71.0 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/dist/app_commands.d.ts +13 -0
- package/dist/app_commands.js +3 -3
- package/dist/args.d.ts +17 -0
- package/dist/args.js +35 -2
- package/dist/args.test.js +49 -0
- package/dist/cli.js +235 -3
- package/dist/client.d.ts +321 -0
- package/dist/client.js +164 -0
- package/dist/dev/rpc_handler.d.ts +1 -1
- package/dist/dev/rpc_handler.js +10 -2
- package/dist/dev/rpc_handler.test.js +24 -6
- package/dist/generate_app_fields.d.ts +2 -0
- package/dist/generate_app_fields.js +1 -1
- package/dist/generate_package_fields.d.ts +48 -0
- package/dist/generate_package_fields.js +104 -0
- package/dist/generate_package_fields.test.d.ts +1 -0
- package/dist/generate_package_fields.test.js +51 -0
- package/dist/package_commands.d.ts +227 -0
- package/dist/package_commands.js +957 -0
- package/dist/package_commands.test.d.ts +1 -0
- package/dist/package_commands.test.js +303 -0
- package/dist/src/cli.js +1420 -138
- package/dist/starter_template.d.ts +1 -1
- package/dist/starter_template.js +10 -4
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -12243,12 +12243,12 @@ var require_tokens = __commonJS({
|
|
|
12243
12243
|
});
|
|
12244
12244
|
}
|
|
12245
12245
|
exports2.assignCategoriesMapProp = assignCategoriesMapProp;
|
|
12246
|
-
function singleAssignCategoriesToksMap(
|
|
12247
|
-
utils_1.forEach(
|
|
12246
|
+
function singleAssignCategoriesToksMap(path9, nextNode) {
|
|
12247
|
+
utils_1.forEach(path9, function(pathNode) {
|
|
12248
12248
|
nextNode.categoryMatchesMap[pathNode.tokenTypeIdx] = true;
|
|
12249
12249
|
});
|
|
12250
12250
|
utils_1.forEach(nextNode.CATEGORIES, function(nextCategory) {
|
|
12251
|
-
var newPath =
|
|
12251
|
+
var newPath = path9.concat(nextNode);
|
|
12252
12252
|
if (!utils_1.contains(newPath, nextCategory)) {
|
|
12253
12253
|
singleAssignCategoriesToksMap(newPath, nextCategory);
|
|
12254
12254
|
}
|
|
@@ -14011,10 +14011,10 @@ var require_interpreter = __commonJS({
|
|
|
14011
14011
|
/** @class */
|
|
14012
14012
|
(function(_super) {
|
|
14013
14013
|
__extends(AbstractNextPossibleTokensWalker2, _super);
|
|
14014
|
-
function AbstractNextPossibleTokensWalker2(topProd,
|
|
14014
|
+
function AbstractNextPossibleTokensWalker2(topProd, path9) {
|
|
14015
14015
|
var _this = _super.call(this) || this;
|
|
14016
14016
|
_this.topProd = topProd;
|
|
14017
|
-
_this.path =
|
|
14017
|
+
_this.path = path9;
|
|
14018
14018
|
_this.possibleTokTypes = [];
|
|
14019
14019
|
_this.nextProductionName = "";
|
|
14020
14020
|
_this.nextProductionOccurrence = 0;
|
|
@@ -14068,9 +14068,9 @@ var require_interpreter = __commonJS({
|
|
|
14068
14068
|
/** @class */
|
|
14069
14069
|
(function(_super) {
|
|
14070
14070
|
__extends(NextAfterTokenWalker2, _super);
|
|
14071
|
-
function NextAfterTokenWalker2(topProd,
|
|
14072
|
-
var _this = _super.call(this, topProd,
|
|
14073
|
-
_this.path =
|
|
14071
|
+
function NextAfterTokenWalker2(topProd, path9) {
|
|
14072
|
+
var _this = _super.call(this, topProd, path9) || this;
|
|
14073
|
+
_this.path = path9;
|
|
14074
14074
|
_this.nextTerminalName = "";
|
|
14075
14075
|
_this.nextTerminalOccurrence = 0;
|
|
14076
14076
|
_this.nextTerminalName = _this.path.lastTok.name;
|
|
@@ -14767,10 +14767,10 @@ var require_lookahead = __commonJS({
|
|
|
14767
14767
|
}
|
|
14768
14768
|
return result;
|
|
14769
14769
|
}
|
|
14770
|
-
function pathToHashKeys(
|
|
14770
|
+
function pathToHashKeys(path9) {
|
|
14771
14771
|
var keys2 = [""];
|
|
14772
|
-
for (var i2 = 0; i2 <
|
|
14773
|
-
var tokType =
|
|
14772
|
+
for (var i2 = 0; i2 < path9.length; i2++) {
|
|
14773
|
+
var tokType = path9[i2];
|
|
14774
14774
|
var longerKeys = [];
|
|
14775
14775
|
for (var j = 0; j < keys2.length; j++) {
|
|
14776
14776
|
var currShorterKey = keys2[j];
|
|
@@ -15082,9 +15082,9 @@ var require_checks = __commonJS({
|
|
|
15082
15082
|
return errors;
|
|
15083
15083
|
}
|
|
15084
15084
|
exports2.validateRuleIsOverridden = validateRuleIsOverridden;
|
|
15085
|
-
function validateNoLeftRecursion(topRule, currRule, errMsgProvider,
|
|
15086
|
-
if (
|
|
15087
|
-
|
|
15085
|
+
function validateNoLeftRecursion(topRule, currRule, errMsgProvider, path9) {
|
|
15086
|
+
if (path9 === void 0) {
|
|
15087
|
+
path9 = [];
|
|
15088
15088
|
}
|
|
15089
15089
|
var errors = [];
|
|
15090
15090
|
var nextNonTerminals = getFirstNoneTerminal(currRule.definition);
|
|
@@ -15097,15 +15097,15 @@ var require_checks = __commonJS({
|
|
|
15097
15097
|
errors.push({
|
|
15098
15098
|
message: errMsgProvider.buildLeftRecursionError({
|
|
15099
15099
|
topLevelRule: topRule,
|
|
15100
|
-
leftRecursionPath:
|
|
15100
|
+
leftRecursionPath: path9
|
|
15101
15101
|
}),
|
|
15102
15102
|
type: parser_1.ParserDefinitionErrorType.LEFT_RECURSION,
|
|
15103
15103
|
ruleName
|
|
15104
15104
|
});
|
|
15105
15105
|
}
|
|
15106
|
-
var validNextSteps = utils.difference(nextNonTerminals,
|
|
15106
|
+
var validNextSteps = utils.difference(nextNonTerminals, path9.concat([topRule]));
|
|
15107
15107
|
var errorsFromNextSteps = utils.map(validNextSteps, function(currRefRule) {
|
|
15108
|
-
var newPath = utils.cloneArr(
|
|
15108
|
+
var newPath = utils.cloneArr(path9);
|
|
15109
15109
|
newPath.push(currRefRule);
|
|
15110
15110
|
return validateNoLeftRecursion(topRule, currRefRule, errMsgProvider, newPath);
|
|
15111
15111
|
});
|
|
@@ -22714,8 +22714,8 @@ var require_utils4 = __commonJS({
|
|
|
22714
22714
|
var result = transform[inputType][outputType](input);
|
|
22715
22715
|
return result;
|
|
22716
22716
|
};
|
|
22717
|
-
exports2.resolve = function(
|
|
22718
|
-
var parts =
|
|
22717
|
+
exports2.resolve = function(path9) {
|
|
22718
|
+
var parts = path9.split("/");
|
|
22719
22719
|
var result = [];
|
|
22720
22720
|
for (var index = 0; index < parts.length; index++) {
|
|
22721
22721
|
var part = parts[index];
|
|
@@ -28568,18 +28568,18 @@ var require_object = __commonJS({
|
|
|
28568
28568
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
28569
28569
|
this.files[name] = object;
|
|
28570
28570
|
};
|
|
28571
|
-
var parentFolder = function(
|
|
28572
|
-
if (
|
|
28573
|
-
|
|
28571
|
+
var parentFolder = function(path9) {
|
|
28572
|
+
if (path9.slice(-1) === "/") {
|
|
28573
|
+
path9 = path9.substring(0, path9.length - 1);
|
|
28574
28574
|
}
|
|
28575
|
-
var lastSlash =
|
|
28576
|
-
return lastSlash > 0 ?
|
|
28575
|
+
var lastSlash = path9.lastIndexOf("/");
|
|
28576
|
+
return lastSlash > 0 ? path9.substring(0, lastSlash) : "";
|
|
28577
28577
|
};
|
|
28578
|
-
var forceTrailingSlash = function(
|
|
28579
|
-
if (
|
|
28580
|
-
|
|
28578
|
+
var forceTrailingSlash = function(path9) {
|
|
28579
|
+
if (path9.slice(-1) !== "/") {
|
|
28580
|
+
path9 += "/";
|
|
28581
28581
|
}
|
|
28582
|
-
return
|
|
28582
|
+
return path9;
|
|
28583
28583
|
};
|
|
28584
28584
|
var folderAdd = function(name, createFolders) {
|
|
28585
28585
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults2.createFolders;
|
|
@@ -29581,8 +29581,8 @@ var require_lib3 = __commonJS({
|
|
|
29581
29581
|
// src/cli.ts
|
|
29582
29582
|
import dns from "node:dns";
|
|
29583
29583
|
import net2 from "node:net";
|
|
29584
|
-
import
|
|
29585
|
-
import
|
|
29584
|
+
import fs9 from "node:fs";
|
|
29585
|
+
import path8 from "node:path";
|
|
29586
29586
|
import readline from "node:readline";
|
|
29587
29587
|
|
|
29588
29588
|
// src/client.ts
|
|
@@ -29680,8 +29680,8 @@ var LoticsClient = class {
|
|
|
29680
29680
|
}
|
|
29681
29681
|
return headers;
|
|
29682
29682
|
}
|
|
29683
|
-
async request(method,
|
|
29684
|
-
const url = `${this.baseUrl}${
|
|
29683
|
+
async request(method, path9, body) {
|
|
29684
|
+
const url = `${this.baseUrl}${path9}`;
|
|
29685
29685
|
const headers = this.buildHeaders();
|
|
29686
29686
|
const init = { method, headers };
|
|
29687
29687
|
if (body !== void 0) {
|
|
@@ -29698,9 +29698,22 @@ var LoticsClient = class {
|
|
|
29698
29698
|
setWorkspaceId(id) {
|
|
29699
29699
|
this.workspaceId = id;
|
|
29700
29700
|
}
|
|
29701
|
+
/** The workspace id the client targets (the `x-workspace-id` header), if resolved. */
|
|
29702
|
+
getWorkspaceId() {
|
|
29703
|
+
return this.workspaceId;
|
|
29704
|
+
}
|
|
29701
29705
|
async listWorkspaces() {
|
|
29702
29706
|
return this.request("GET", "/v1/workspaces");
|
|
29703
29707
|
}
|
|
29708
|
+
/**
|
|
29709
|
+
* Resolve one workspace's info by id from the org's workspace list (the only
|
|
29710
|
+
* API-key-accessible source carrying `is_dev`). Returns null when the
|
|
29711
|
+
* workspace isn't visible to these credentials.
|
|
29712
|
+
*/
|
|
29713
|
+
async getWorkspaceInfo(id) {
|
|
29714
|
+
const workspaces = await this.listWorkspaces();
|
|
29715
|
+
return workspaces.find((w) => w.id === id) ?? null;
|
|
29716
|
+
}
|
|
29704
29717
|
async createWorkspace(body) {
|
|
29705
29718
|
return this.request("POST", "/v1/workspaces", body);
|
|
29706
29719
|
}
|
|
@@ -29749,6 +29762,175 @@ var LoticsClient = class {
|
|
|
29749
29762
|
async createApp(body) {
|
|
29750
29763
|
return this.request("POST", "/v1/apps", body);
|
|
29751
29764
|
}
|
|
29765
|
+
/**
|
|
29766
|
+
* Install an app package version into the current workspace — scaffolds the
|
|
29767
|
+
* data model, deploys the package bundle, materializes its
|
|
29768
|
+
* queries/workflows/agents, and pins the installation. Returns the resulting
|
|
29769
|
+
* installation app. `version` omitted installs the latest published version.
|
|
29770
|
+
*/
|
|
29771
|
+
async installAppPackage(package_id, body) {
|
|
29772
|
+
return this.request(
|
|
29773
|
+
"POST",
|
|
29774
|
+
`/v1/app-packages/${encodeURIComponent(package_id)}/installations`,
|
|
29775
|
+
body
|
|
29776
|
+
);
|
|
29777
|
+
}
|
|
29778
|
+
/**
|
|
29779
|
+
* Eject an installation from its package — re-deploy the pinned version's
|
|
29780
|
+
* source as a workspace-owned app version, then sever the package link
|
|
29781
|
+
* (clears `package_id`/`package_version`, stamps `ejected_at`). One-way: the
|
|
29782
|
+
* app becomes a normal bespoke app and can no longer be upgraded. Returns the
|
|
29783
|
+
* resulting app.
|
|
29784
|
+
*/
|
|
29785
|
+
async ejectAppPackage(app_id) {
|
|
29786
|
+
return this.request("POST", `/v1/apps/${encodeURIComponent(app_id)}/eject`);
|
|
29787
|
+
}
|
|
29788
|
+
/**
|
|
29789
|
+
* Extract a DRAFT app package from an existing bespoke app — the promotion
|
|
29790
|
+
* read (docs/app_packages.md § Promotion). Pure: nothing is written. Returns
|
|
29791
|
+
* the alias-keyed draft `contract` (opaque to the CLI — the server is the
|
|
29792
|
+
* validating authority), the origin workspace's `binding` (which doubles as
|
|
29793
|
+
* the adopt binding), a findings `report` (any `error` ⇒ not publishable
|
|
29794
|
+
* as-is), and the file-backed `template_files` the CLI must stage into the
|
|
29795
|
+
* project at their `bytes_ref` paths. Backs `lotics package extract`.
|
|
29796
|
+
* Admin-only.
|
|
29797
|
+
*/
|
|
29798
|
+
async extractAppPackage(app_id) {
|
|
29799
|
+
return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/package-extract`);
|
|
29800
|
+
}
|
|
29801
|
+
/**
|
|
29802
|
+
* Adopt a published package onto an EXISTING (bespoke or ejected) app — the
|
|
29803
|
+
* final promotion step. The workspace already holds the concrete objects, so
|
|
29804
|
+
* nothing is scaffolded or rewritten: the server verifies the `binding` is
|
|
29805
|
+
* complete, live, and FAITHFUL to the version's contract, then writes only the
|
|
29806
|
+
* installation pin (the app becomes installation #1, upgradeable again). A
|
|
29807
|
+
* ConflictError names the aliases that diverge. `version` omitted adopts the
|
|
29808
|
+
* latest. Backs `lotics package adopt`. Admin-only.
|
|
29809
|
+
*/
|
|
29810
|
+
async adoptAppPackage(app_id, body) {
|
|
29811
|
+
return this.request("POST", `/v1/apps/${encodeURIComponent(app_id)}/package-adopt`, body);
|
|
29812
|
+
}
|
|
29813
|
+
/**
|
|
29814
|
+
* Fleet upgrade — bring every installation of a package across the CALLER'S
|
|
29815
|
+
* org to the target version (latest when omitted) in one call. Hands-off
|
|
29816
|
+
* applies only where the preview is clean; installations with breaking/
|
|
29817
|
+
* drift/modified-core findings are skipped and reported for the normal
|
|
29818
|
+
* per-installation consent flow. Backs `lotics package fleet-upgrade`.
|
|
29819
|
+
* Admin-only; org-scoped (no workspace header needed).
|
|
29820
|
+
*/
|
|
29821
|
+
async fleetUpgradeAppPackage(package_id, body) {
|
|
29822
|
+
return this.request(
|
|
29823
|
+
"POST",
|
|
29824
|
+
`/v1/app-packages/${encodeURIComponent(package_id)}/fleet-upgrade`,
|
|
29825
|
+
body
|
|
29826
|
+
);
|
|
29827
|
+
}
|
|
29828
|
+
// --- App packages (registry authoring + dev harness) ---
|
|
29829
|
+
/**
|
|
29830
|
+
* Create a registry app package — the Lotics-owned, workspace-agnostic
|
|
29831
|
+
* blueprint. `lotics package publish` calls this on first publish (when the
|
|
29832
|
+
* local manifest has no `package_id`), then publishes version 1 against the
|
|
29833
|
+
* returned id. Admin-only.
|
|
29834
|
+
*/
|
|
29835
|
+
async createAppPackage(body) {
|
|
29836
|
+
return this.request("POST", "/v1/app-packages", body);
|
|
29837
|
+
}
|
|
29838
|
+
/**
|
|
29839
|
+
* Fetch a registry app package's metadata (incl. `latest_version` and the
|
|
29840
|
+
* Lotics-backed `is_official` trust badge). Admin-only; cross-tenant by id.
|
|
29841
|
+
*/
|
|
29842
|
+
async getAppPackage(package_id) {
|
|
29843
|
+
return this.request("GET", `/v1/app-packages/${encodeURIComponent(package_id)}`);
|
|
29844
|
+
}
|
|
29845
|
+
/**
|
|
29846
|
+
* Publish a new immutable package version — multipart upload of the alias-keyed
|
|
29847
|
+
* contract (JSON) + the prebuilt code bundle (a gzipped tarball carrying
|
|
29848
|
+
* `source.tar.gz` + `dist.tar.gz` members). The server validates the contract +
|
|
29849
|
+
* bundle, then allocates the next monotonic version. The `contract` is opaque
|
|
29850
|
+
* JSON to the transport (the server is the validating authority). Admin-only.
|
|
29851
|
+
*/
|
|
29852
|
+
async publishAppPackageVersion(package_id, args) {
|
|
29853
|
+
const formData = new FormData();
|
|
29854
|
+
formData.append("contract", JSON.stringify(args.contract));
|
|
29855
|
+
formData.append(
|
|
29856
|
+
"bundle",
|
|
29857
|
+
new Blob([new Uint8Array(args.bundle)], { type: "application/gzip" }),
|
|
29858
|
+
"bundle.tar.gz"
|
|
29859
|
+
);
|
|
29860
|
+
if (args.changelog) formData.append("changelog", args.changelog);
|
|
29861
|
+
const url = `${this.baseUrl}/v1/app-packages/${encodeURIComponent(package_id)}/versions`;
|
|
29862
|
+
const response = await fetch(url, {
|
|
29863
|
+
method: "POST",
|
|
29864
|
+
headers: this.buildHeaders(),
|
|
29865
|
+
// no Content-Type — fetch sets the multipart boundary
|
|
29866
|
+
body: formData
|
|
29867
|
+
});
|
|
29868
|
+
if (!response.ok) await this.throwResponseError(response);
|
|
29869
|
+
return response.json();
|
|
29870
|
+
}
|
|
29871
|
+
/**
|
|
29872
|
+
* Upgrade a package installation to a newer published version — extends the
|
|
29873
|
+
* binding additively, re-materializes the target version's
|
|
29874
|
+
* queries/workflows/agents (preserving workspace overlay), prunes dropped
|
|
29875
|
+
* package artifacts, and bumps the pin. `version` omitted upgrades to the
|
|
29876
|
+
* latest. Returns the resulting app. Admin-only.
|
|
29877
|
+
*/
|
|
29878
|
+
async upgradeAppPackage(app_id, body) {
|
|
29879
|
+
return this.request(
|
|
29880
|
+
"POST",
|
|
29881
|
+
`/v1/apps/${encodeURIComponent(app_id)}/package-upgrade`,
|
|
29882
|
+
body
|
|
29883
|
+
);
|
|
29884
|
+
}
|
|
29885
|
+
/**
|
|
29886
|
+
* Preview a package upgrade — the additive plan, informational removals,
|
|
29887
|
+
* breaking contract changes, the binding drift report, and the modified-core
|
|
29888
|
+
* report — with no writes. Admin-only.
|
|
29889
|
+
*/
|
|
29890
|
+
async previewAppPackageUpgrade(app_id, opts = {}) {
|
|
29891
|
+
const query = opts.version !== void 0 ? `?version=${opts.version}` : "";
|
|
29892
|
+
return this.request(
|
|
29893
|
+
"GET",
|
|
29894
|
+
`/v1/apps/${encodeURIComponent(app_id)}/package-upgrade${query}`
|
|
29895
|
+
);
|
|
29896
|
+
}
|
|
29897
|
+
/**
|
|
29898
|
+
* Re-bind a package role to a different workspace group (the current group
|
|
29899
|
+
* still exists). Re-materializes at the pinned version; refuses over
|
|
29900
|
+
* modified-core findings. Admin-only.
|
|
29901
|
+
*/
|
|
29902
|
+
async rebindAppPackageRole(app_id, body) {
|
|
29903
|
+
return this.request(
|
|
29904
|
+
"POST",
|
|
29905
|
+
`/v1/apps/${encodeURIComponent(app_id)}/package-rebind-role`,
|
|
29906
|
+
body
|
|
29907
|
+
);
|
|
29908
|
+
}
|
|
29909
|
+
/**
|
|
29910
|
+
* Workspace-wide dangling-reference sweep — active app/workflow artifacts
|
|
29911
|
+
* whose prefixed schema ids no longer resolve. Backs
|
|
29912
|
+
* `lotics workspace doctor`. Admin-only.
|
|
29913
|
+
*/
|
|
29914
|
+
async getWorkspaceDanglingReferences() {
|
|
29915
|
+
return this.request("GET", "/v1/workspaces/dangling-references");
|
|
29916
|
+
}
|
|
29917
|
+
/**
|
|
29918
|
+
* Health check for a package installation — version pin vs. registry latest,
|
|
29919
|
+
* binding drift, and locally modified core artifacts. Read-only; backs
|
|
29920
|
+
* `lotics package doctor`. Admin-only.
|
|
29921
|
+
*/
|
|
29922
|
+
async getAppPackageHealth(app_id) {
|
|
29923
|
+
return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/package-health`);
|
|
29924
|
+
}
|
|
29925
|
+
/**
|
|
29926
|
+
* Reset a package installation in a DEV workspace — drop the package-owned
|
|
29927
|
+
* scaffolded tables and re-scaffold clean. Hard-gated server-side to dev
|
|
29928
|
+
* workspaces (a non-dev workspace is refused). Returns the resulting app.
|
|
29929
|
+
* Admin-only.
|
|
29930
|
+
*/
|
|
29931
|
+
async resetAppPackage(app_id) {
|
|
29932
|
+
return this.request("POST", `/v1/apps/${encodeURIComponent(app_id)}/package-reset`);
|
|
29933
|
+
}
|
|
29752
29934
|
/**
|
|
29753
29935
|
* Resolve the display name + fields (incl. select options) of the given tables
|
|
29754
29936
|
* — the schema `lotics app codegen` turns into the runtime `.lotics/app_fields.ts`
|
|
@@ -29830,6 +30012,10 @@ var LoticsClient = class {
|
|
|
29830
30012
|
const qs = group_id ? `?group_id=${encodeURIComponent(group_id)}` : "";
|
|
29831
30013
|
return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/members${qs}`);
|
|
29832
30014
|
}
|
|
30015
|
+
/** A package installation's alias→id maps (fields/options/roles) — the app's runtime F/OPT resolution. */
|
|
30016
|
+
async appBinding(app_id) {
|
|
30017
|
+
return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/binding`);
|
|
30018
|
+
}
|
|
29833
30019
|
/**
|
|
29834
30020
|
* Resolve the full option set (key, label, color) of a named query's select
|
|
29835
30021
|
* columns — the picker companion to `appQuery`. Mirrors
|
|
@@ -30372,7 +30558,7 @@ import { tmpdir } from "node:os";
|
|
|
30372
30558
|
|
|
30373
30559
|
// src/starter_template.ts
|
|
30374
30560
|
var STARTER_FALLBACK_UI_VERSION = "6.1.0";
|
|
30375
|
-
var STARTER_FALLBACK_SDK_VERSION = "0.
|
|
30561
|
+
var STARTER_FALLBACK_SDK_VERSION = "0.51.0";
|
|
30376
30562
|
var STARTER_REACT_NATIVE_VERSION = "0.85.3";
|
|
30377
30563
|
function buildStarterTemplate(args) {
|
|
30378
30564
|
const uiVersion = args.ui_version ?? `^${STARTER_FALLBACK_UI_VERSION}`;
|
|
@@ -30592,6 +30778,11 @@ export default defineConfig({
|
|
|
30592
30778
|
build: {
|
|
30593
30779
|
outDir: "dist",
|
|
30594
30780
|
sourcemap: true,
|
|
30781
|
+
// Top-level await (package projects' generated .lotics/app_fields.ts
|
|
30782
|
+
// resolves the installation binding at module load) needs es2022 \u2014 Vite's
|
|
30783
|
+
// default 'modules' baseline is es2020 and esbuild hard-fails TLA there.
|
|
30784
|
+
// Dev already transforms at esnext, so this only aligns the prod build.
|
|
30785
|
+
target: "es2022",
|
|
30595
30786
|
},
|
|
30596
30787
|
server: {
|
|
30597
30788
|
// Allow the sandboxed null-origin iframe used by \`lotics app dev\` to
|
|
@@ -31095,6 +31286,7 @@ var SUPPORTED_OPS = /* @__PURE__ */ new Set([
|
|
|
31095
31286
|
"workflow",
|
|
31096
31287
|
"members",
|
|
31097
31288
|
"context",
|
|
31289
|
+
"binding",
|
|
31098
31290
|
"upload_url",
|
|
31099
31291
|
"upload_complete",
|
|
31100
31292
|
"comments.list",
|
|
@@ -31112,10 +31304,11 @@ async function dispatchRpc(client, body, opts) {
|
|
|
31112
31304
|
}
|
|
31113
31305
|
switch (body.op) {
|
|
31114
31306
|
case "context": {
|
|
31115
|
-
const who = await client.whoami();
|
|
31307
|
+
const [who, app] = await Promise.all([client.whoami(), client.getApp(body.app_id)]);
|
|
31116
31308
|
return {
|
|
31117
31309
|
member_id: who.member_id,
|
|
31118
|
-
comments_enabled: opts?.commentsEnabled ?? false
|
|
31310
|
+
comments_enabled: opts?.commentsEnabled ?? false,
|
|
31311
|
+
config: app.config ?? {}
|
|
31119
31312
|
};
|
|
31120
31313
|
}
|
|
31121
31314
|
case "query": {
|
|
@@ -31151,6 +31344,8 @@ async function dispatchRpc(client, body, opts) {
|
|
|
31151
31344
|
const p = body.payload;
|
|
31152
31345
|
return client.appMembers(body.app_id, p?.group);
|
|
31153
31346
|
}
|
|
31347
|
+
case "binding":
|
|
31348
|
+
return client.appBinding(body.app_id);
|
|
31154
31349
|
case "upload_url": {
|
|
31155
31350
|
const p = body.payload;
|
|
31156
31351
|
if (!p || typeof p.filename !== "string" || typeof p.mime_type !== "string" || typeof p.file_size !== "number") {
|
|
@@ -31995,6 +32190,7 @@ function walk(node, visit) {
|
|
|
31995
32190
|
case "sort":
|
|
31996
32191
|
case "limit":
|
|
31997
32192
|
case "unpivot":
|
|
32193
|
+
case "unnest":
|
|
31998
32194
|
walk(node.from, visit);
|
|
31999
32195
|
return;
|
|
32000
32196
|
case "join":
|
|
@@ -33162,6 +33358,864 @@ function escapeRegExp(s) {
|
|
|
33162
33358
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33163
33359
|
}
|
|
33164
33360
|
|
|
33361
|
+
// src/package_commands.ts
|
|
33362
|
+
import fs6 from "node:fs";
|
|
33363
|
+
import path7 from "node:path";
|
|
33364
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
33365
|
+
|
|
33366
|
+
// src/generate_package_fields.ts
|
|
33367
|
+
var HEADER5 = `// Auto-generated by 'lotics package new/extract/dev/sync' from contract.json.
|
|
33368
|
+
// DO NOT EDIT \u2014 regenerated whenever the contract changes.
|
|
33369
|
+
//
|
|
33370
|
+
// Package apps resolve F/OPT/ROLE at MODULE LOAD from the installation's
|
|
33371
|
+
// binding (contract alias \u2192 THIS workspace's concrete id) via the SDK's
|
|
33372
|
+
// \`binding\` RPC. Top-level await: the module graph waits for the binding
|
|
33373
|
+
// before any importer evaluates, so every entry is a plain string.
|
|
33374
|
+
import { getAppBinding } from "@lotics/app-sdk";
|
|
33375
|
+
|
|
33376
|
+
const binding = await getAppBinding();
|
|
33377
|
+
|
|
33378
|
+
function bound(map: Record<string, string>, key: string, kind: string): string {
|
|
33379
|
+
const id = map[key];
|
|
33380
|
+
if (id === undefined) {
|
|
33381
|
+
throw new Error(
|
|
33382
|
+
\`app_fields: \${kind} "\${key}" is not in this installation's binding \u2014 \` +
|
|
33383
|
+
\`the generated app_fields.ts is stale relative to the installed contract version.\`,
|
|
33384
|
+
);
|
|
33385
|
+
}
|
|
33386
|
+
return id;
|
|
33387
|
+
}
|
|
33388
|
+
`;
|
|
33389
|
+
function generatePackageAppFields(contract) {
|
|
33390
|
+
const entities = contract.entities ?? [];
|
|
33391
|
+
const roles = contract.roles ?? [];
|
|
33392
|
+
const fieldBlocks = [];
|
|
33393
|
+
for (const entity of entities) {
|
|
33394
|
+
const lines = (entity.fields ?? []).map(
|
|
33395
|
+
(field) => ` ${propKey(field.alias)}: bound(binding.fields, ${JSON.stringify(`${entity.alias}.${field.alias}`)}, "field"),`
|
|
33396
|
+
);
|
|
33397
|
+
if (lines.length === 0) continue;
|
|
33398
|
+
fieldBlocks.push(` ${propKey(entity.alias.toUpperCase())}: {
|
|
33399
|
+
${lines.join("\n")}
|
|
33400
|
+
},`);
|
|
33401
|
+
}
|
|
33402
|
+
const optionBlocks = [];
|
|
33403
|
+
for (const entity of entities) {
|
|
33404
|
+
const perField = [];
|
|
33405
|
+
for (const field of entity.fields ?? []) {
|
|
33406
|
+
const options = field.options ?? [];
|
|
33407
|
+
if (options.length === 0) continue;
|
|
33408
|
+
const lines = options.map(
|
|
33409
|
+
(option) => ` ${propKey(option.alias)}: bound(binding.options, ${JSON.stringify(`${entity.alias}.${field.alias}:${option.alias}`)}, "option"),`
|
|
33410
|
+
);
|
|
33411
|
+
perField.push(` ${propKey(field.alias)}: {
|
|
33412
|
+
${lines.join("\n")}
|
|
33413
|
+
},`);
|
|
33414
|
+
}
|
|
33415
|
+
if (perField.length > 0) {
|
|
33416
|
+
optionBlocks.push(` ${propKey(entity.alias.toUpperCase())}: {
|
|
33417
|
+
${perField.join("\n")}
|
|
33418
|
+
},`);
|
|
33419
|
+
}
|
|
33420
|
+
}
|
|
33421
|
+
const fMap = fieldBlocks.length > 0 ? `export const F = {
|
|
33422
|
+
${fieldBlocks.join("\n")}
|
|
33423
|
+
} as const;` : `export const F = {} as const;`;
|
|
33424
|
+
const optMap = optionBlocks.length > 0 ? `export const OPT = {
|
|
33425
|
+
${optionBlocks.join("\n")}
|
|
33426
|
+
} as const;` : `export const OPT = {} as const;`;
|
|
33427
|
+
const roleMap = roles.length > 0 ? `export const ROLE = {
|
|
33428
|
+
${roles.map((role) => ` ${propKey(role.alias)}: bound(binding.roles, ${JSON.stringify(role.alias)}, "role"),`).join("\n")}
|
|
33429
|
+
} as const;` : `export const ROLE = {} as const;`;
|
|
33430
|
+
return `${HEADER5}
|
|
33431
|
+
${fMap}
|
|
33432
|
+
|
|
33433
|
+
${optMap}
|
|
33434
|
+
|
|
33435
|
+
${roleMap}
|
|
33436
|
+
|
|
33437
|
+
/** Field-id alias map: \`F[<ENTITY>][<field>]\` is this installation's \`fld_\u2026\` id. */
|
|
33438
|
+
export type AppFields = typeof F;
|
|
33439
|
+
/** Select-option alias map: \`OPT[<ENTITY>][<field>][<option>]\` is this installation's \`opt_\u2026\` id. */
|
|
33440
|
+
export type AppOptions = typeof OPT;
|
|
33441
|
+
/** Role alias map: \`ROLE[<role>]\` is this installation's \`grp_\u2026\` id. */
|
|
33442
|
+
export type AppRoles = typeof ROLE;
|
|
33443
|
+
`;
|
|
33444
|
+
}
|
|
33445
|
+
|
|
33446
|
+
// src/file_command_io.ts
|
|
33447
|
+
import fs5 from "node:fs";
|
|
33448
|
+
import path6 from "node:path";
|
|
33449
|
+
var CliError = class extends Error {
|
|
33450
|
+
constructor(message) {
|
|
33451
|
+
super(message);
|
|
33452
|
+
this.name = "CliError";
|
|
33453
|
+
}
|
|
33454
|
+
};
|
|
33455
|
+
function fail(message) {
|
|
33456
|
+
throw new CliError(message);
|
|
33457
|
+
}
|
|
33458
|
+
function writeFileAtomic(filePath, bytes) {
|
|
33459
|
+
const dir = path6.dirname(path6.resolve(filePath));
|
|
33460
|
+
const tmp = path6.join(dir, `.${path6.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
|
|
33461
|
+
fs5.writeFileSync(tmp, bytes);
|
|
33462
|
+
try {
|
|
33463
|
+
fs5.renameSync(tmp, filePath);
|
|
33464
|
+
} catch (error) {
|
|
33465
|
+
try {
|
|
33466
|
+
fs5.unlinkSync(tmp);
|
|
33467
|
+
} catch {
|
|
33468
|
+
}
|
|
33469
|
+
throw error;
|
|
33470
|
+
}
|
|
33471
|
+
console.error(`Wrote ${filePath}`);
|
|
33472
|
+
}
|
|
33473
|
+
|
|
33474
|
+
// src/package_commands.ts
|
|
33475
|
+
var CONTRACT_FILE = "contract.json";
|
|
33476
|
+
var ADOPT_BINDING_FILE = "adopt_binding.json";
|
|
33477
|
+
function packageJsonPath(projectDir) {
|
|
33478
|
+
return path7.join(projectDir, "package.json");
|
|
33479
|
+
}
|
|
33480
|
+
function isPlainObject(value) {
|
|
33481
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33482
|
+
}
|
|
33483
|
+
function readPackageProject(projectDir) {
|
|
33484
|
+
const pkgPath2 = packageJsonPath(projectDir);
|
|
33485
|
+
if (!fs6.existsSync(pkgPath2)) {
|
|
33486
|
+
throw new Error(
|
|
33487
|
+
`No package.json in ${projectDir}. Run this inside a package project (lotics package new <name>).`
|
|
33488
|
+
);
|
|
33489
|
+
}
|
|
33490
|
+
const parsed = JSON.parse(fs6.readFileSync(pkgPath2, "utf-8"));
|
|
33491
|
+
if (!isPlainObject(parsed)) throw new Error(`Malformed package.json in ${projectDir}.`);
|
|
33492
|
+
const lotics = parsed.lotics;
|
|
33493
|
+
const pkg2 = isPlainObject(lotics) ? lotics.package : void 0;
|
|
33494
|
+
if (!isPlainObject(pkg2) || typeof pkg2.name !== "string") {
|
|
33495
|
+
throw new Error(
|
|
33496
|
+
`${pkgPath2} has no lotics.package manifest \u2014 not a package project. Use "lotics package new <name>".`
|
|
33497
|
+
);
|
|
33498
|
+
}
|
|
33499
|
+
const dev = {};
|
|
33500
|
+
if (isPlainObject(pkg2.dev)) {
|
|
33501
|
+
for (const [ws, entry] of Object.entries(pkg2.dev)) {
|
|
33502
|
+
if (isPlainObject(entry) && typeof entry.app_id === "string" && typeof entry.version === "number") {
|
|
33503
|
+
dev[ws] = { app_id: entry.app_id, version: entry.version };
|
|
33504
|
+
}
|
|
33505
|
+
}
|
|
33506
|
+
}
|
|
33507
|
+
const manifest = {
|
|
33508
|
+
id: typeof pkg2.id === "string" ? pkg2.id : null,
|
|
33509
|
+
name: pkg2.name,
|
|
33510
|
+
description: typeof pkg2.description === "string" ? pkg2.description : null,
|
|
33511
|
+
version: typeof pkg2.version === "number" ? pkg2.version : null,
|
|
33512
|
+
dev
|
|
33513
|
+
};
|
|
33514
|
+
return { pkgJson: parsed, manifest };
|
|
33515
|
+
}
|
|
33516
|
+
function writePackageManifest(projectDir, project) {
|
|
33517
|
+
const next = {
|
|
33518
|
+
...project.pkgJson,
|
|
33519
|
+
lotics: {
|
|
33520
|
+
...isPlainObject(project.pkgJson.lotics) ? project.pkgJson.lotics : {},
|
|
33521
|
+
package: project.manifest
|
|
33522
|
+
}
|
|
33523
|
+
};
|
|
33524
|
+
writeFileAtomic(
|
|
33525
|
+
packageJsonPath(projectDir),
|
|
33526
|
+
new TextEncoder().encode(JSON.stringify(next, null, 2) + "\n")
|
|
33527
|
+
);
|
|
33528
|
+
}
|
|
33529
|
+
function sanitizePackageJsonForSource(pkgJson) {
|
|
33530
|
+
const lotics = isPlainObject(pkgJson.lotics) ? pkgJson.lotics : {};
|
|
33531
|
+
const pkg2 = isPlainObject(lotics.package) ? lotics.package : {};
|
|
33532
|
+
const { dev: _dev, ...pkgWithoutDev } = pkg2;
|
|
33533
|
+
return {
|
|
33534
|
+
...pkgJson,
|
|
33535
|
+
lotics: { ...lotics, package: pkgWithoutDev }
|
|
33536
|
+
};
|
|
33537
|
+
}
|
|
33538
|
+
function draftPackageProjectFromApp(appPkgJson, args) {
|
|
33539
|
+
const { lotics: _appManifest, ...rest } = appPkgJson;
|
|
33540
|
+
return {
|
|
33541
|
+
pkgJson: rest,
|
|
33542
|
+
manifest: { id: null, name: args.name, description: args.description, version: null, dev: {} }
|
|
33543
|
+
};
|
|
33544
|
+
}
|
|
33545
|
+
function parseAdoptBindingFile(raw, expectedAppId) {
|
|
33546
|
+
if (!isPlainObject(raw) || typeof raw.app_id !== "string" || typeof raw.workspace_id !== "string" || !isPlainObject(raw.binding)) {
|
|
33547
|
+
throw new Error(
|
|
33548
|
+
"Malformed .lotics/adopt_binding.json \u2014 expected { app_id, workspace_id, binding }."
|
|
33549
|
+
);
|
|
33550
|
+
}
|
|
33551
|
+
if (raw.app_id !== expectedAppId) {
|
|
33552
|
+
throw new Error(
|
|
33553
|
+
`.lotics/adopt_binding.json records app ${raw.app_id}, but you are adopting ${expectedAppId}. A binding maps one app's concrete ids and must never be applied to another \u2014 run "lotics package extract ${expectedAppId}" to produce the right pin.`
|
|
33554
|
+
);
|
|
33555
|
+
}
|
|
33556
|
+
return {
|
|
33557
|
+
app_id: raw.app_id,
|
|
33558
|
+
workspace_id: raw.workspace_id,
|
|
33559
|
+
binding: raw.binding
|
|
33560
|
+
};
|
|
33561
|
+
}
|
|
33562
|
+
function formatExtractReport(report) {
|
|
33563
|
+
const order = ["error", "warning", "info"];
|
|
33564
|
+
const lines = order.flatMap(
|
|
33565
|
+
(severity) => report.filter((f) => f.severity === severity).map((f) => ` [${f.severity}] ${f.area}: ${f.message}`)
|
|
33566
|
+
);
|
|
33567
|
+
return { lines, hasError: report.some((f) => f.severity === "error") };
|
|
33568
|
+
}
|
|
33569
|
+
function dotLoticsDirEnsured(projectDir) {
|
|
33570
|
+
const dir = path7.join(projectDir, ".lotics");
|
|
33571
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
33572
|
+
return dir;
|
|
33573
|
+
}
|
|
33574
|
+
function cmpVersions(a, b) {
|
|
33575
|
+
const pa = a.split(".").map(Number);
|
|
33576
|
+
const pb = b.split(".").map(Number);
|
|
33577
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
33578
|
+
const d = (pa[i2] || 0) - (pb[i2] || 0);
|
|
33579
|
+
if (d !== 0) return d;
|
|
33580
|
+
}
|
|
33581
|
+
return 0;
|
|
33582
|
+
}
|
|
33583
|
+
function packageSdkRange(sdkLatest) {
|
|
33584
|
+
const version = sdkLatest !== null && cmpVersions(sdkLatest, STARTER_FALLBACK_SDK_VERSION) > 0 ? sdkLatest : STARTER_FALLBACK_SDK_VERSION;
|
|
33585
|
+
return `^${version}`;
|
|
33586
|
+
}
|
|
33587
|
+
function readContract(projectDir) {
|
|
33588
|
+
const contractPath = path7.join(projectDir, CONTRACT_FILE);
|
|
33589
|
+
if (!fs6.existsSync(contractPath)) {
|
|
33590
|
+
throw new Error(
|
|
33591
|
+
`No ${CONTRACT_FILE} in ${projectDir}. A package project declares its data model there.`
|
|
33592
|
+
);
|
|
33593
|
+
}
|
|
33594
|
+
return JSON.parse(fs6.readFileSync(contractPath, "utf-8"));
|
|
33595
|
+
}
|
|
33596
|
+
function writePackageAppFields(projectDir) {
|
|
33597
|
+
const contract = readContract(projectDir);
|
|
33598
|
+
const dotLotics = path7.join(projectDir, ".lotics");
|
|
33599
|
+
fs6.mkdirSync(dotLotics, { recursive: true });
|
|
33600
|
+
fs6.writeFileSync(path7.join(dotLotics, "app_fields.ts"), generatePackageAppFields(contract));
|
|
33601
|
+
console.error("Wrote .lotics/app_fields.ts (contract-derived, runtime-resolved)");
|
|
33602
|
+
}
|
|
33603
|
+
var SOURCE_STAGE_EXCLUDES = /* @__PURE__ */ new Set([
|
|
33604
|
+
"node_modules",
|
|
33605
|
+
"dist",
|
|
33606
|
+
".lotics",
|
|
33607
|
+
".git",
|
|
33608
|
+
"bundle.tar.gz",
|
|
33609
|
+
"package.json"
|
|
33610
|
+
]);
|
|
33611
|
+
function stagePackageSource(projectDir, sourceStage) {
|
|
33612
|
+
const project = readPackageProject(projectDir);
|
|
33613
|
+
fs6.mkdirSync(sourceStage, { recursive: true });
|
|
33614
|
+
for (const entry of fs6.readdirSync(projectDir)) {
|
|
33615
|
+
if (SOURCE_STAGE_EXCLUDES.has(entry) || entry.endsWith(".tsbuildinfo")) continue;
|
|
33616
|
+
fs6.cpSync(path7.join(projectDir, entry), path7.join(sourceStage, entry), { recursive: true });
|
|
33617
|
+
}
|
|
33618
|
+
fs6.writeFileSync(
|
|
33619
|
+
path7.join(sourceStage, "package.json"),
|
|
33620
|
+
JSON.stringify(sanitizePackageJsonForSource(project.pkgJson), null, 2) + "\n"
|
|
33621
|
+
);
|
|
33622
|
+
}
|
|
33623
|
+
async function buildPackageBundle(projectDir) {
|
|
33624
|
+
console.error("Building...");
|
|
33625
|
+
await runNpm(["run", "build"], projectDir);
|
|
33626
|
+
const distDir = path7.join(projectDir, "dist");
|
|
33627
|
+
if (!fs6.existsSync(distDir)) {
|
|
33628
|
+
throw new Error(
|
|
33629
|
+
`Build did not produce a dist/ directory in ${projectDir}. Check that 'npm run build' is configured correctly.`
|
|
33630
|
+
);
|
|
33631
|
+
}
|
|
33632
|
+
const stage = fs6.mkdtempSync(path7.join(tmpdir2(), "lotics-pkg-"));
|
|
33633
|
+
const bundlePath = path7.join(tmpdir2(), `lotics-bundle-${Date.now()}.tar.gz`);
|
|
33634
|
+
try {
|
|
33635
|
+
console.error("Packaging source...");
|
|
33636
|
+
const sourceStage = path7.join(stage, "source");
|
|
33637
|
+
stagePackageSource(projectDir, sourceStage);
|
|
33638
|
+
await runTar(["-czf", path7.join(stage, "source.tar.gz"), "-C", sourceStage, "."], projectDir);
|
|
33639
|
+
console.error("Packaging dist...");
|
|
33640
|
+
await runTar(["-czf", path7.join(stage, "dist.tar.gz"), "-C", distDir, "."], projectDir);
|
|
33641
|
+
console.error("Bundling...");
|
|
33642
|
+
await runTar(["-czf", bundlePath, "source.tar.gz", "dist.tar.gz"], stage);
|
|
33643
|
+
return fs6.readFileSync(bundlePath);
|
|
33644
|
+
} finally {
|
|
33645
|
+
fs6.rmSync(stage, { recursive: true, force: true });
|
|
33646
|
+
if (fs6.existsSync(bundlePath)) fs6.unlinkSync(bundlePath);
|
|
33647
|
+
}
|
|
33648
|
+
}
|
|
33649
|
+
function starterContract(name) {
|
|
33650
|
+
return {
|
|
33651
|
+
entities: [
|
|
33652
|
+
{
|
|
33653
|
+
alias: "item",
|
|
33654
|
+
label: name,
|
|
33655
|
+
description: `Records managed by the ${name} package.`,
|
|
33656
|
+
fields: [
|
|
33657
|
+
{ alias: "name", label: "Name", type: "text", required: true },
|
|
33658
|
+
{ alias: "notes", label: "Notes", type: "text" },
|
|
33659
|
+
{
|
|
33660
|
+
alias: "status",
|
|
33661
|
+
label: "Status",
|
|
33662
|
+
type: "select",
|
|
33663
|
+
options: [
|
|
33664
|
+
{ alias: "open", label: "Open", color: "blue" },
|
|
33665
|
+
{ alias: "done", label: "Done", color: "green" }
|
|
33666
|
+
]
|
|
33667
|
+
}
|
|
33668
|
+
]
|
|
33669
|
+
}
|
|
33670
|
+
],
|
|
33671
|
+
roles: [],
|
|
33672
|
+
templates: [],
|
|
33673
|
+
queries: [
|
|
33674
|
+
{
|
|
33675
|
+
alias: "items",
|
|
33676
|
+
ast: {
|
|
33677
|
+
kind: "from_table",
|
|
33678
|
+
from_entity: "item",
|
|
33679
|
+
sort: [{ field_key: "name", order: "asc" }]
|
|
33680
|
+
}
|
|
33681
|
+
}
|
|
33682
|
+
],
|
|
33683
|
+
workflows: [],
|
|
33684
|
+
agents: [],
|
|
33685
|
+
config: [
|
|
33686
|
+
{ alias: "heading", label: "List heading", type: "text", default: name }
|
|
33687
|
+
]
|
|
33688
|
+
};
|
|
33689
|
+
}
|
|
33690
|
+
async function packageNew(args) {
|
|
33691
|
+
const targetPath = path7.resolve(args.targetPath ?? appDirName(args.name));
|
|
33692
|
+
if (fs6.existsSync(targetPath) && fs6.readdirSync(targetPath).length > 0) {
|
|
33693
|
+
throw new Error(`Target directory ${targetPath} is not empty.`);
|
|
33694
|
+
}
|
|
33695
|
+
fs6.mkdirSync(targetPath, { recursive: true });
|
|
33696
|
+
const [uiLatest, sdkLatest] = await Promise.all([
|
|
33697
|
+
fetchLatestNpmVersion("@lotics/ui"),
|
|
33698
|
+
fetchLatestNpmVersion("@lotics/app-sdk")
|
|
33699
|
+
]);
|
|
33700
|
+
const files = buildStarterTemplate({
|
|
33701
|
+
app_name: args.name,
|
|
33702
|
+
app_id: "",
|
|
33703
|
+
workspace_id: "",
|
|
33704
|
+
ui_version: uiLatest ? `^${uiLatest}` : void 0,
|
|
33705
|
+
sdk_version: packageSdkRange(sdkLatest)
|
|
33706
|
+
});
|
|
33707
|
+
for (const file of files) {
|
|
33708
|
+
const fullPath = path7.join(targetPath, file.path);
|
|
33709
|
+
if (file.path === "package.json") {
|
|
33710
|
+
const pkg2 = JSON.parse(file.content);
|
|
33711
|
+
const manifest = {
|
|
33712
|
+
id: null,
|
|
33713
|
+
name: args.name,
|
|
33714
|
+
description: null,
|
|
33715
|
+
version: null,
|
|
33716
|
+
dev: {}
|
|
33717
|
+
};
|
|
33718
|
+
pkg2.lotics = { package: manifest };
|
|
33719
|
+
fs6.mkdirSync(path7.dirname(fullPath), { recursive: true });
|
|
33720
|
+
fs6.writeFileSync(fullPath, JSON.stringify(pkg2, null, 2) + "\n");
|
|
33721
|
+
continue;
|
|
33722
|
+
}
|
|
33723
|
+
fs6.mkdirSync(path7.dirname(fullPath), { recursive: true });
|
|
33724
|
+
fs6.writeFileSync(fullPath, file.content);
|
|
33725
|
+
}
|
|
33726
|
+
fs6.writeFileSync(
|
|
33727
|
+
path7.join(targetPath, CONTRACT_FILE),
|
|
33728
|
+
JSON.stringify(starterContract(args.name), null, 2) + "\n"
|
|
33729
|
+
);
|
|
33730
|
+
writePackageAppFields(targetPath);
|
|
33731
|
+
console.error(`Scaffolded ${files.length + 1} files into ${targetPath}`);
|
|
33732
|
+
console.error("Installing npm dependencies...");
|
|
33733
|
+
await runNpm(["install"], targetPath);
|
|
33734
|
+
console.error(`
|
|
33735
|
+
Ready. Next steps:`);
|
|
33736
|
+
console.error(` cd ${path7.relative(process.cwd(), targetPath) || "."}`);
|
|
33737
|
+
console.error(` # edit contract.json + src/App.tsx, then run it against a dev workspace:`);
|
|
33738
|
+
console.error(` lotics workspace create "<name> dev" --dev`);
|
|
33739
|
+
console.error(` lotics package dev --workspace <dev_ws>`);
|
|
33740
|
+
}
|
|
33741
|
+
async function packageBuild(args) {
|
|
33742
|
+
const projectDir = path7.resolve(args.projectDir ?? process.cwd());
|
|
33743
|
+
readPackageProject(projectDir);
|
|
33744
|
+
const bundle = await buildPackageBundle(projectDir);
|
|
33745
|
+
const out = path7.join(projectDir, "bundle.tar.gz");
|
|
33746
|
+
fs6.writeFileSync(out, bundle);
|
|
33747
|
+
console.error(`Built ${out} (${(bundle.byteLength / 1024).toFixed(1)} KB)`);
|
|
33748
|
+
}
|
|
33749
|
+
async function publishVersion(client, projectDir, opts) {
|
|
33750
|
+
const project = readPackageProject(projectDir);
|
|
33751
|
+
const contract = readContract(projectDir);
|
|
33752
|
+
let packageId = project.manifest.id;
|
|
33753
|
+
if (packageId === null) {
|
|
33754
|
+
const pkg2 = await client.createAppPackage({
|
|
33755
|
+
name: project.manifest.name,
|
|
33756
|
+
description: project.manifest.description
|
|
33757
|
+
});
|
|
33758
|
+
packageId = pkg2.id;
|
|
33759
|
+
project.manifest.id = packageId;
|
|
33760
|
+
writePackageManifest(projectDir, project);
|
|
33761
|
+
console.error(`Created package ${pkg2.name} (${pkg2.id}).`);
|
|
33762
|
+
}
|
|
33763
|
+
const bundle = await buildPackageBundle(projectDir);
|
|
33764
|
+
console.error("Publishing version...");
|
|
33765
|
+
const version = await client.publishAppPackageVersion(packageId, {
|
|
33766
|
+
contract,
|
|
33767
|
+
bundle,
|
|
33768
|
+
changelog: opts.changelog ?? null
|
|
33769
|
+
});
|
|
33770
|
+
project.manifest.version = version.version;
|
|
33771
|
+
writePackageManifest(projectDir, project);
|
|
33772
|
+
return { package_id: packageId, version: version.version };
|
|
33773
|
+
}
|
|
33774
|
+
async function packagePublish(client, args) {
|
|
33775
|
+
const projectDir = path7.resolve(args.projectDir ?? process.cwd());
|
|
33776
|
+
const { package_id, version } = await publishVersion(client, projectDir, {
|
|
33777
|
+
changelog: args.changelog
|
|
33778
|
+
});
|
|
33779
|
+
console.error(`Published ${package_id} v${version}.`);
|
|
33780
|
+
console.error(` Install it: lotics package install ${package_id} --version ${version}`);
|
|
33781
|
+
}
|
|
33782
|
+
function assertDevWorkspace(workspace) {
|
|
33783
|
+
if (workspace.is_dev === true) return;
|
|
33784
|
+
throw new Error(
|
|
33785
|
+
`Workspace "${workspace.name}" (${workspace.id}) is not a dev workspace. "lotics package dev"/"sync" scaffold package tables into the target workspace, so it must be a throwaway dev workspace. Create one with "lotics workspace create <name> --dev" and pass --workspace <dev_ws>.`
|
|
33786
|
+
);
|
|
33787
|
+
}
|
|
33788
|
+
async function syncToDevWorkspace(client, projectDir) {
|
|
33789
|
+
const devWorkspaceId = client.getWorkspaceId();
|
|
33790
|
+
if (!devWorkspaceId) {
|
|
33791
|
+
throw new Error(
|
|
33792
|
+
"No dev workspace selected. Pass --workspace <dev_ws> (a workspace created with --dev)."
|
|
33793
|
+
);
|
|
33794
|
+
}
|
|
33795
|
+
const workspace = await client.getWorkspaceInfo(devWorkspaceId);
|
|
33796
|
+
if (!workspace) {
|
|
33797
|
+
throw new Error(
|
|
33798
|
+
`Workspace ${devWorkspaceId} is not accessible with these credentials. Pass --workspace <dev_ws> (a workspace created with --dev).`
|
|
33799
|
+
);
|
|
33800
|
+
}
|
|
33801
|
+
assertDevWorkspace(workspace);
|
|
33802
|
+
writePackageAppFields(projectDir);
|
|
33803
|
+
const { package_id, version } = await publishVersion(client, projectDir, {
|
|
33804
|
+
changelog: "dev sync"
|
|
33805
|
+
});
|
|
33806
|
+
const project = readPackageProject(projectDir);
|
|
33807
|
+
const existing = project.manifest.dev[devWorkspaceId];
|
|
33808
|
+
let appId;
|
|
33809
|
+
if (existing) {
|
|
33810
|
+
console.error(`Upgrading dev installation ${existing.app_id} \u2192 v${version}...`);
|
|
33811
|
+
const app = await client.upgradeAppPackage(existing.app_id, { version });
|
|
33812
|
+
appId = app.id;
|
|
33813
|
+
} else {
|
|
33814
|
+
console.error(`Installing ${package_id} v${version} into dev workspace ${devWorkspaceId}...`);
|
|
33815
|
+
const app = await client.installAppPackage(package_id, { version });
|
|
33816
|
+
appId = app.id;
|
|
33817
|
+
}
|
|
33818
|
+
project.manifest.dev[devWorkspaceId] = { app_id: appId, version };
|
|
33819
|
+
writePackageManifest(projectDir, project);
|
|
33820
|
+
const installed = await client.getApp(appId);
|
|
33821
|
+
return { app_id: appId, app_name: installed.name, workspace_id: devWorkspaceId, version };
|
|
33822
|
+
}
|
|
33823
|
+
async function packageSync(client, args) {
|
|
33824
|
+
const projectDir = path7.resolve(args.projectDir ?? process.cwd());
|
|
33825
|
+
const result = await syncToDevWorkspace(client, projectDir);
|
|
33826
|
+
console.error(
|
|
33827
|
+
`Synced ${result.app_name} v${result.version} \u2192 ${result.app_id} (workspace ${result.workspace_id}).`
|
|
33828
|
+
);
|
|
33829
|
+
}
|
|
33830
|
+
async function packageDev(client, args) {
|
|
33831
|
+
const projectDir = path7.resolve(args.projectDir ?? process.cwd());
|
|
33832
|
+
const synced = await syncToDevWorkspace(client, projectDir);
|
|
33833
|
+
const handle = await startDevServer({
|
|
33834
|
+
projectDir,
|
|
33835
|
+
app_id: synced.app_id,
|
|
33836
|
+
app_name: synced.app_name,
|
|
33837
|
+
workspace_id: synced.workspace_id,
|
|
33838
|
+
api_url: client.baseUrl,
|
|
33839
|
+
port: args.port,
|
|
33840
|
+
vitePort: args.vitePort,
|
|
33841
|
+
client
|
|
33842
|
+
});
|
|
33843
|
+
await handle.ready;
|
|
33844
|
+
const url = `http://localhost:${handle.port}`;
|
|
33845
|
+
console.error(`
|
|
33846
|
+
lotics package dev`);
|
|
33847
|
+
console.error(` package: ${synced.app_name} (dev installation ${synced.app_id} v${synced.version})`);
|
|
33848
|
+
console.error(` workspace: ${synced.workspace_id} (dev)`);
|
|
33849
|
+
if (client.viewAsMemberId) {
|
|
33850
|
+
console.error(` view as: ${client.viewAsMemberId}`);
|
|
33851
|
+
}
|
|
33852
|
+
console.error(` vite: http://localhost:${handle.vitePort}/`);
|
|
33853
|
+
console.error(` open: ${url}`);
|
|
33854
|
+
console.error(` rpc: ${client.baseUrl} (via Bearer API key)
|
|
33855
|
+
`);
|
|
33856
|
+
console.error(` Edit contract.json then re-run "lotics package dev" / "lotics package sync" to migrate.`);
|
|
33857
|
+
console.error(` Ctrl-C to stop.
|
|
33858
|
+
`);
|
|
33859
|
+
openBrowser(url);
|
|
33860
|
+
await new Promise((resolve2) => {
|
|
33861
|
+
const onSig = () => {
|
|
33862
|
+
process.off("SIGINT", onSig);
|
|
33863
|
+
process.off("SIGTERM", onSig);
|
|
33864
|
+
resolve2();
|
|
33865
|
+
};
|
|
33866
|
+
process.on("SIGINT", onSig);
|
|
33867
|
+
process.on("SIGTERM", onSig);
|
|
33868
|
+
});
|
|
33869
|
+
console.error("\nStopping\u2026");
|
|
33870
|
+
await handle.stop();
|
|
33871
|
+
}
|
|
33872
|
+
async function packageReset(client, args) {
|
|
33873
|
+
const projectDir = path7.resolve(args.projectDir ?? process.cwd());
|
|
33874
|
+
const devWorkspaceId = client.getWorkspaceId();
|
|
33875
|
+
if (!devWorkspaceId) {
|
|
33876
|
+
throw new Error(
|
|
33877
|
+
"No dev workspace selected. Pass --workspace <dev_ws> (a workspace created with --dev)."
|
|
33878
|
+
);
|
|
33879
|
+
}
|
|
33880
|
+
const { manifest } = readPackageProject(projectDir);
|
|
33881
|
+
const pin = manifest.dev[devWorkspaceId];
|
|
33882
|
+
if (!pin) {
|
|
33883
|
+
throw new Error(
|
|
33884
|
+
`No dev installation recorded for workspace ${devWorkspaceId}. Run "lotics package dev --workspace ${devWorkspaceId}" first.`
|
|
33885
|
+
);
|
|
33886
|
+
}
|
|
33887
|
+
console.error(`Resetting dev installation ${pin.app_id} in workspace ${devWorkspaceId}...`);
|
|
33888
|
+
const app = await client.resetAppPackage(pin.app_id);
|
|
33889
|
+
console.error(`Reset ${app.name} \u2192 ${app.id}. The scaffolded tables were dropped and re-created clean.`);
|
|
33890
|
+
}
|
|
33891
|
+
function resolveInstallationAppId(client, explicit) {
|
|
33892
|
+
if (explicit) return explicit;
|
|
33893
|
+
const workspaceId = client.getWorkspaceId();
|
|
33894
|
+
if (!workspaceId) {
|
|
33895
|
+
throw new Error("Pass an app id (lotics package doctor <app_id>) or select a workspace.");
|
|
33896
|
+
}
|
|
33897
|
+
let manifest;
|
|
33898
|
+
try {
|
|
33899
|
+
({ manifest } = readPackageProject(path7.resolve(process.cwd())));
|
|
33900
|
+
} catch {
|
|
33901
|
+
throw new Error(
|
|
33902
|
+
"No app id given and the current directory is not a package project. Pass one explicitly: lotics package doctor <app_id>."
|
|
33903
|
+
);
|
|
33904
|
+
}
|
|
33905
|
+
const pin = manifest.dev[workspaceId];
|
|
33906
|
+
if (!pin) {
|
|
33907
|
+
throw new Error(
|
|
33908
|
+
`No app id given and no dev installation recorded for workspace ${workspaceId}. Pass one explicitly: lotics package doctor <app_id>.`
|
|
33909
|
+
);
|
|
33910
|
+
}
|
|
33911
|
+
return pin.app_id;
|
|
33912
|
+
}
|
|
33913
|
+
function parseResolveFlags(resolve2) {
|
|
33914
|
+
const resolutions = {};
|
|
33915
|
+
for (const entry of resolve2) {
|
|
33916
|
+
const eq = entry.indexOf("=");
|
|
33917
|
+
if (eq <= 0 || eq === entry.length - 1) {
|
|
33918
|
+
throw new Error(
|
|
33919
|
+
`Invalid --resolve "${entry}" \u2014 expected <key>=recreate|revert|keep or <key>=<existing_id>.`
|
|
33920
|
+
);
|
|
33921
|
+
}
|
|
33922
|
+
const key = entry.slice(0, eq);
|
|
33923
|
+
const value = entry.slice(eq + 1);
|
|
33924
|
+
resolutions[key] = value === "recreate" || value === "revert" || value === "keep" ? value : { bind_to: value };
|
|
33925
|
+
}
|
|
33926
|
+
return resolutions;
|
|
33927
|
+
}
|
|
33928
|
+
async function packageDoctor(client, args) {
|
|
33929
|
+
const app_id = resolveInstallationAppId(client, args.app_id);
|
|
33930
|
+
const health = await client.getAppPackageHealth(app_id);
|
|
33931
|
+
console.error(`${health.package_name} \u2014 installation ${health.app_id}`);
|
|
33932
|
+
console.error(
|
|
33933
|
+
` Installed: v${health.installed_version} Latest: v${health.latest_version}` + (health.update_available ? " \u2192 update available" : "")
|
|
33934
|
+
);
|
|
33935
|
+
if (health.drift.length === 0) {
|
|
33936
|
+
console.error(" Binding: healthy \u2014 every bound alias resolves.");
|
|
33937
|
+
} else {
|
|
33938
|
+
console.error(` Binding drift (${health.drift.length}):`);
|
|
33939
|
+
for (const d of health.drift) {
|
|
33940
|
+
console.error(` - ${d.namespace}.${d.alias} \u2192 ${d.id} (missing from the workspace)`);
|
|
33941
|
+
}
|
|
33942
|
+
console.error(
|
|
33943
|
+
` Resolve while upgrading:
|
|
33944
|
+
lotics package upgrade ${app_id} --resolve <namespace.alias>=recreate (or =<existing_id> to re-point)`
|
|
33945
|
+
);
|
|
33946
|
+
process.exitCode = 1;
|
|
33947
|
+
}
|
|
33948
|
+
if (health.modified.length === 0) {
|
|
33949
|
+
console.error(" Package artifacts: pristine \u2014 no local edits an upgrade would revert.");
|
|
33950
|
+
} else {
|
|
33951
|
+
console.error(` Locally modified package artifacts (${health.modified.length}):`);
|
|
33952
|
+
for (const m of health.modified) {
|
|
33953
|
+
console.error(` - ${m.kind}.${m.alias} (an upgrade overwrites this unless kept)`);
|
|
33954
|
+
}
|
|
33955
|
+
console.error(
|
|
33956
|
+
` Consent while upgrading:
|
|
33957
|
+
lotics package upgrade ${app_id} --resolve <kind.alias>=revert (or =keep to retain the edit)`
|
|
33958
|
+
);
|
|
33959
|
+
process.exitCode = 1;
|
|
33960
|
+
}
|
|
33961
|
+
if (health.update_available) {
|
|
33962
|
+
console.error(` Upgrade: lotics package upgrade ${app_id}`);
|
|
33963
|
+
}
|
|
33964
|
+
}
|
|
33965
|
+
async function packageUpgrade(client, args) {
|
|
33966
|
+
const preview = await client.previewAppPackageUpgrade(args.app_id, {
|
|
33967
|
+
...args.version !== void 0 ? { version: args.version } : {}
|
|
33968
|
+
});
|
|
33969
|
+
console.error(
|
|
33970
|
+
`Upgrade v${preview.from_version} \u2192 v${preview.to_version}` + (preview.changelog ? ` \u2014 ${preview.changelog}` : "")
|
|
33971
|
+
);
|
|
33972
|
+
const summarize = (sets) => Object.entries(sets).filter(([, entries]) => entries.length > 0).map(([kind, entries]) => `${entries.length} ${kind}`).join(", ");
|
|
33973
|
+
const added = summarize(preview.diff.added);
|
|
33974
|
+
const removed = summarize(preview.diff.removed);
|
|
33975
|
+
if (added) console.error(` Adds: ${added}`);
|
|
33976
|
+
if (removed) console.error(` Unbinds (workspace data kept): ${removed}`);
|
|
33977
|
+
if (preview.diff.breaking.length > 0) {
|
|
33978
|
+
console.error(
|
|
33979
|
+
" Breaking contract changes \u2014 NOT resolvable via --resolve (a bound alias's shape changed):"
|
|
33980
|
+
);
|
|
33981
|
+
for (const b of preview.diff.breaking) {
|
|
33982
|
+
console.error(` - ${b.entity}.${b.alias} (${b.kind}): ${b.from} \u2192 ${b.to}`);
|
|
33983
|
+
}
|
|
33984
|
+
console.error(
|
|
33985
|
+
` There is no in-flow resolution for this class. The package author must publish a version
|
|
33986
|
+
that keeps these aliases' shape stable, or eject this app (severing the package link)
|
|
33987
|
+
before making the change: lotics package eject ${args.app_id}`
|
|
33988
|
+
);
|
|
33989
|
+
process.exit(1);
|
|
33990
|
+
}
|
|
33991
|
+
const unresolvedDrift = preview.drift.filter(
|
|
33992
|
+
(d) => args.resolutions[`${d.namespace}.${d.alias}`] === void 0
|
|
33993
|
+
);
|
|
33994
|
+
const unresolvedModified = preview.modified.filter(
|
|
33995
|
+
(m) => args.resolutions[`${m.kind}.${m.alias}`] === void 0
|
|
33996
|
+
);
|
|
33997
|
+
if (unresolvedDrift.length > 0 || unresolvedModified.length > 0) {
|
|
33998
|
+
if (unresolvedDrift.length > 0) {
|
|
33999
|
+
console.error(" Binding drift must be resolved before upgrading:");
|
|
34000
|
+
for (const d of unresolvedDrift) {
|
|
34001
|
+
console.error(
|
|
34002
|
+
` --resolve ${d.namespace}.${d.alias}=recreate (or =<existing_id> to re-point; was ${d.id})`
|
|
34003
|
+
);
|
|
34004
|
+
}
|
|
34005
|
+
}
|
|
34006
|
+
if (unresolvedModified.length > 0) {
|
|
34007
|
+
console.error(" Locally modified package artifacts need consent before upgrading:");
|
|
34008
|
+
for (const m of unresolvedModified) {
|
|
34009
|
+
console.error(
|
|
34010
|
+
` --resolve ${m.kind}.${m.alias}=revert (overwrite the local edit; or =keep to retain it)`
|
|
34011
|
+
);
|
|
34012
|
+
}
|
|
34013
|
+
}
|
|
34014
|
+
process.exit(1);
|
|
34015
|
+
}
|
|
34016
|
+
const app = await client.upgradeAppPackage(args.app_id, {
|
|
34017
|
+
...args.version !== void 0 ? { version: args.version } : {},
|
|
34018
|
+
...Object.keys(args.resolutions).length > 0 ? { resolutions: args.resolutions } : {}
|
|
34019
|
+
});
|
|
34020
|
+
console.error(`Upgraded ${app.name} \u2192 v${app.package_version} (${app.id}).`);
|
|
34021
|
+
}
|
|
34022
|
+
async function packageInstall(client, args) {
|
|
34023
|
+
const pkg2 = await client.getAppPackage(args.package_id);
|
|
34024
|
+
console.error(
|
|
34025
|
+
pkg2.is_official ? `Installing ${pkg2.name} \u2014 official Lotics package...` : `Installing ${pkg2.name} \u2014 third-party package (runs under your authority once installed)...`
|
|
34026
|
+
);
|
|
34027
|
+
const app = await client.installAppPackage(args.package_id, {
|
|
34028
|
+
...args.version !== void 0 ? { version: args.version } : {}
|
|
34029
|
+
});
|
|
34030
|
+
const versionLabel = app.package_version !== null ? `v${app.package_version}` : "(unknown version)";
|
|
34031
|
+
console.error(
|
|
34032
|
+
`Installed ${app.name} ${versionLabel} \u2192 ${app.id} (workspace ${app.workspace_id}).`
|
|
34033
|
+
);
|
|
34034
|
+
console.error(" The data model, queries, workflows, and agents are live.");
|
|
34035
|
+
console.error(" Pull it for local editing: lotics app pull " + app.id);
|
|
34036
|
+
}
|
|
34037
|
+
async function packageEject(client, args) {
|
|
34038
|
+
const app = await client.ejectAppPackage(args.app_id);
|
|
34039
|
+
console.error(`Ejected ${app.name} \u2192 ${app.id} (workspace ${app.workspace_id}).`);
|
|
34040
|
+
console.error(" The package link is severed \u2014 it's now a normal bespoke app and can no longer be upgraded.");
|
|
34041
|
+
console.error(" Its data model, queries, workflows, and templates are unchanged.");
|
|
34042
|
+
console.error(" Pull the pinned source for local editing: lotics app pull " + app.id);
|
|
34043
|
+
}
|
|
34044
|
+
async function packageExtract(client, args) {
|
|
34045
|
+
const app = await client.getApp(args.app_id);
|
|
34046
|
+
if (!app.current_version_id) {
|
|
34047
|
+
throw new Error(
|
|
34048
|
+
`App ${app.id} has no deployed version \u2014 extract stages its source archive, so deploy it first.`
|
|
34049
|
+
);
|
|
34050
|
+
}
|
|
34051
|
+
const extracted = await client.extractAppPackage(args.app_id);
|
|
34052
|
+
const { lines, hasError } = formatExtractReport(extracted.report);
|
|
34053
|
+
if (lines.length > 0) {
|
|
34054
|
+
console.error(`Extraction report (${extracted.report.length}):`);
|
|
34055
|
+
for (const line of lines) console.error(line);
|
|
34056
|
+
} else {
|
|
34057
|
+
console.error("Extraction report: no findings.");
|
|
34058
|
+
}
|
|
34059
|
+
const targetPath = path7.resolve(args.targetPath ?? appDirName(app.name));
|
|
34060
|
+
if (fs6.existsSync(targetPath) && fs6.readdirSync(targetPath).length > 0) {
|
|
34061
|
+
throw new Error(`Target directory ${targetPath} is not empty.`);
|
|
34062
|
+
}
|
|
34063
|
+
fs6.mkdirSync(targetPath, { recursive: true });
|
|
34064
|
+
const version = await client.getAppVersion(app.id, app.current_version_id);
|
|
34065
|
+
const sourceUrl = await client.getAppVersionSourceUrl(app.id, version.id);
|
|
34066
|
+
const tmpFile = path7.join(tmpdir2(), `lotics-extract-${app.id}-${Date.now()}.tar.gz`);
|
|
34067
|
+
console.error("Downloading source archive...");
|
|
34068
|
+
await client.downloadFile(sourceUrl, tmpFile);
|
|
34069
|
+
try {
|
|
34070
|
+
console.error(`Extracting to ${targetPath}...`);
|
|
34071
|
+
await runTar(["-xzf", tmpFile, "-C", targetPath], targetPath);
|
|
34072
|
+
} finally {
|
|
34073
|
+
if (fs6.existsSync(tmpFile)) fs6.unlinkSync(tmpFile);
|
|
34074
|
+
}
|
|
34075
|
+
const appPkgJson = JSON.parse(
|
|
34076
|
+
fs6.readFileSync(packageJsonPath(targetPath), "utf-8")
|
|
34077
|
+
);
|
|
34078
|
+
const draft = draftPackageProjectFromApp(appPkgJson, { name: app.name, description: null });
|
|
34079
|
+
const deps = isPlainObject(draft.pkgJson.dependencies) ? draft.pkgJson.dependencies : {};
|
|
34080
|
+
const originRange = typeof deps["@lotics/app-sdk"] === "string" ? deps["@lotics/app-sdk"] : null;
|
|
34081
|
+
const originFloor = originRange?.replace(/^[\^~]/, "") ?? null;
|
|
34082
|
+
if (originFloor === null || cmpVersions(originFloor, STARTER_FALLBACK_SDK_VERSION) < 0) {
|
|
34083
|
+
const raised = packageSdkRange(await fetchLatestNpmVersion("@lotics/app-sdk"));
|
|
34084
|
+
draft.pkgJson.dependencies = { ...deps, "@lotics/app-sdk": raised };
|
|
34085
|
+
console.error(`Raised @lotics/app-sdk to ${raised} (generated app_fields needs getAppBinding)`);
|
|
34086
|
+
}
|
|
34087
|
+
writePackageManifest(targetPath, draft);
|
|
34088
|
+
fs6.writeFileSync(
|
|
34089
|
+
path7.join(targetPath, CONTRACT_FILE),
|
|
34090
|
+
JSON.stringify(extracted.contract, null, 2) + "\n"
|
|
34091
|
+
);
|
|
34092
|
+
console.error(`Wrote ${CONTRACT_FILE}`);
|
|
34093
|
+
writePackageAppFields(targetPath);
|
|
34094
|
+
const starterViteConfig = buildStarterTemplate({
|
|
34095
|
+
app_name: app.name,
|
|
34096
|
+
app_id: "",
|
|
34097
|
+
workspace_id: ""
|
|
34098
|
+
}).find((f) => f.path === "vite.config.ts");
|
|
34099
|
+
if (starterViteConfig === void 0) {
|
|
34100
|
+
throw new Error("starter template is missing vite.config.ts \u2014 cannot refresh the package project");
|
|
34101
|
+
}
|
|
34102
|
+
const viteConfigPath = path7.join(targetPath, "vite.config.ts");
|
|
34103
|
+
const originViteConfig = fs6.existsSync(viteConfigPath) ? fs6.readFileSync(viteConfigPath, "utf-8") : null;
|
|
34104
|
+
fs6.writeFileSync(viteConfigPath, starterViteConfig.content);
|
|
34105
|
+
if (originViteConfig !== null && originViteConfig !== starterViteConfig.content) {
|
|
34106
|
+
const stash = path7.join(dotLoticsDirEnsured(targetPath), "vite.config.origin.ts");
|
|
34107
|
+
fs6.writeFileSync(stash, originViteConfig);
|
|
34108
|
+
console.error(
|
|
34109
|
+
"Refreshed vite.config.ts from the starter (build.target es2022). The origin app's config differed \u2014 its original was saved to .lotics/vite.config.origin.ts; re-apply any custom optimizeDeps/plugins entries you still need (never dev-link aliases)."
|
|
34110
|
+
);
|
|
34111
|
+
} else {
|
|
34112
|
+
console.error("Refreshed vite.config.ts from the starter (build.target es2022)");
|
|
34113
|
+
}
|
|
34114
|
+
for (const tf of extracted.template_files) {
|
|
34115
|
+
const dest = path7.join(targetPath, tf.bytes_ref);
|
|
34116
|
+
fs6.mkdirSync(path7.dirname(dest), { recursive: true });
|
|
34117
|
+
const { path: downloaded } = await client.downloadFileById(tf.file_id, path7.dirname(dest));
|
|
34118
|
+
if (path7.resolve(downloaded) !== path7.resolve(dest)) fs6.renameSync(downloaded, dest);
|
|
34119
|
+
console.error(`Wrote ${tf.bytes_ref}`);
|
|
34120
|
+
}
|
|
34121
|
+
const dotLotics = path7.join(targetPath, ".lotics");
|
|
34122
|
+
fs6.mkdirSync(dotLotics, { recursive: true });
|
|
34123
|
+
fs6.writeFileSync(
|
|
34124
|
+
path7.join(dotLotics, ADOPT_BINDING_FILE),
|
|
34125
|
+
JSON.stringify(
|
|
34126
|
+
{ app_id: app.id, workspace_id: app.workspace_id, binding: extracted.binding },
|
|
34127
|
+
null,
|
|
34128
|
+
2
|
|
34129
|
+
) + "\n"
|
|
34130
|
+
);
|
|
34131
|
+
console.error(`Wrote .lotics/${ADOPT_BINDING_FILE}`);
|
|
34132
|
+
console.error("Installing npm dependencies...");
|
|
34133
|
+
await runNpm(["install"], targetPath);
|
|
34134
|
+
if (hasError) {
|
|
34135
|
+
console.error(
|
|
34136
|
+
"\nExtraction produced error findings \u2014 the draft is written but NOT publishable as-is."
|
|
34137
|
+
);
|
|
34138
|
+
console.error(
|
|
34139
|
+
"Fix the reported items above, then publish (which re-validates the contract)."
|
|
34140
|
+
);
|
|
34141
|
+
process.exitCode = 1;
|
|
34142
|
+
return;
|
|
34143
|
+
}
|
|
34144
|
+
console.error("\nDraft package project written. Next steps:");
|
|
34145
|
+
console.error(` cd ${path7.relative(process.cwd(), targetPath) || "."}`);
|
|
34146
|
+
console.error(" # review the aliases in contract.json, then:");
|
|
34147
|
+
console.error(` lotics package publish -m "v1"`);
|
|
34148
|
+
console.error(` lotics package adopt ${app.id} (from this project, same workspace)`);
|
|
34149
|
+
}
|
|
34150
|
+
async function packageAdopt(client, args) {
|
|
34151
|
+
const projectDir = path7.resolve(args.projectDir ?? process.cwd());
|
|
34152
|
+
const { manifest } = readPackageProject(projectDir);
|
|
34153
|
+
if (manifest.id === null) {
|
|
34154
|
+
throw new Error(
|
|
34155
|
+
"This package project has never been published (no package id). Publish first:\n lotics package publish"
|
|
34156
|
+
);
|
|
34157
|
+
}
|
|
34158
|
+
const version = args.version ?? manifest.version;
|
|
34159
|
+
if (version === null) {
|
|
34160
|
+
throw new Error(
|
|
34161
|
+
"No version to adopt \u2014 publish this project first (lotics package publish) or pass --version N."
|
|
34162
|
+
);
|
|
34163
|
+
}
|
|
34164
|
+
const bindingPath = path7.join(projectDir, ".lotics", ADOPT_BINDING_FILE);
|
|
34165
|
+
if (!fs6.existsSync(bindingPath)) {
|
|
34166
|
+
throw new Error(
|
|
34167
|
+
`No .lotics/${ADOPT_BINDING_FILE} in ${projectDir}. Adopt binds the origin app that "lotics package extract" recorded \u2014 run extract to produce this project.`
|
|
34168
|
+
);
|
|
34169
|
+
}
|
|
34170
|
+
const pin = parseAdoptBindingFile(
|
|
34171
|
+
JSON.parse(fs6.readFileSync(bindingPath, "utf-8")),
|
|
34172
|
+
args.app_id
|
|
34173
|
+
);
|
|
34174
|
+
const app = await client.adoptAppPackage(args.app_id, {
|
|
34175
|
+
package_id: manifest.id,
|
|
34176
|
+
version,
|
|
34177
|
+
binding: pin.binding
|
|
34178
|
+
});
|
|
34179
|
+
console.error(
|
|
34180
|
+
`Adopted ${app.name} \u2192 installation of ${app.package_id} v${app.package_version}.`
|
|
34181
|
+
);
|
|
34182
|
+
console.error(` Verify the installation: lotics package doctor ${app.id}`);
|
|
34183
|
+
}
|
|
34184
|
+
async function packageFleetUpgrade(client, args) {
|
|
34185
|
+
const result = await client.fleetUpgradeAppPackage(args.package_id, {
|
|
34186
|
+
...args.version !== void 0 ? { version: args.version } : {}
|
|
34187
|
+
});
|
|
34188
|
+
console.error(`Fleet upgrade of ${result.package_id} \u2192 v${result.target_version}:`);
|
|
34189
|
+
if (result.installations.length === 0) {
|
|
34190
|
+
console.error(" No installations of this package in your organization.");
|
|
34191
|
+
return;
|
|
34192
|
+
}
|
|
34193
|
+
const counts = { upgraded: 0, up_to_date: 0, skipped: 0, failed: 0 };
|
|
34194
|
+
for (const inst of result.installations) {
|
|
34195
|
+
counts[inst.outcome]++;
|
|
34196
|
+
const from = inst.from_version === null ? "?" : `v${inst.from_version}`;
|
|
34197
|
+
const line = ` [${inst.outcome}] ${inst.workspace_name} \u2014 ${inst.app_name} (${from} \u2192 v${result.target_version})`;
|
|
34198
|
+
if (inst.outcome === "skipped" && inst.blockers) {
|
|
34199
|
+
console.error(
|
|
34200
|
+
`${line}: breaking=${inst.blockers.breaking} drift=${inst.blockers.drift} modified=${inst.blockers.modified}`
|
|
34201
|
+
);
|
|
34202
|
+
console.error(
|
|
34203
|
+
` resolve via: lotics package upgrade ${inst.app_id} --version ${result.target_version} ...`
|
|
34204
|
+
);
|
|
34205
|
+
} else if (inst.message) {
|
|
34206
|
+
console.error(`${line}: ${inst.message}`);
|
|
34207
|
+
} else {
|
|
34208
|
+
console.error(line);
|
|
34209
|
+
}
|
|
34210
|
+
}
|
|
34211
|
+
console.error(
|
|
34212
|
+
`Done: ${counts.upgraded} upgraded, ${counts.up_to_date} already current, ${counts.skipped} skipped, ${counts.failed} failed.`
|
|
34213
|
+
);
|
|
34214
|
+
if (counts.skipped > 0 || counts.failed > 0) {
|
|
34215
|
+
process.exitCode = 1;
|
|
34216
|
+
}
|
|
34217
|
+
}
|
|
34218
|
+
|
|
33165
34219
|
// src/args.ts
|
|
33166
34220
|
function parseArgs(argv) {
|
|
33167
34221
|
const flags = {
|
|
@@ -33178,9 +34232,12 @@ function parseArgs(argv) {
|
|
|
33178
34232
|
message: void 0,
|
|
33179
34233
|
local: false,
|
|
33180
34234
|
all: false,
|
|
34235
|
+
dev: false,
|
|
33181
34236
|
yes: false,
|
|
33182
34237
|
printCreated: false,
|
|
33183
34238
|
cleanup: false,
|
|
34239
|
+
packageVersion: void 0,
|
|
34240
|
+
resolve: [],
|
|
33184
34241
|
version: false,
|
|
33185
34242
|
help: false
|
|
33186
34243
|
};
|
|
@@ -33231,6 +34288,9 @@ function parseArgs(argv) {
|
|
|
33231
34288
|
case "--local":
|
|
33232
34289
|
flags.local = true;
|
|
33233
34290
|
break;
|
|
34291
|
+
case "--dev":
|
|
34292
|
+
flags.dev = true;
|
|
34293
|
+
break;
|
|
33234
34294
|
case "--all":
|
|
33235
34295
|
flags.all = true;
|
|
33236
34296
|
break;
|
|
@@ -33245,10 +34305,32 @@ function parseArgs(argv) {
|
|
|
33245
34305
|
case "--cleanup":
|
|
33246
34306
|
flags.cleanup = true;
|
|
33247
34307
|
break;
|
|
34308
|
+
case "--resolve": {
|
|
34309
|
+
const value = argv[++i2];
|
|
34310
|
+
if (value === void 0 || value.startsWith("-")) {
|
|
34311
|
+
throw new Error(
|
|
34312
|
+
"--resolve requires a value: <key>=recreate|revert|keep or <key>=<existing_id> (drift: <namespace.alias>; modified core: <kind>.<alias>)."
|
|
34313
|
+
);
|
|
34314
|
+
}
|
|
34315
|
+
flags.resolve.push(value);
|
|
34316
|
+
break;
|
|
34317
|
+
}
|
|
33248
34318
|
case "--version":
|
|
33249
|
-
case "-v":
|
|
33250
|
-
|
|
34319
|
+
case "-v": {
|
|
34320
|
+
const next = argv[i2 + 1];
|
|
34321
|
+
if (command === "package") {
|
|
34322
|
+
if (next === void 0 || next.startsWith("-")) {
|
|
34323
|
+
throw new Error(
|
|
34324
|
+
"--version requires a version number for package commands (e.g. --version 2)."
|
|
34325
|
+
);
|
|
34326
|
+
}
|
|
34327
|
+
flags.packageVersion = next;
|
|
34328
|
+
i2++;
|
|
34329
|
+
} else {
|
|
34330
|
+
flags.version = true;
|
|
34331
|
+
}
|
|
33251
34332
|
break;
|
|
34333
|
+
}
|
|
33252
34334
|
case "--help":
|
|
33253
34335
|
case "-h":
|
|
33254
34336
|
flags.help = true;
|
|
@@ -33299,35 +34381,7 @@ async function ingestJsonArgs(opts) {
|
|
|
33299
34381
|
}
|
|
33300
34382
|
|
|
33301
34383
|
// src/xlsx.ts
|
|
33302
|
-
import
|
|
33303
|
-
|
|
33304
|
-
// src/file_command_io.ts
|
|
33305
|
-
import fs5 from "node:fs";
|
|
33306
|
-
import path6 from "node:path";
|
|
33307
|
-
var CliError = class extends Error {
|
|
33308
|
-
constructor(message) {
|
|
33309
|
-
super(message);
|
|
33310
|
-
this.name = "CliError";
|
|
33311
|
-
}
|
|
33312
|
-
};
|
|
33313
|
-
function fail(message) {
|
|
33314
|
-
throw new CliError(message);
|
|
33315
|
-
}
|
|
33316
|
-
function writeFileAtomic(filePath, bytes) {
|
|
33317
|
-
const dir = path6.dirname(path6.resolve(filePath));
|
|
33318
|
-
const tmp = path6.join(dir, `.${path6.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
|
|
33319
|
-
fs5.writeFileSync(tmp, bytes);
|
|
33320
|
-
try {
|
|
33321
|
-
fs5.renameSync(tmp, filePath);
|
|
33322
|
-
} catch (error) {
|
|
33323
|
-
try {
|
|
33324
|
-
fs5.unlinkSync(tmp);
|
|
33325
|
-
} catch {
|
|
33326
|
-
}
|
|
33327
|
-
throw error;
|
|
33328
|
-
}
|
|
33329
|
-
console.error(`Wrote ${filePath}`);
|
|
33330
|
-
}
|
|
34384
|
+
import fs7 from "node:fs";
|
|
33331
34385
|
|
|
33332
34386
|
// ../xlsx/node_modules/fast-xml-parser/src/util.js
|
|
33333
34387
|
var nameStartChar = ":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
|
|
@@ -36104,16 +37158,16 @@ var MatcherView = class {
|
|
|
36104
37158
|
* @returns {string|undefined}
|
|
36105
37159
|
*/
|
|
36106
37160
|
getCurrentTag() {
|
|
36107
|
-
const
|
|
36108
|
-
return
|
|
37161
|
+
const path9 = this._matcher.path;
|
|
37162
|
+
return path9.length > 0 ? path9[path9.length - 1].tag : void 0;
|
|
36109
37163
|
}
|
|
36110
37164
|
/**
|
|
36111
37165
|
* Get current namespace.
|
|
36112
37166
|
* @returns {string|undefined}
|
|
36113
37167
|
*/
|
|
36114
37168
|
getCurrentNamespace() {
|
|
36115
|
-
const
|
|
36116
|
-
return
|
|
37169
|
+
const path9 = this._matcher.path;
|
|
37170
|
+
return path9.length > 0 ? path9[path9.length - 1].namespace : void 0;
|
|
36117
37171
|
}
|
|
36118
37172
|
/**
|
|
36119
37173
|
* Get current node's attribute value.
|
|
@@ -36121,9 +37175,9 @@ var MatcherView = class {
|
|
|
36121
37175
|
* @returns {*}
|
|
36122
37176
|
*/
|
|
36123
37177
|
getAttrValue(attrName) {
|
|
36124
|
-
const
|
|
36125
|
-
if (
|
|
36126
|
-
return
|
|
37178
|
+
const path9 = this._matcher.path;
|
|
37179
|
+
if (path9.length === 0) return void 0;
|
|
37180
|
+
return path9[path9.length - 1].values?.[attrName];
|
|
36127
37181
|
}
|
|
36128
37182
|
/**
|
|
36129
37183
|
* Check if current node has an attribute.
|
|
@@ -36131,9 +37185,9 @@ var MatcherView = class {
|
|
|
36131
37185
|
* @returns {boolean}
|
|
36132
37186
|
*/
|
|
36133
37187
|
hasAttr(attrName) {
|
|
36134
|
-
const
|
|
36135
|
-
if (
|
|
36136
|
-
const current =
|
|
37188
|
+
const path9 = this._matcher.path;
|
|
37189
|
+
if (path9.length === 0) return false;
|
|
37190
|
+
const current = path9[path9.length - 1];
|
|
36137
37191
|
return current.values !== void 0 && attrName in current.values;
|
|
36138
37192
|
}
|
|
36139
37193
|
/**
|
|
@@ -36141,18 +37195,18 @@ var MatcherView = class {
|
|
|
36141
37195
|
* @returns {number}
|
|
36142
37196
|
*/
|
|
36143
37197
|
getPosition() {
|
|
36144
|
-
const
|
|
36145
|
-
if (
|
|
36146
|
-
return
|
|
37198
|
+
const path9 = this._matcher.path;
|
|
37199
|
+
if (path9.length === 0) return -1;
|
|
37200
|
+
return path9[path9.length - 1].position ?? 0;
|
|
36147
37201
|
}
|
|
36148
37202
|
/**
|
|
36149
37203
|
* Get current node's repeat counter (occurrence count of this tag name).
|
|
36150
37204
|
* @returns {number}
|
|
36151
37205
|
*/
|
|
36152
37206
|
getCounter() {
|
|
36153
|
-
const
|
|
36154
|
-
if (
|
|
36155
|
-
return
|
|
37207
|
+
const path9 = this._matcher.path;
|
|
37208
|
+
if (path9.length === 0) return -1;
|
|
37209
|
+
return path9[path9.length - 1].counter ?? 0;
|
|
36156
37210
|
}
|
|
36157
37211
|
/**
|
|
36158
37212
|
* Get current node's sibling index (alias for getPosition).
|
|
@@ -41608,10 +42662,10 @@ function resolveRelativePath(basePath, relativePath) {
|
|
|
41608
42662
|
}
|
|
41609
42663
|
return resolved.join("/");
|
|
41610
42664
|
}
|
|
41611
|
-
function findZipEntry(zipEntries,
|
|
41612
|
-
if (zipEntries[
|
|
41613
|
-
if (zipEntries[`xl/${
|
|
41614
|
-
const noSlash =
|
|
42665
|
+
function findZipEntry(zipEntries, path9) {
|
|
42666
|
+
if (zipEntries[path9]) return zipEntries[path9];
|
|
42667
|
+
if (zipEntries[`xl/${path9}`]) return zipEntries[`xl/${path9}`];
|
|
42668
|
+
const noSlash = path9.replace(/^\//, "");
|
|
41615
42669
|
if (zipEntries[noSlash]) return zipEntries[noSlash];
|
|
41616
42670
|
return void 0;
|
|
41617
42671
|
}
|
|
@@ -43334,9 +44388,9 @@ function parseExcelFromZip(zip, options) {
|
|
|
43334
44388
|
}
|
|
43335
44389
|
return result;
|
|
43336
44390
|
}
|
|
43337
|
-
function findEntry(zip,
|
|
43338
|
-
if (zip[
|
|
43339
|
-
const lower =
|
|
44391
|
+
function findEntry(zip, path9) {
|
|
44392
|
+
if (zip[path9]) return zip[path9];
|
|
44393
|
+
const lower = path9.toLowerCase();
|
|
43340
44394
|
for (const key of Object.keys(zip)) {
|
|
43341
44395
|
if (key.toLowerCase() === lower) return zip[key];
|
|
43342
44396
|
}
|
|
@@ -43947,12 +45001,12 @@ function extractPivotRoundTripInfo(originalZip) {
|
|
|
43947
45001
|
if (paths.length > 0) pivotTablesBySheetIndex.set(i2, paths);
|
|
43948
45002
|
}
|
|
43949
45003
|
const pivotXmlPaths = [];
|
|
43950
|
-
for (const
|
|
43951
|
-
if (
|
|
43952
|
-
pivotXmlPaths.push(
|
|
45004
|
+
for (const path9 of Object.keys(originalZip)) {
|
|
45005
|
+
if (path9.startsWith("xl/pivotTables/") && path9.endsWith(".xml")) {
|
|
45006
|
+
pivotXmlPaths.push(path9);
|
|
43953
45007
|
}
|
|
43954
|
-
if (
|
|
43955
|
-
pivotXmlPaths.push(
|
|
45008
|
+
if (path9.startsWith("xl/pivotCache/") && path9.endsWith(".xml")) {
|
|
45009
|
+
pivotXmlPaths.push(path9);
|
|
43956
45010
|
}
|
|
43957
45011
|
}
|
|
43958
45012
|
return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths };
|
|
@@ -43960,15 +45014,15 @@ function extractPivotRoundTripInfo(originalZip) {
|
|
|
43960
45014
|
function decode(bytes) {
|
|
43961
45015
|
return new TextDecoder().decode(bytes);
|
|
43962
45016
|
}
|
|
43963
|
-
function pivotContentTypeFor(
|
|
43964
|
-
if (
|
|
43965
|
-
return `<Override PartName="/${
|
|
45017
|
+
function pivotContentTypeFor(path9) {
|
|
45018
|
+
if (path9.startsWith("xl/pivotTables/") && path9.endsWith(".xml")) {
|
|
45019
|
+
return `<Override PartName="/${path9}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
|
|
43966
45020
|
}
|
|
43967
|
-
if (
|
|
43968
|
-
return `<Override PartName="/${
|
|
45021
|
+
if (path9.includes("/pivotCacheDefinition") && path9.endsWith(".xml")) {
|
|
45022
|
+
return `<Override PartName="/${path9}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
|
|
43969
45023
|
}
|
|
43970
|
-
if (
|
|
43971
|
-
return `<Override PartName="/${
|
|
45024
|
+
if (path9.includes("/pivotCacheRecords") && path9.endsWith(".xml")) {
|
|
45025
|
+
return `<Override PartName="/${path9}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
|
|
43972
45026
|
}
|
|
43973
45027
|
return void 0;
|
|
43974
45028
|
}
|
|
@@ -44040,13 +45094,13 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
44040
45094
|
regeneratedPaths.add(`xl/worksheets/sheet${i2 + 1}.xml`);
|
|
44041
45095
|
regeneratedPaths.add(`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`);
|
|
44042
45096
|
}
|
|
44043
|
-
for (const
|
|
44044
|
-
if (
|
|
44045
|
-
regeneratedPaths.add(
|
|
45097
|
+
for (const path9 of Object.keys(originalZip)) {
|
|
45098
|
+
if (path9.startsWith("xl/drawings/") || path9.startsWith("xl/charts/") || path9.startsWith("xl/tables/") || path9.startsWith("xl/media/")) {
|
|
45099
|
+
regeneratedPaths.add(path9);
|
|
44046
45100
|
}
|
|
44047
45101
|
}
|
|
44048
|
-
for (const [
|
|
44049
|
-
if (!regeneratedPaths.has(
|
|
45102
|
+
for (const [path9, data] of Object.entries(originalZip)) {
|
|
45103
|
+
if (!regeneratedPaths.has(path9)) entries[path9] = data;
|
|
44050
45104
|
}
|
|
44051
45105
|
}
|
|
44052
45106
|
const sharedStrings = buildSharedStrings(workbook);
|
|
@@ -44061,8 +45115,8 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
44061
45115
|
buildWorkbookRels(workbook, pivotInfo)
|
|
44062
45116
|
);
|
|
44063
45117
|
const extraContentTypes = [];
|
|
44064
|
-
for (const
|
|
44065
|
-
const ct = pivotContentTypeFor(
|
|
45118
|
+
for (const path9 of pivotInfo.pivotXmlPaths) {
|
|
45119
|
+
const ct = pivotContentTypeFor(path9);
|
|
44066
45120
|
if (ct) extraContentTypes.push(ct);
|
|
44067
45121
|
}
|
|
44068
45122
|
let globalChartIndex = 1;
|
|
@@ -45823,14 +46877,14 @@ var DependencyGraph = class {
|
|
|
45823
46877
|
stack.push({ cell: p, path: [cell, p] });
|
|
45824
46878
|
}
|
|
45825
46879
|
while (stack.length > 0) {
|
|
45826
|
-
const { cell: current, path:
|
|
45827
|
-
if (current === cell) return
|
|
46880
|
+
const { cell: current, path: path9 } = stack.pop();
|
|
46881
|
+
if (current === cell) return path9;
|
|
45828
46882
|
if (visited.has(current)) continue;
|
|
45829
46883
|
visited.add(current);
|
|
45830
46884
|
const nextPrec = this.precedents.get(current);
|
|
45831
46885
|
if (!nextPrec) continue;
|
|
45832
46886
|
for (const p of nextPrec) {
|
|
45833
|
-
stack.push({ cell: p, path: [...
|
|
46887
|
+
stack.push({ cell: p, path: [...path9, p] });
|
|
45834
46888
|
}
|
|
45835
46889
|
}
|
|
45836
46890
|
return null;
|
|
@@ -46821,8 +47875,8 @@ function adjustMergedCellsForColDelete(sheet, atCol, count) {
|
|
|
46821
47875
|
|
|
46822
47876
|
// src/xlsx.ts
|
|
46823
47877
|
function loadFile(filePath) {
|
|
46824
|
-
if (!
|
|
46825
|
-
const buffer =
|
|
47878
|
+
if (!fs7.existsSync(filePath)) fail(`File not found: ${filePath}`);
|
|
47879
|
+
const buffer = fs7.readFileSync(filePath);
|
|
46826
47880
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
46827
47881
|
const originalZip = unzipXlsx(arrayBuffer);
|
|
46828
47882
|
const parsed = parseExcelBuffer(arrayBuffer);
|
|
@@ -46872,7 +47926,7 @@ function lazyEngine(workbook) {
|
|
|
46872
47926
|
};
|
|
46873
47927
|
}
|
|
46874
47928
|
function readToJson(filePath) {
|
|
46875
|
-
const buffer =
|
|
47929
|
+
const buffer = fs7.readFileSync(filePath);
|
|
46876
47930
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
46877
47931
|
const parsed = parseExcelBuffer(arrayBuffer);
|
|
46878
47932
|
return {
|
|
@@ -47262,7 +48316,7 @@ async function runXlsxCommand(subcommand, toolArgs, restArgs) {
|
|
|
47262
48316
|
}
|
|
47263
48317
|
|
|
47264
48318
|
// src/docx.ts
|
|
47265
|
-
import
|
|
48319
|
+
import fs8 from "node:fs";
|
|
47266
48320
|
|
|
47267
48321
|
// ../docx/src/parse/parser.ts
|
|
47268
48322
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
@@ -49033,11 +50087,11 @@ async function parseDocx(buffer) {
|
|
|
49033
50087
|
const zip = await import_jszip.default.loadAsync(buffer);
|
|
49034
50088
|
const parts = /* @__PURE__ */ new Map();
|
|
49035
50089
|
const filePromises = [];
|
|
49036
|
-
zip.forEach((
|
|
50090
|
+
zip.forEach((path9, file) => {
|
|
49037
50091
|
if (file.dir) return;
|
|
49038
50092
|
filePromises.push(
|
|
49039
50093
|
file.async("uint8array").then((bytes) => {
|
|
49040
|
-
parts.set(
|
|
50094
|
+
parts.set(path9, bytes);
|
|
49041
50095
|
})
|
|
49042
50096
|
);
|
|
49043
50097
|
});
|
|
@@ -49266,9 +50320,9 @@ var DEFAULT_PARTS = [
|
|
|
49266
50320
|
["word/theme/theme1.xml", () => encoder.encode(THEME_XML)]
|
|
49267
50321
|
];
|
|
49268
50322
|
function fillDefaultParts(parts) {
|
|
49269
|
-
for (const [
|
|
49270
|
-
if (!parts.has(
|
|
49271
|
-
parts.set(
|
|
50323
|
+
for (const [path9, makeBytes] of DEFAULT_PARTS) {
|
|
50324
|
+
if (!parts.has(path9)) {
|
|
50325
|
+
parts.set(path9, makeBytes());
|
|
49272
50326
|
}
|
|
49273
50327
|
}
|
|
49274
50328
|
return parts;
|
|
@@ -49278,9 +50332,9 @@ function fillDefaultParts(parts) {
|
|
|
49278
50332
|
async function serializeDocx(doc) {
|
|
49279
50333
|
const zip = new import_jszip2.default();
|
|
49280
50334
|
const parts = fillDefaultParts(new Map(doc.parts));
|
|
49281
|
-
for (const [
|
|
49282
|
-
if (
|
|
49283
|
-
zip.file(
|
|
50335
|
+
for (const [path9, bytes] of parts) {
|
|
50336
|
+
if (path9 === "word/document.xml") continue;
|
|
50337
|
+
zip.file(path9, bytes);
|
|
49284
50338
|
}
|
|
49285
50339
|
const documentXml = serializeDocumentXml(doc);
|
|
49286
50340
|
zip.file("word/document.xml", documentXml);
|
|
@@ -49366,8 +50420,8 @@ var DEFAULT_DOC_ATTRS = {
|
|
|
49366
50420
|
"@_xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
|
49367
50421
|
};
|
|
49368
50422
|
async function loadFile2(filePath) {
|
|
49369
|
-
if (!
|
|
49370
|
-
const bytes =
|
|
50423
|
+
if (!fs8.existsSync(filePath)) fail(`File not found: ${filePath}`);
|
|
50424
|
+
const bytes = fs8.readFileSync(filePath);
|
|
49371
50425
|
return parseDocx(new Uint8Array(bytes));
|
|
49372
50426
|
}
|
|
49373
50427
|
async function writeDoc(filePath, doc) {
|
|
@@ -49659,7 +50713,7 @@ async function runDocxCommand(subcommand, toolArgs, restArgs) {
|
|
|
49659
50713
|
import { spawn as spawn3 } from "node:child_process";
|
|
49660
50714
|
import { createServer } from "node:http";
|
|
49661
50715
|
import { readFileSync as readFileSync2, writeFileSync, existsSync, mkdtempSync, rmSync, readdirSync } from "node:fs";
|
|
49662
|
-
import { tmpdir as
|
|
50716
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
49663
50717
|
import { join, dirname, resolve, extname, basename } from "node:path";
|
|
49664
50718
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
49665
50719
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
@@ -49752,7 +50806,7 @@ async function runPreviewCommand(filePath, flags) {
|
|
|
49752
50806
|
});
|
|
49753
50807
|
await new Promise((r) => server.listen(0, "127.0.0.1", () => r()));
|
|
49754
50808
|
const httpPort = server.address().port;
|
|
49755
|
-
const udd = mkdtempSync(join(
|
|
50809
|
+
const udd = mkdtempSync(join(tmpdir3(), "lotics-render-"));
|
|
49756
50810
|
const child = spawn3(chrome, [
|
|
49757
50811
|
"--headless=new",
|
|
49758
50812
|
"--disable-gpu",
|
|
@@ -49893,6 +50947,7 @@ COMMANDS
|
|
|
49893
50947
|
lotics workspace select <id> Switch to a different workspace
|
|
49894
50948
|
lotics workspace create <name> Create a new workspace (admin only)
|
|
49895
50949
|
lotics workspace delete <id> --yes Delete a workspace (admin only; soft delete, recoverable)
|
|
50950
|
+
lotics workspace doctor Report dangling schema references (admin only)
|
|
49896
50951
|
lotics tools List all available tools
|
|
49897
50952
|
lotics tools <name> Show tool description and input schema
|
|
49898
50953
|
lotics run <tool> '<json>' Execute a tool
|
|
@@ -49925,6 +50980,37 @@ COMMANDS
|
|
|
49925
50980
|
lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address
|
|
49926
50981
|
lotics app rename "<new name>" Rename the app's display name (launcher title)
|
|
49927
50982
|
lotics app dev [path] Run the app locally with HMR (RPC forwarded to prod)
|
|
50983
|
+
lotics package new <name> [path] Scaffold a package project (contract + app source)
|
|
50984
|
+
lotics package build [path] Build the publishable bundle (source + dist)
|
|
50985
|
+
lotics package publish [path] Publish a new immutable package version
|
|
50986
|
+
lotics package dev [path] Sync the package into a dev workspace + run the app
|
|
50987
|
+
dev server (--workspace <dev_ws> selects it)
|
|
50988
|
+
lotics package sync [path] Re-sync (additive migrate + materialize) into a dev ws
|
|
50989
|
+
lotics package reset [path] DEV-ONLY: drop scaffolded tables + re-scaffold clean
|
|
50990
|
+
lotics package install <package> [--version N]
|
|
50991
|
+
Install an app package into this workspace
|
|
50992
|
+
(scaffolds the data model + deploys + materializes)
|
|
50993
|
+
lotics package upgrade <app_id> [--version N] [--resolve <key>=recreate|revert|keep|<id> ...]
|
|
50994
|
+
Preview-then-apply a package upgrade; refuses while
|
|
50995
|
+
any drift/modified finding lacks a --resolve, and
|
|
50996
|
+
hard-stops on breaking contract changes
|
|
50997
|
+
lotics package doctor [app_id] Installation health: version pin vs latest, binding
|
|
50998
|
+
drift, locally modified core (exit 1 on findings)
|
|
50999
|
+
lotics package rebind-role <app_id> <alias> <grp_id>
|
|
51000
|
+
Re-point a package role at a different group
|
|
51001
|
+
(re-materializes at the pinned version)
|
|
51002
|
+
lotics package eject <app_id> Sever an installation's package link
|
|
51003
|
+
(re-deploys the pinned source as a bespoke app)
|
|
51004
|
+
lotics package extract <app_id> [path] Promote a bespoke app to a draft package
|
|
51005
|
+
project (contract + binding + templates); always
|
|
51006
|
+
writes the draft, exits 1 on error findings
|
|
51007
|
+
lotics package adopt <app_id> [path] Bind the published package project onto the
|
|
51008
|
+
origin app (reads .lotics/adopt_binding.json;
|
|
51009
|
+
--version N pins a specific version)
|
|
51010
|
+
lotics package fleet-upgrade <package_id> [--version N]
|
|
51011
|
+
Upgrade EVERY installation of the package across
|
|
51012
|
+
your org: applies where the preview is clean,
|
|
51013
|
+
skips + reports findings (exit 1 unless all current)
|
|
49928
51014
|
lotics ui link <component> [--ui-src <path>] [--remove]
|
|
49929
51015
|
Dev-link @lotics/ui to packages/ui/src (Vite alias
|
|
49930
51016
|
+ tsc paths) for live HMR + typecheck. Monorepo apps
|
|
@@ -49953,6 +51039,8 @@ FLAGS
|
|
|
49953
51039
|
is_current_member / row-scoping resolve to them (also
|
|
49954
51040
|
LOTICS_VIEW_AS env; admin key only; writes stay yours)
|
|
49955
51041
|
--local Pin the current directory (lotics org use / auth api-key)
|
|
51042
|
+
--dev (lotics workspace create) Mark a throwaway app-package dev
|
|
51043
|
+
workspace \u2014 required for "lotics package reset"
|
|
49956
51044
|
--all (lotics auth logout) Remove every saved credential
|
|
49957
51045
|
--version Show version
|
|
49958
51046
|
|
|
@@ -50037,8 +51125,8 @@ function prompt(question) {
|
|
|
50037
51125
|
});
|
|
50038
51126
|
});
|
|
50039
51127
|
}
|
|
50040
|
-
async function publicPost(
|
|
50041
|
-
const response = await fetch(`${API_BASE_URL}${
|
|
51128
|
+
async function publicPost(path9, body) {
|
|
51129
|
+
const response = await fetch(`${API_BASE_URL}${path9}`, {
|
|
50042
51130
|
method: "POST",
|
|
50043
51131
|
headers: { "Content-Type": "application/json" },
|
|
50044
51132
|
body: JSON.stringify(body)
|
|
@@ -50184,13 +51272,13 @@ async function resolveWorkspace(client, ctx) {
|
|
|
50184
51272
|
function resolveUploadPaths(rawPaths) {
|
|
50185
51273
|
const result = [];
|
|
50186
51274
|
for (const p of rawPaths) {
|
|
50187
|
-
const resolved =
|
|
50188
|
-
const stat =
|
|
51275
|
+
const resolved = path8.resolve(p);
|
|
51276
|
+
const stat = fs9.statSync(resolved);
|
|
50189
51277
|
if (stat.isDirectory()) {
|
|
50190
|
-
const entries =
|
|
51278
|
+
const entries = fs9.readdirSync(resolved, { withFileTypes: true });
|
|
50191
51279
|
for (const entry of entries) {
|
|
50192
51280
|
if (entry.isFile()) {
|
|
50193
|
-
result.push(
|
|
51281
|
+
result.push(path8.join(resolved, entry.name));
|
|
50194
51282
|
}
|
|
50195
51283
|
}
|
|
50196
51284
|
} else {
|
|
@@ -50325,6 +51413,19 @@ async function main() {
|
|
|
50325
51413
|
console.error("Usage: lotics ui link <component> [--ui-src <abs path>] [--remove]");
|
|
50326
51414
|
process.exit(1);
|
|
50327
51415
|
}
|
|
51416
|
+
if (command === "package" && subcommand === "new") {
|
|
51417
|
+
const name = toolArgs;
|
|
51418
|
+
if (!name) {
|
|
51419
|
+
console.error("Usage: lotics package new <name> [path]");
|
|
51420
|
+
process.exit(1);
|
|
51421
|
+
}
|
|
51422
|
+
await packageNew({ name, targetPath: restArgs[0] });
|
|
51423
|
+
return;
|
|
51424
|
+
}
|
|
51425
|
+
if (command === "package" && subcommand === "build") {
|
|
51426
|
+
await packageBuild({ projectDir: toolArgs });
|
|
51427
|
+
return;
|
|
51428
|
+
}
|
|
50328
51429
|
if (command === "app" && subcommand === "workflow" && toolArgs === "check") {
|
|
50329
51430
|
await appWorkflowCheck({ alias: restArgs[0] });
|
|
50330
51431
|
return;
|
|
@@ -50399,7 +51500,7 @@ async function main() {
|
|
|
50399
51500
|
}
|
|
50400
51501
|
return;
|
|
50401
51502
|
}
|
|
50402
|
-
if (command !== "tools" && command !== "upload" && command !== "run" && command !== "download" && command !== "workspace" && command !== "app") {
|
|
51503
|
+
if (command !== "tools" && command !== "upload" && command !== "run" && command !== "download" && command !== "workspace" && command !== "app" && command !== "package") {
|
|
50403
51504
|
console.error(`Unknown command: ${command}`);
|
|
50404
51505
|
console.error('Run "lotics --help" for usage.');
|
|
50405
51506
|
process.exit(1);
|
|
@@ -50421,6 +51522,24 @@ async function main() {
|
|
|
50421
51522
|
console.error(" lotics app dev [path] Run the app locally with HMR + RPC forwarding");
|
|
50422
51523
|
process.exit(1);
|
|
50423
51524
|
}
|
|
51525
|
+
if (command === "package" && !subcommand) {
|
|
51526
|
+
console.error("Usage:");
|
|
51527
|
+
console.error(" lotics package new <name> [path] Scaffold a package project (contract + app source)");
|
|
51528
|
+
console.error(" lotics package build [path] Build the publishable bundle (source + dist)");
|
|
51529
|
+
console.error(" lotics package publish [path] [-m <changelog>] Publish a new immutable package version");
|
|
51530
|
+
console.error(" lotics package dev [path] [--workspace <ws>] Sync into a dev workspace + run the app dev server");
|
|
51531
|
+
console.error(" lotics package sync [path] [--workspace <ws>] Re-sync (additive migrate + materialize) into a dev workspace");
|
|
51532
|
+
console.error(" lotics package reset [path] [--workspace <ws>] DEV-ONLY: drop scaffolded tables + re-scaffold clean");
|
|
51533
|
+
console.error(" lotics package install <package> [--version N] Install a package into this workspace");
|
|
51534
|
+
console.error(" lotics package upgrade <app_id> [--version N] [--resolve ns.alias=recreate|<id>] Preview + apply an upgrade");
|
|
51535
|
+
console.error(" lotics package doctor [app_id] Health: version pin vs latest + binding drift");
|
|
51536
|
+
console.error(" lotics package rebind-role <app_id> <alias> <grp_id> Re-point a package role at another group");
|
|
51537
|
+
console.error(" lotics package eject <app_id> Sever an installation's package link");
|
|
51538
|
+
console.error(" lotics package extract <app_id> [path] Promote a bespoke app to a draft package project");
|
|
51539
|
+
console.error(" lotics package adopt <app_id> [path] Bind the published project onto the origin app");
|
|
51540
|
+
console.error(" lotics package fleet-upgrade <package_id> [--version N] Upgrade every org installation (clean ones apply; findings skip)");
|
|
51541
|
+
process.exit(1);
|
|
51542
|
+
}
|
|
50424
51543
|
if (command === "run" && !subcommand) {
|
|
50425
51544
|
console.error(
|
|
50426
51545
|
"Usage: lotics run <tool> '<json_args>'\n lotics run <tool> @args.json (read args from a file \u2014 for large payloads)\n cat args.json | lotics run <tool> (read args from stdin)"
|
|
@@ -50447,6 +51566,25 @@ async function main() {
|
|
|
50447
51566
|
}
|
|
50448
51567
|
const { client, ctx } = requireClient(flags);
|
|
50449
51568
|
if (command === "workspace") {
|
|
51569
|
+
if (subcommand === "doctor") {
|
|
51570
|
+
await resolveWorkspace(client, ctx);
|
|
51571
|
+
const dangling = await client.getWorkspaceDanglingReferences();
|
|
51572
|
+
if (dangling.length === 0) {
|
|
51573
|
+
console.error("Workspace references: healthy \u2014 every referenced schema id resolves.");
|
|
51574
|
+
return;
|
|
51575
|
+
}
|
|
51576
|
+
console.error(`Dangling schema references (${dangling.length}):`);
|
|
51577
|
+
for (const d of dangling) {
|
|
51578
|
+
console.error(
|
|
51579
|
+
` - ${d.referent.kind} "${d.referent.name}" (${d.referent.id}) \u2192 ${d.namespace} ${d.id} (missing)`
|
|
51580
|
+
);
|
|
51581
|
+
}
|
|
51582
|
+
console.error(
|
|
51583
|
+
"Each referent points at schema that no longer exists \u2014 edit or archive it, or recreate the missing schema."
|
|
51584
|
+
);
|
|
51585
|
+
process.exitCode = 1;
|
|
51586
|
+
return;
|
|
51587
|
+
}
|
|
50450
51588
|
const workspaces = await client.listWorkspaces();
|
|
50451
51589
|
const currentWorkspaceId = ctx.workspaceId;
|
|
50452
51590
|
if (subcommand === "select") {
|
|
@@ -50475,11 +51613,11 @@ Available workspaces:`);
|
|
|
50475
51613
|
if (subcommand === "create") {
|
|
50476
51614
|
const name = toolArgs;
|
|
50477
51615
|
if (!name) {
|
|
50478
|
-
console.error("Usage: lotics workspace create <name> [--timezone <tz>]");
|
|
51616
|
+
console.error("Usage: lotics workspace create <name> [--timezone <tz>] [--dev]");
|
|
50479
51617
|
process.exit(1);
|
|
50480
51618
|
}
|
|
50481
51619
|
const timezone = flags.timezone;
|
|
50482
|
-
const created = await client.createWorkspace({ name, timezone });
|
|
51620
|
+
const created = await client.createWorkspace({ name, timezone, is_dev: flags.dev || void 0 });
|
|
50483
51621
|
setSelectedWorkspace(created.id);
|
|
50484
51622
|
client.setWorkspaceId(created.id);
|
|
50485
51623
|
if (flags.json) {
|
|
@@ -50541,6 +51679,150 @@ Available workspaces:`);
|
|
|
50541
51679
|
return;
|
|
50542
51680
|
}
|
|
50543
51681
|
await resolveWorkspace(client, ctx);
|
|
51682
|
+
if (command === "package") {
|
|
51683
|
+
if (subcommand === "install") {
|
|
51684
|
+
const packageId = toolArgs;
|
|
51685
|
+
if (!packageId) {
|
|
51686
|
+
console.error("Usage: lotics package install <package> [--version N]");
|
|
51687
|
+
process.exit(1);
|
|
51688
|
+
}
|
|
51689
|
+
let version;
|
|
51690
|
+
if (flags.packageVersion !== void 0) {
|
|
51691
|
+
version = Number(flags.packageVersion);
|
|
51692
|
+
if (!Number.isInteger(version) || version <= 0) {
|
|
51693
|
+
console.error(`Invalid --version "${flags.packageVersion}" \u2014 expected a positive integer.`);
|
|
51694
|
+
process.exit(1);
|
|
51695
|
+
}
|
|
51696
|
+
}
|
|
51697
|
+
await packageInstall(client, { package_id: packageId, version });
|
|
51698
|
+
return;
|
|
51699
|
+
}
|
|
51700
|
+
if (subcommand === "eject") {
|
|
51701
|
+
const appId = toolArgs;
|
|
51702
|
+
if (!appId) {
|
|
51703
|
+
console.error("Usage: lotics package eject <app_id>");
|
|
51704
|
+
process.exit(1);
|
|
51705
|
+
}
|
|
51706
|
+
await packageEject(client, { app_id: appId });
|
|
51707
|
+
return;
|
|
51708
|
+
}
|
|
51709
|
+
if (subcommand === "extract") {
|
|
51710
|
+
const appId = toolArgs;
|
|
51711
|
+
if (!appId) {
|
|
51712
|
+
console.error("Usage: lotics package extract <app_id> [path]");
|
|
51713
|
+
console.error("Promotes a bespoke app to a draft package project (contract + binding + templates).");
|
|
51714
|
+
process.exit(1);
|
|
51715
|
+
}
|
|
51716
|
+
await packageExtract(client, { app_id: appId, targetPath: restArgs[0] });
|
|
51717
|
+
return;
|
|
51718
|
+
}
|
|
51719
|
+
if (subcommand === "adopt") {
|
|
51720
|
+
const appId = toolArgs;
|
|
51721
|
+
if (!appId) {
|
|
51722
|
+
console.error("Usage: lotics package adopt <app_id> [path]");
|
|
51723
|
+
console.error("Binds the published package project (this dir, or [path]) onto the origin app.");
|
|
51724
|
+
process.exit(1);
|
|
51725
|
+
}
|
|
51726
|
+
let version;
|
|
51727
|
+
if (flags.packageVersion !== void 0) {
|
|
51728
|
+
version = Number(flags.packageVersion);
|
|
51729
|
+
if (!Number.isInteger(version) || version <= 0) {
|
|
51730
|
+
console.error(`Invalid --version "${flags.packageVersion}" \u2014 expected a positive integer.`);
|
|
51731
|
+
process.exit(1);
|
|
51732
|
+
}
|
|
51733
|
+
}
|
|
51734
|
+
await packageAdopt(client, { app_id: appId, version, projectDir: restArgs[0] });
|
|
51735
|
+
return;
|
|
51736
|
+
}
|
|
51737
|
+
if (subcommand === "fleet-upgrade") {
|
|
51738
|
+
const packageId = toolArgs;
|
|
51739
|
+
if (!packageId) {
|
|
51740
|
+
console.error("Usage: lotics package fleet-upgrade <package_id> [--version N]");
|
|
51741
|
+
process.exit(1);
|
|
51742
|
+
}
|
|
51743
|
+
let version;
|
|
51744
|
+
if (flags.packageVersion !== void 0) {
|
|
51745
|
+
version = Number(flags.packageVersion);
|
|
51746
|
+
if (!Number.isInteger(version) || version <= 0) {
|
|
51747
|
+
console.error(`Invalid --version "${flags.packageVersion}" \u2014 expected a positive integer.`);
|
|
51748
|
+
process.exit(1);
|
|
51749
|
+
}
|
|
51750
|
+
}
|
|
51751
|
+
await packageFleetUpgrade(client, { package_id: packageId, version });
|
|
51752
|
+
return;
|
|
51753
|
+
}
|
|
51754
|
+
if (subcommand === "doctor") {
|
|
51755
|
+
await packageDoctor(client, { app_id: toolArgs });
|
|
51756
|
+
return;
|
|
51757
|
+
}
|
|
51758
|
+
if (subcommand === "rebind-role") {
|
|
51759
|
+
const appId = toolArgs;
|
|
51760
|
+
const [roleAlias, groupId] = restArgs;
|
|
51761
|
+
if (!appId || !roleAlias || !groupId) {
|
|
51762
|
+
console.error("Usage: lotics package rebind-role <app_id> <role_alias> <grp_id>");
|
|
51763
|
+
process.exit(1);
|
|
51764
|
+
}
|
|
51765
|
+
const result = await client.rebindAppPackageRole(appId, {
|
|
51766
|
+
role_alias: roleAlias,
|
|
51767
|
+
group_id: groupId
|
|
51768
|
+
});
|
|
51769
|
+
console.error(
|
|
51770
|
+
`Rebound role "${result.role_alias}" \u2192 ${result.group_id}` + (result.previous_group_id ? ` (was ${result.previous_group_id})` : "") + ". Package workflows/agents were re-materialized against the new group."
|
|
51771
|
+
);
|
|
51772
|
+
return;
|
|
51773
|
+
}
|
|
51774
|
+
if (subcommand === "upgrade") {
|
|
51775
|
+
const appId = toolArgs;
|
|
51776
|
+
if (!appId) {
|
|
51777
|
+
console.error(
|
|
51778
|
+
"Usage: lotics package upgrade <app_id> [--version N] [--resolve <namespace.alias>=recreate|<id> ...]"
|
|
51779
|
+
);
|
|
51780
|
+
process.exit(1);
|
|
51781
|
+
}
|
|
51782
|
+
let version;
|
|
51783
|
+
if (flags.packageVersion !== void 0) {
|
|
51784
|
+
version = Number(flags.packageVersion);
|
|
51785
|
+
if (!Number.isInteger(version) || version <= 0) {
|
|
51786
|
+
console.error(`Invalid --version "${flags.packageVersion}" \u2014 expected a positive integer.`);
|
|
51787
|
+
process.exit(1);
|
|
51788
|
+
}
|
|
51789
|
+
}
|
|
51790
|
+
await packageUpgrade(client, {
|
|
51791
|
+
app_id: appId,
|
|
51792
|
+
version,
|
|
51793
|
+
resolutions: parseResolveFlags(flags.resolve)
|
|
51794
|
+
});
|
|
51795
|
+
return;
|
|
51796
|
+
}
|
|
51797
|
+
if (subcommand === "publish") {
|
|
51798
|
+
await packagePublish(client, { projectDir: toolArgs, changelog: flags.message });
|
|
51799
|
+
return;
|
|
51800
|
+
}
|
|
51801
|
+
if (subcommand === "sync") {
|
|
51802
|
+
await packageSync(client, { projectDir: toolArgs });
|
|
51803
|
+
return;
|
|
51804
|
+
}
|
|
51805
|
+
if (subcommand === "reset") {
|
|
51806
|
+
await packageReset(client, { projectDir: toolArgs });
|
|
51807
|
+
return;
|
|
51808
|
+
}
|
|
51809
|
+
if (subcommand === "dev") {
|
|
51810
|
+
const projectDir = toolArgs;
|
|
51811
|
+
let port;
|
|
51812
|
+
let vitePort;
|
|
51813
|
+
for (const a of restArgs) {
|
|
51814
|
+
const portMatch = /^--port=(\d+)$/.exec(a);
|
|
51815
|
+
const vitePortMatch = /^--vite-port=(\d+)$/.exec(a);
|
|
51816
|
+
if (portMatch) port = Number(portMatch[1]);
|
|
51817
|
+
else if (vitePortMatch) vitePort = Number(vitePortMatch[1]);
|
|
51818
|
+
}
|
|
51819
|
+
await packageDev(client, { projectDir, port, vitePort });
|
|
51820
|
+
return;
|
|
51821
|
+
}
|
|
51822
|
+
console.error(`Unknown package subcommand: ${subcommand}`);
|
|
51823
|
+
console.error("Run 'lotics package' for usage.");
|
|
51824
|
+
process.exit(1);
|
|
51825
|
+
}
|
|
50544
51826
|
if (command === "app") {
|
|
50545
51827
|
if (subcommand === "create") {
|
|
50546
51828
|
const name = toolArgs;
|
|
@@ -50620,7 +51902,7 @@ Available workspaces:`);
|
|
|
50620
51902
|
const ingested = await ingestJsonArgs({
|
|
50621
51903
|
rawArg: restArgs[1],
|
|
50622
51904
|
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
50623
|
-
readFile: (p) =>
|
|
51905
|
+
readFile: (p) => fs9.readFileSync(p, "utf-8"),
|
|
50624
51906
|
readStdin
|
|
50625
51907
|
});
|
|
50626
51908
|
if (ingested.kind === "error") {
|
|
@@ -50772,7 +52054,7 @@ ${JSON.stringify(info.input_schema, null, 2)}`);
|
|
|
50772
52054
|
const ingested = await ingestJsonArgs({
|
|
50773
52055
|
rawArg: toolArgs,
|
|
50774
52056
|
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
50775
|
-
readFile: (p) =>
|
|
52057
|
+
readFile: (p) => fs9.readFileSync(p, "utf-8"),
|
|
50776
52058
|
readStdin
|
|
50777
52059
|
});
|
|
50778
52060
|
if (ingested.kind === "error") {
|