@lotics/cli 0.66.0 → 0.68.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/dist/app_commands.js +48 -19
- package/dist/src/cli.js +47 -26
- package/dist/starter_template.js +5 -7
- package/package.json +2 -2
package/dist/app_commands.js
CHANGED
|
@@ -911,7 +911,16 @@ args) {
|
|
|
911
911
|
});
|
|
912
912
|
console.error(`Deployed v${result.version_number} (${result.version_id})`);
|
|
913
913
|
console.error(`Bundle size: ${(result.bundle_size_bytes / 1024).toFixed(1)} KB`);
|
|
914
|
-
|
|
914
|
+
// One post-deploy getApp feeds both advisory nudges (branding, unbound
|
|
915
|
+
// aliases). Deploy already succeeded — a failed check must not mask that.
|
|
916
|
+
try {
|
|
917
|
+
const app = await client.getApp(meta.app_id);
|
|
918
|
+
warnIfUnbranded(app);
|
|
919
|
+
warnIfUnboundAliases(app, meta.workflows ?? {}, meta.agents ?? {});
|
|
920
|
+
}
|
|
921
|
+
catch (err) {
|
|
922
|
+
console.error(`(skipped post-deploy checks: ${err.message})`);
|
|
923
|
+
}
|
|
915
924
|
}
|
|
916
925
|
catch (err) {
|
|
917
926
|
const e = err;
|
|
@@ -935,24 +944,44 @@ args) {
|
|
|
935
944
|
* generic tile in the launcher. Branding is set via `update_app` (the single
|
|
936
945
|
* setter) — this only reminds; it never fails the deploy.
|
|
937
946
|
*/
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
947
|
+
function warnIfUnbranded(app) {
|
|
948
|
+
const missing = [];
|
|
949
|
+
if (!app.icon)
|
|
950
|
+
missing.push("icon");
|
|
951
|
+
if (!app.theme?.color)
|
|
952
|
+
missing.push("color");
|
|
953
|
+
if (missing.length === 0)
|
|
954
|
+
return;
|
|
955
|
+
console.error(`\n⚠ This app has no ${missing.join(" or ")} set — it shows a generic tile in the launcher.\n` +
|
|
956
|
+
` Set it: lotics run update_app '{"app_id":"${app.id}","icon":"<lucide-name>","theme":{"color":"blue"}}'\n` +
|
|
957
|
+
` Find an icon: lotics run search_app_icons '{"query":"<word>"}'`);
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Non-blocking nudge after a successful deploy: catch manifest workflow/agent aliases
|
|
961
|
+
* that are NOT bound on the server. Deploy ships code + queries only — it never binds
|
|
962
|
+
* workflows/agents (`set_app_workflow` / `set_app_agent` own `apps.workflows`/`apps.agents`;
|
|
963
|
+
* the manifest maps are a pulled reflection). So an alias hand-added to `lotics.workflows`
|
|
964
|
+
* / `lotics.agents` (or bound then removed) compiles + deploys clean and only throws when
|
|
965
|
+
* the app first calls `useWorkflow` / `useAgentRun`. Surface that divergence HERE — at
|
|
966
|
+
* deploy time — instead of at the user's first click. Advisory only; never fails the deploy.
|
|
967
|
+
*/
|
|
968
|
+
function warnIfUnboundAliases(app, declaredWorkflows, declaredAgents) {
|
|
969
|
+
const boundWorkflows = new Set(Object.keys(app.workflows ?? {}));
|
|
970
|
+
const boundAgents = new Set(Object.keys(app.agents ?? {}));
|
|
971
|
+
const unboundWorkflows = Object.keys(declaredWorkflows).filter((a) => !boundWorkflows.has(a));
|
|
972
|
+
const unboundAgents = Object.keys(declaredAgents).filter((a) => !boundAgents.has(a));
|
|
973
|
+
if (unboundWorkflows.length === 0 && unboundAgents.length === 0)
|
|
974
|
+
return;
|
|
975
|
+
const lines = [
|
|
976
|
+
"\n⚠ The manifest declares aliases that are NOT bound on the server. Deploy ships code +",
|
|
977
|
+
" queries only — it does NOT bind workflows/agents, so the app will throw \"has no … alias\"",
|
|
978
|
+
" the first time it calls them. Bind each one:",
|
|
979
|
+
];
|
|
980
|
+
for (const alias of unboundWorkflows)
|
|
981
|
+
lines.push(` • workflow "${alias}" → lotics app workflow set ${alias}`);
|
|
982
|
+
for (const alias of unboundAgents)
|
|
983
|
+
lines.push(` • agent "${alias}" → bind with set_app_agent (lotics run set_app_agent …)`);
|
|
984
|
+
console.error(lines.join("\n"));
|
|
956
985
|
}
|
|
957
986
|
/**
|
|
958
987
|
* `lotics app dev [path] [--port=5174] [--vite-port=5173]`
|
package/dist/src/cli.js
CHANGED
|
@@ -30395,18 +30395,16 @@ function buildStarterTemplate(args) {
|
|
|
30395
30395
|
},
|
|
30396
30396
|
dependencies: {
|
|
30397
30397
|
"@lotics/app-sdk": sdkVersion,
|
|
30398
|
-
//
|
|
30399
|
-
//
|
|
30400
|
-
//
|
|
30401
|
-
|
|
30398
|
+
// The FilePreview engines (pdfjs-dist / @lotics/docx / @lotics/xlsx) are
|
|
30399
|
+
// NOT listed here: they ship as @lotics/ui dependencies (7.14.0+), so
|
|
30400
|
+
// every app gets them transitively — one version source, no skew. An app
|
|
30401
|
+
// that IMPORTS @lotics/docx or @lotics/xlsx directly (its own doc/excel
|
|
30402
|
+
// builders) declares its own dependency then.
|
|
30402
30403
|
"@lotics/ui": uiVersion,
|
|
30403
|
-
"@lotics/xlsx": "^0.1.0",
|
|
30404
30404
|
"@react-native-picker/picker": "^2.7.0",
|
|
30405
30405
|
"expo-image": "~3.0.9",
|
|
30406
30406
|
"lucide-react": "^0.562.0",
|
|
30407
30407
|
"lucide-react-native": "^0.562.0",
|
|
30408
|
-
// PDF preview engine for FilePreview/FileGalleryModal — also lazy-loaded.
|
|
30409
|
-
"pdfjs-dist": "^6.0.0",
|
|
30410
30408
|
react: "^19.0.0",
|
|
30411
30409
|
"react-dom": "^19.0.0",
|
|
30412
30410
|
"react-native": STARTER_REACT_NATIVE_VERSION,
|
|
@@ -32758,7 +32756,13 @@ async function appDeploy(client, args) {
|
|
|
32758
32756
|
});
|
|
32759
32757
|
console.error(`Deployed v${result.version_number} (${result.version_id})`);
|
|
32760
32758
|
console.error(`Bundle size: ${(result.bundle_size_bytes / 1024).toFixed(1)} KB`);
|
|
32761
|
-
|
|
32759
|
+
try {
|
|
32760
|
+
const app = await client.getApp(meta.app_id);
|
|
32761
|
+
warnIfUnbranded(app);
|
|
32762
|
+
warnIfUnboundAliases(app, meta.workflows ?? {}, meta.agents ?? {});
|
|
32763
|
+
} catch (err2) {
|
|
32764
|
+
console.error(`(skipped post-deploy checks: ${err2.message})`);
|
|
32765
|
+
}
|
|
32762
32766
|
} catch (err2) {
|
|
32763
32767
|
const e = err2;
|
|
32764
32768
|
if (e.code === "VERSION_CONFLICT") {
|
|
@@ -32774,22 +32778,32 @@ async function appDeploy(client, args) {
|
|
|
32774
32778
|
if (fs4.existsSync(tmpDist)) fs4.unlinkSync(tmpDist);
|
|
32775
32779
|
}
|
|
32776
32780
|
}
|
|
32777
|
-
|
|
32778
|
-
|
|
32779
|
-
|
|
32780
|
-
|
|
32781
|
-
|
|
32782
|
-
|
|
32783
|
-
|
|
32784
|
-
console.error(
|
|
32785
|
-
`
|
|
32781
|
+
function warnIfUnbranded(app) {
|
|
32782
|
+
const missing = [];
|
|
32783
|
+
if (!app.icon) missing.push("icon");
|
|
32784
|
+
if (!app.theme?.color) missing.push("color");
|
|
32785
|
+
if (missing.length === 0) return;
|
|
32786
|
+
console.error(
|
|
32787
|
+
`
|
|
32786
32788
|
\u26A0 This app has no ${missing.join(" or ")} set \u2014 it shows a generic tile in the launcher.
|
|
32787
|
-
Set it: lotics run update_app '{"app_id":"${
|
|
32789
|
+
Set it: lotics run update_app '{"app_id":"${app.id}","icon":"<lucide-name>","theme":{"color":"blue"}}'
|
|
32788
32790
|
Find an icon: lotics run search_app_icons '{"query":"<word>"}'`
|
|
32789
|
-
|
|
32790
|
-
|
|
32791
|
-
|
|
32792
|
-
}
|
|
32791
|
+
);
|
|
32792
|
+
}
|
|
32793
|
+
function warnIfUnboundAliases(app, declaredWorkflows, declaredAgents) {
|
|
32794
|
+
const boundWorkflows = new Set(Object.keys(app.workflows ?? {}));
|
|
32795
|
+
const boundAgents = new Set(Object.keys(app.agents ?? {}));
|
|
32796
|
+
const unboundWorkflows = Object.keys(declaredWorkflows).filter((a) => !boundWorkflows.has(a));
|
|
32797
|
+
const unboundAgents = Object.keys(declaredAgents).filter((a) => !boundAgents.has(a));
|
|
32798
|
+
if (unboundWorkflows.length === 0 && unboundAgents.length === 0) return;
|
|
32799
|
+
const lines = [
|
|
32800
|
+
"\n\u26A0 The manifest declares aliases that are NOT bound on the server. Deploy ships code +",
|
|
32801
|
+
' queries only \u2014 it does NOT bind workflows/agents, so the app will throw "has no \u2026 alias"',
|
|
32802
|
+
" the first time it calls them. Bind each one:"
|
|
32803
|
+
];
|
|
32804
|
+
for (const alias of unboundWorkflows) lines.push(` \u2022 workflow "${alias}" \u2192 lotics app workflow set ${alias}`);
|
|
32805
|
+
for (const alias of unboundAgents) lines.push(` \u2022 agent "${alias}" \u2192 bind with set_app_agent (lotics run set_app_agent \u2026)`);
|
|
32806
|
+
console.error(lines.join("\n"));
|
|
32793
32807
|
}
|
|
32794
32808
|
async function appDev(client, args) {
|
|
32795
32809
|
const projectDir = path5.resolve(args.projectDir ?? process.cwd());
|
|
@@ -42716,6 +42730,7 @@ function readCfbStreams(bytes) {
|
|
|
42716
42730
|
throw new Error("Unsupported .xls: invalid OLE2 sector size");
|
|
42717
42731
|
}
|
|
42718
42732
|
const sectorOffset = (n) => sectorSize * (n + 1);
|
|
42733
|
+
const maxSectors = Math.ceil(bytes.length / sectorSize) + 1;
|
|
42719
42734
|
const difat = [];
|
|
42720
42735
|
for (let i2 = 0; i2 < 109; i2++) {
|
|
42721
42736
|
const v = u32(76 + i2 * 4);
|
|
@@ -42723,7 +42738,9 @@ function readCfbStreams(bytes) {
|
|
|
42723
42738
|
}
|
|
42724
42739
|
let ds = firstDifatSector;
|
|
42725
42740
|
const entriesPerSector = sectorSize / 4;
|
|
42726
|
-
|
|
42741
|
+
const seenDifat = /* @__PURE__ */ new Set();
|
|
42742
|
+
while (ds !== ENDOFCHAIN && ds !== FREESECT && ds < maxSectors && !seenDifat.has(ds)) {
|
|
42743
|
+
seenDifat.add(ds);
|
|
42727
42744
|
const base = sectorOffset(ds);
|
|
42728
42745
|
for (let i2 = 0; i2 < entriesPerSector - 1; i2++) {
|
|
42729
42746
|
const v = u32(base + i2 * 4);
|
|
@@ -42733,14 +42750,18 @@ function readCfbStreams(bytes) {
|
|
|
42733
42750
|
}
|
|
42734
42751
|
const fat = [];
|
|
42735
42752
|
for (const fatSector of difat) {
|
|
42753
|
+
if (fat.length >= maxSectors) break;
|
|
42754
|
+
if (fatSector >= maxSectors) continue;
|
|
42736
42755
|
const base = sectorOffset(fatSector);
|
|
42737
|
-
for (let i2 = 0; i2 < entriesPerSector
|
|
42756
|
+
for (let i2 = 0; i2 < entriesPerSector && fat.length < maxSectors; i2++) {
|
|
42757
|
+
fat.push(u32(base + i2 * 4));
|
|
42758
|
+
}
|
|
42738
42759
|
}
|
|
42739
42760
|
const readChain = (src, start, size, ss, offOf, chain) => {
|
|
42740
|
-
const
|
|
42761
|
+
const maxSectors2 = Math.floor(src.length / ss) + 2;
|
|
42741
42762
|
const parts = [];
|
|
42742
42763
|
let s = start;
|
|
42743
|
-
for (let guard = 0; s !== ENDOFCHAIN && s !== FREESECT && s < chain.length && guard <
|
|
42764
|
+
for (let guard = 0; s !== ENDOFCHAIN && s !== FREESECT && s < chain.length && guard < maxSectors2; guard++) {
|
|
42744
42765
|
const o = offOf(s);
|
|
42745
42766
|
parts.push(src.subarray(o, o + ss));
|
|
42746
42767
|
s = chain[s];
|
package/dist/starter_template.js
CHANGED
|
@@ -80,18 +80,16 @@ export function buildStarterTemplate(args) {
|
|
|
80
80
|
},
|
|
81
81
|
dependencies: {
|
|
82
82
|
"@lotics/app-sdk": sdkVersion,
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
83
|
+
// The FilePreview engines (pdfjs-dist / @lotics/docx / @lotics/xlsx) are
|
|
84
|
+
// NOT listed here: they ship as @lotics/ui dependencies (7.14.0+), so
|
|
85
|
+
// every app gets them transitively — one version source, no skew. An app
|
|
86
|
+
// that IMPORTS @lotics/docx or @lotics/xlsx directly (its own doc/excel
|
|
87
|
+
// builders) declares its own dependency then.
|
|
87
88
|
"@lotics/ui": uiVersion,
|
|
88
|
-
"@lotics/xlsx": "^0.1.0",
|
|
89
89
|
"@react-native-picker/picker": "^2.7.0",
|
|
90
90
|
"expo-image": "~3.0.9",
|
|
91
91
|
"lucide-react": "^0.562.0",
|
|
92
92
|
"lucide-react-native": "^0.562.0",
|
|
93
|
-
// PDF preview engine for FilePreview/FileGalleryModal — also lazy-loaded.
|
|
94
|
-
"pdfjs-dist": "^6.0.0",
|
|
95
93
|
react: "^19.0.0",
|
|
96
94
|
"react-dom": "^19.0.0",
|
|
97
95
|
"react-native": STARTER_REACT_NATIVE_VERSION,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lotics/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.68.0",
|
|
4
4
|
"description": "Lotics SDK and CLI for AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@types/node": "^22.15.21",
|
|
27
27
|
"esbuild": "^0.28.1",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
|
-
"vitest": "^4.1.
|
|
29
|
+
"vitest": "^4.1.9"
|
|
30
30
|
},
|
|
31
31
|
"keywords": [
|
|
32
32
|
"lotics",
|