@lotics/cli 0.89.1 → 0.90.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.
Files changed (2) hide show
  1. package/dist/src/cli.js +151 -118
  2. package/package.json +1 -1
package/dist/src/cli.js CHANGED
@@ -30643,7 +30643,7 @@ import { tmpdir } from "node:os";
30643
30643
 
30644
30644
  // src/starter_template.ts
30645
30645
  var STARTER_FALLBACK_UI_VERSION = "6.1.0";
30646
- var STARTER_FALLBACK_SDK_VERSION = "0.51.0";
30646
+ var STARTER_FALLBACK_SDK_VERSION = "0.52.0";
30647
30647
  var STARTER_REACT_NATIVE_VERSION = "0.85.3";
30648
30648
  var VITEST_SETUP_FILENAME = "vitest.setup.ts";
30649
30649
  var VITEST_SETUP_CONTENT = `import { vi } from "vitest";
@@ -30793,8 +30793,32 @@ function buildStarterTemplate(args) {
30793
30793
  path: "vite.config.ts",
30794
30794
  content: `/// <reference types="vitest" />
30795
30795
  import { defineConfig } from "vite";
30796
+ import type { Plugin } from "vite";
30796
30797
  import react from "@vitejs/plugin-react";
30797
30798
 
30799
+ // @lotics/ui/icon.tsx deep-imports \`lucide-react-native/dist/esm/icons/<name>\`.
30800
+ // lucide-react-native's \`exports\` map lists only "." and "./icons", so a strict
30801
+ // resolver (the sandbox's vite dev optimizer) blocks the deep path with
30802
+ // \`Missing "./dist/esm/icons/<name>" specifier\`. lucide-react ships the same
30803
+ // per-icon files with NO exports map, so redirect there. A \`resolveId\` PLUGIN
30804
+ // (not \`resolve.alias\`) is required: the dep-optimizer SCAN runs plugin
30805
+ // resolveId hooks but does NOT apply regex \`resolve.alias\`, so the alias alone
30806
+ // fixes the production build but leaves the dev preview broken.
30807
+ function lucideIconsWebAlias(): Plugin {
30808
+ return {
30809
+ name: "lucide-icons-web-alias",
30810
+ enforce: "pre",
30811
+ async resolveId(source, importer, options) {
30812
+ const m = /^lucide-react-native\\/dist\\/esm\\/icons\\/(.+)$/.exec(source);
30813
+ if (!m) return null;
30814
+ return this.resolve(\`lucide-react/dist/esm/icons/\${m[1]}\`, importer, {
30815
+ ...options,
30816
+ skipSelf: true,
30817
+ });
30818
+ },
30819
+ };
30820
+ }
30821
+
30798
30822
  // Vite default base (/) emits absolute asset URLs in index.html. Lotics's
30799
30823
  // render endpoint rewrites those to /v1/apps/{id}/asset/... so the bundle
30800
30824
  // loads via the platform's asset proxy. Don't change \`base\` unless you
@@ -30804,14 +30828,8 @@ import react from "@vitejs/plugin-react";
30804
30828
  // (View, Text, Pressable, StyleSheet, etc.) render in a pure-web environment.
30805
30829
  // .web.tsx is prioritized in resolve.extensions so per-target variants
30806
30830
  // (avatar.web.tsx, wave_avatar.web.tsx) win over the native .tsx file.
30807
- //
30808
- // @lotics/ui/icon.tsx imports from \`lucide-react-native/dist/esm/icons/<name>\`
30809
- // \u2014 deep paths that lucide-react-native's package \`exports\` map blocks under
30810
- // Vite's strict resolution. lucide-react has the same per-icon files with no
30811
- // exports map, so we alias the deep path to use it. Web rendering of <svg>
30812
- // is identical to RN-SVG when running under RN-Web.
30813
30831
  export default defineConfig({
30814
- plugins: [react()],
30832
+ plugins: [lucideIconsWebAlias(), react()],
30815
30833
  // RN libraries reference globals Metro injects but Vite does not \u2014 undefined
30816
30834
  // \u21D2 the bundle throws. \`__DEV__\` (react-native-web, @react-native-picker's
30817
30835
  // UnimplementedView): throws at load, blank iframe. \`global\` (rn-web
@@ -30822,13 +30840,7 @@ export default defineConfig({
30822
30840
  // is safe. Define both so dev and the deployed build behave identically.
30823
30841
  define: { __DEV__: "false", global: "globalThis" },
30824
30842
  resolve: {
30825
- alias: [
30826
- {
30827
- find: /^lucide-react-native\\/dist\\/esm\\/icons\\/(.+)$/,
30828
- replacement: "lucide-react/dist/esm/icons/$1",
30829
- },
30830
- { find: "react-native", replacement: "react-native-web" },
30831
- ],
30843
+ alias: [{ find: "react-native", replacement: "react-native-web" }],
30832
30844
  // \`.web.js\` resolves the web build of RN packages that ship \`X.js\` (native)
30833
30845
  // beside \`X.web.js\` (web) \u2014 e.g. @react-native-picker/picker, whose compiled
30834
30846
  // \`Picker.web.js\` renders a real <select>. Without it the extensionless
@@ -30907,6 +30919,12 @@ export default defineConfig({
30907
30919
  // iframe loads modules from api.lotics.ai which already permits null
30908
30920
  // origin via CORS.
30909
30921
  cors: { origin: "*" },
30922
+ // Chat-authoring previews reach this dev server through the sandbox proxy
30923
+ // at \`5173-<id>-<token>.lotics-sandbox.app\`. Vite \u22655.4.12 rejects HMR
30924
+ // WebSocket upgrades whose Origin doesn't match a trusted host (its
30925
+ // cross-site WS hijack fix) \u2014 without this entry the proxied preview page
30926
+ // loads over HTTP but HMR never connects, so edits stop live-updating.
30927
+ allowedHosts: [".lotics-sandbox.app"],
30910
30928
  // @lotics/ui/fonts.css references the API's /iframe/fonts/*.woff2 files
30911
30929
  // by root-relative URL. A deployed app is served from the API origin so
30912
30930
  // they resolve directly; under \`lotics app dev\` the app runs on
@@ -31050,6 +31068,7 @@ mount(
31050
31068
  import { View } from "react-native";
31051
31069
  import { useNavigate, useParams } from "react-router-dom";
31052
31070
  import { AppRouter } from "@lotics/app-sdk/router";
31071
+ import { useAiContext } from "@lotics/app-sdk";
31053
31072
  import { Card } from "@lotics/ui/card";
31054
31073
  import { Text } from "@lotics/ui/text";
31055
31074
  import { Button } from "@lotics/ui/button";
@@ -31114,6 +31133,16 @@ function ItemDetailScreen() {
31114
31133
  const { id } = useParams();
31115
31134
  const navigate = useNavigate();
31116
31135
  const item = ITEMS.find((i) => i.id === id);
31136
+ // Tell the member's ambient chat agent what this screen is showing, so a
31137
+ // question like "summarise this" has context. This is PUSH-ONLY: a snapshot of
31138
+ // what the app rendered to the member, never a channel for chat to pull app
31139
+ // data \u2014 the text lands in the prompt as labeled data (not instructions) and
31140
+ // any record refs would act only within the member's own IAM. Pass null to
31141
+ // clear the slot (here: nothing to describe when the item isn't found).
31142
+ useAiContext(
31143
+ "item_detail",
31144
+ item ? { description: \`Viewing item "\${item.name}".\`, data: { id: item.id } } : null,
31145
+ );
31117
31146
  return (
31118
31147
  <Screen>
31119
31148
  {/* An in-app Back control; navigate(-1) walks the history (the browser Back
@@ -31203,9 +31232,9 @@ each alias lives in \`package.json#lotics.workflows.<alias>\`.
31203
31232
  path: "src/lucide-react-native.d.ts",
31204
31233
  content: `// Type shim for lucide-react-native's deep-icon imports
31205
31234
  // (\`lucide-react-native/dist/esm/icons/<name>\`). The package ships JS-only
31206
- // files without per-file .d.ts. The Vite alias in vite.config.ts rewrites
31207
- // these to lucide-react at bundle time; this declaration covers the
31208
- // TypeScript compile-time gap.
31235
+ // files without per-file .d.ts. The lucideIconsWebAlias() plugin in
31236
+ // vite.config.ts redirects these to lucide-react at resolve time; this
31237
+ // declaration covers the TypeScript compile-time gap.
31209
31238
  declare module "lucide-react-native/dist/esm/icons/*" {
31210
31239
  import type { ComponentType } from "react";
31211
31240
  const Icon: ComponentType<{
@@ -32266,48 +32295,10 @@ function openBrowser(url) {
32266
32295
  child.unref();
32267
32296
  }
32268
32297
 
32269
- // src/generate_app_workflows_dts.ts
32270
- var HEADER = `// Auto-generated by 'lotics app pull/dev/deploy'.
32271
- // DO NOT EDIT \u2014 regenerated from package.json#lotics.workflows.
32272
- //
32273
- // This file gives \`useWorkflow("alias")\` a typed input parameter at call
32274
- // sites by augmenting the @lotics/app-sdk \`AppWorkflows\` interface.
32275
-
32276
- import "@lotics/app-sdk";
32277
- `;
32278
- function generateAppWorkflowsDts(workflows) {
32279
- const entries = Object.entries(workflows ?? {});
32280
- if (entries.length === 0) {
32281
- return `${HEADER}
32282
- // No workflows declared in package.json#lotics.workflows.
32283
- // Add an entry to enable typed useWorkflow<"alias"> at call sites.
32284
- declare module "@lotics/app-sdk" {
32285
- interface AppWorkflows {}
32286
- }
32287
- `;
32288
- }
32289
- entries.sort(([a], [b]) => a.localeCompare(b));
32290
- const inputLines = [];
32291
- const resultLines = [];
32292
- for (const [alias, declaration] of entries) {
32293
- const valueType = declaration.inputs ? inputsToType(declaration.inputs, { nullableOptional: true }) : "Record<string, unknown>";
32294
- const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
32295
- inputLines.push(` ${aliasKey}: ${valueType};`);
32296
- if (declaration.outputs) {
32297
- resultLines.push(` ${aliasKey}: ${objectFieldsToType(declaration.outputs)};`);
32298
- }
32299
- }
32300
- const resultsBlock = resultLines.length > 0 ? `
32301
- interface AppWorkflowResults {
32302
- ${resultLines.join("\n")}
32303
- }` : "";
32304
- return `${HEADER}
32305
- declare module "@lotics/app-sdk" {
32306
- interface AppWorkflows {
32307
- ${inputLines.join("\n")}
32308
- }${resultsBlock}
32309
- }
32310
- `;
32298
+ // ../shared/src/app_dts.ts
32299
+ var IDENTIFIER_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
32300
+ function isValidIdentifier(name) {
32301
+ return IDENTIFIER_REGEX.test(name);
32311
32302
  }
32312
32303
  function inputsToType(inputs, opts) {
32313
32304
  const nullableOptional = opts?.nullableOptional === true;
@@ -32421,28 +32412,56 @@ function outputDeclToTsType(decl) {
32421
32412
  return "unknown";
32422
32413
  }
32423
32414
  }
32424
- var IDENTIFIER_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
32425
- function isValidIdentifier(name) {
32426
- return IDENTIFIER_REGEX.test(name);
32427
- }
32415
+ var QUERIES_HEADER = `// Auto-generated by 'lotics app pull/dev/deploy'.
32416
+ // DO NOT EDIT \u2014 regenerated from package.json#lotics.queries.
32417
+ //
32418
+ // This file gives \`useQuery("alias", params)\` typed params at call sites by
32419
+ // augmenting the @lotics/app-sdk \`AppQueries\` interface.
32428
32420
 
32429
- // src/generate_app_agents_dts.ts
32430
- var HEADER2 = `// Auto-generated by 'lotics app pull/dev/deploy'.
32431
- // DO NOT EDIT \u2014 regenerated from package.json#lotics.agents.
32421
+ import "@lotics/app-sdk";
32422
+ `;
32423
+ function generateAppQueriesDts(queries) {
32424
+ const entries = Object.entries(queries ?? {});
32425
+ if (entries.length === 0) {
32426
+ return `${QUERIES_HEADER}
32427
+ // No queries declared in package.json#lotics.queries.
32428
+ // Add an entry to enable typed useQuery("alias", params) at call sites.
32429
+ declare module "@lotics/app-sdk" {
32430
+ interface AppQueries {}
32431
+ }
32432
+ `;
32433
+ }
32434
+ entries.sort(([a], [b]) => a.localeCompare(b));
32435
+ const lines = [];
32436
+ for (const [alias, declaration] of entries) {
32437
+ const valueType = inputsToType(declaration.params ?? {});
32438
+ const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
32439
+ lines.push(` ${aliasKey}: ${valueType};`);
32440
+ }
32441
+ return `${QUERIES_HEADER}
32442
+ declare module "@lotics/app-sdk" {
32443
+ interface AppQueries {
32444
+ ${lines.join("\n")}
32445
+ }
32446
+ }
32447
+ `;
32448
+ }
32449
+ var WORKFLOWS_HEADER = `// Auto-generated by 'lotics app pull/dev/deploy'.
32450
+ // DO NOT EDIT \u2014 regenerated from package.json#lotics.workflows.
32432
32451
  //
32433
- // This file gives \`useAgentRun("alias")\` typed input + output at call sites by
32434
- // augmenting the @lotics/app-sdk \`AppAgents\` / \`AppAgentResults\` interfaces.
32452
+ // This file gives \`useWorkflow("alias")\` a typed input parameter at call
32453
+ // sites by augmenting the @lotics/app-sdk \`AppWorkflows\` interface.
32435
32454
 
32436
32455
  import "@lotics/app-sdk";
32437
32456
  `;
32438
- function generateAppAgentsDts(agents) {
32439
- const entries = Object.entries(agents ?? {});
32457
+ function generateAppWorkflowsDts(workflows) {
32458
+ const entries = Object.entries(workflows ?? {});
32440
32459
  if (entries.length === 0) {
32441
- return `${HEADER2}
32442
- // No agents declared in package.json#lotics.agents.
32443
- // Add an entry to enable typed useAgentRun<"alias"> at call sites.
32460
+ return `${WORKFLOWS_HEADER}
32461
+ // No workflows declared in package.json#lotics.workflows.
32462
+ // Add an entry to enable typed useWorkflow<"alias"> at call sites.
32444
32463
  declare module "@lotics/app-sdk" {
32445
- interface AppAgents {}
32464
+ interface AppWorkflows {}
32446
32465
  }
32447
32466
  `;
32448
32467
  }
@@ -32450,7 +32469,7 @@ declare module "@lotics/app-sdk" {
32450
32469
  const inputLines = [];
32451
32470
  const resultLines = [];
32452
32471
  for (const [alias, declaration] of entries) {
32453
- const valueType = declaration.inputs ? inputsToType(declaration.inputs) : "Record<string, unknown>";
32472
+ const valueType = declaration.inputs ? inputsToType(declaration.inputs, { nullableOptional: true }) : "Record<string, unknown>";
32454
32473
  const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
32455
32474
  inputLines.push(` ${aliasKey}: ${valueType};`);
32456
32475
  if (declaration.outputs) {
@@ -32458,53 +32477,78 @@ declare module "@lotics/app-sdk" {
32458
32477
  }
32459
32478
  }
32460
32479
  const resultsBlock = resultLines.length > 0 ? `
32461
- interface AppAgentResults {
32480
+ interface AppWorkflowResults {
32462
32481
  ${resultLines.join("\n")}
32463
32482
  }` : "";
32464
- return `${HEADER2}
32483
+ return `${WORKFLOWS_HEADER}
32465
32484
  declare module "@lotics/app-sdk" {
32466
- interface AppAgents {
32485
+ interface AppWorkflows {
32467
32486
  ${inputLines.join("\n")}
32468
32487
  }${resultsBlock}
32469
32488
  }
32470
32489
  `;
32471
32490
  }
32472
-
32473
- // src/generate_app_queries_dts.ts
32474
- var HEADER3 = `// Auto-generated by 'lotics app pull/dev/deploy'.
32475
- // DO NOT EDIT \u2014 regenerated from package.json#lotics.queries.
32491
+ var AGENTS_HEADER = `// Auto-generated by 'lotics app pull/dev/deploy'.
32492
+ // DO NOT EDIT \u2014 regenerated from package.json#lotics.agents.
32476
32493
  //
32477
- // This file gives \`useQuery("alias", params)\` typed params at call sites by
32478
- // augmenting the @lotics/app-sdk \`AppQueries\` interface.
32494
+ // This file gives \`useAgentRun("alias")\` typed input + output at call sites by
32495
+ // augmenting the @lotics/app-sdk \`AppAgents\` / \`AppAgentResults\` interfaces.
32479
32496
 
32480
32497
  import "@lotics/app-sdk";
32481
32498
  `;
32482
- function generateAppQueriesDts(queries) {
32483
- const entries = Object.entries(queries ?? {});
32499
+ function generateAppAgentsDts(agents) {
32500
+ const entries = Object.entries(agents ?? {});
32484
32501
  if (entries.length === 0) {
32485
- return `${HEADER3}
32486
- // No queries declared in package.json#lotics.queries.
32487
- // Add an entry to enable typed useQuery("alias", params) at call sites.
32502
+ return `${AGENTS_HEADER}
32503
+ // No agents declared in package.json#lotics.agents.
32504
+ // Add an entry to enable typed useAgentRun<"alias"> at call sites.
32488
32505
  declare module "@lotics/app-sdk" {
32489
- interface AppQueries {}
32506
+ interface AppAgents {}
32490
32507
  }
32491
32508
  `;
32492
32509
  }
32493
32510
  entries.sort(([a], [b]) => a.localeCompare(b));
32494
- const lines = [];
32511
+ const inputLines = [];
32512
+ const resultLines = [];
32495
32513
  for (const [alias, declaration] of entries) {
32496
- const valueType = inputsToType(declaration.params ?? {});
32514
+ const valueType = declaration.inputs ? inputsToType(declaration.inputs) : "Record<string, unknown>";
32497
32515
  const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
32498
- lines.push(` ${aliasKey}: ${valueType};`);
32516
+ inputLines.push(` ${aliasKey}: ${valueType};`);
32517
+ if (declaration.outputs) {
32518
+ resultLines.push(` ${aliasKey}: ${objectFieldsToType(declaration.outputs)};`);
32519
+ }
32499
32520
  }
32500
- return `${HEADER3}
32521
+ const resultsBlock = resultLines.length > 0 ? `
32522
+ interface AppAgentResults {
32523
+ ${resultLines.join("\n")}
32524
+ }` : "";
32525
+ return `${AGENTS_HEADER}
32501
32526
  declare module "@lotics/app-sdk" {
32502
- interface AppQueries {
32503
- ${lines.join("\n")}
32504
- }
32527
+ interface AppAgents {
32528
+ ${inputLines.join("\n")}
32529
+ }${resultsBlock}
32505
32530
  }
32506
32531
  `;
32507
32532
  }
32533
+ var CAPABILITY_GATED_CALLS = {
32534
+ comments: ["useComments", "createComment", "updateComment", "deleteComment"]
32535
+ };
32536
+ function undeclaredCapabilities(sourceText, declared) {
32537
+ const used = [];
32538
+ for (const [capability, calls] of Object.entries(CAPABILITY_GATED_CALLS)) {
32539
+ const isCalled = calls.some((call) => new RegExp(`\\b${call}\\b`).test(sourceText));
32540
+ if (isCalled && declared?.[capability] !== true) used.push(capability);
32541
+ }
32542
+ return used;
32543
+ }
32544
+ function unboundAliases(declared, bound) {
32545
+ const boundWorkflows = new Set(bound.workflows ?? []);
32546
+ const boundAgents = new Set(bound.agents ?? []);
32547
+ return {
32548
+ workflows: [...declared.workflows ?? []].filter((a) => !boundWorkflows.has(a)),
32549
+ agents: [...declared.agents ?? []].filter((a) => !boundAgents.has(a))
32550
+ };
32551
+ }
32508
32552
 
32509
32553
  // ../shared/src/app_query_ast.ts
32510
32554
  function collectQueryTableIds(node) {
@@ -32545,7 +32589,7 @@ function walk(node, visit) {
32545
32589
  }
32546
32590
 
32547
32591
  // src/generate_app_fields.ts
32548
- var HEADER4 = `// Auto-generated by 'lotics app codegen' (and app pull/dev/deploy).
32592
+ var HEADER = `// Auto-generated by 'lotics app codegen' (and app pull/dev/deploy).
32549
32593
  // DO NOT EDIT \u2014 regenerated from the workspace schema.
32550
32594
  //
32551
32595
  // Runtime field + option ids addressed by stable display-name aliases:
@@ -32639,7 +32683,7 @@ ${tableBlocks.join("\n")}
32639
32683
  }
32640
32684
  function generateAppFields(tables) {
32641
32685
  if (tables.length === 0) {
32642
- return `${HEADER4}
32686
+ return `${HEADER}
32643
32687
  export const F = {} as const;
32644
32688
 
32645
32689
  export const OPT = {} as const;
@@ -32651,7 +32695,7 @@ export type AppOptions = typeof OPT;
32651
32695
  `;
32652
32696
  }
32653
32697
  const aliased = aliasTables(tables);
32654
- return `${HEADER4}
32698
+ return `${HEADER}
32655
32699
  ${emitFieldMap(aliased)}
32656
32700
 
32657
32701
  ${emitOptionMap(aliased)}
@@ -32664,7 +32708,7 @@ export type AppOptions = typeof OPT;
32664
32708
  }
32665
32709
 
32666
32710
  // src/generate_package_fields.ts
32667
- var HEADER5 = `// Auto-generated by 'lotics app codegen' (linked/published app; also app pull/dev/deploy).
32711
+ var HEADER2 = `// Auto-generated by 'lotics app codegen' (linked/published app; also app pull/dev/deploy).
32668
32712
  // DO NOT EDIT \u2014 regenerated from the installation's live binding.
32669
32713
  //
32670
32714
  // A package installation resolves F/OPT/ROLE at MODULE LOAD from its binding
@@ -32764,7 +32808,7 @@ ${lines.join("\n")}
32764
32808
  }
32765
32809
  function generatePackageAppFields(binding) {
32766
32810
  const { entities, roles } = parseBinding(binding);
32767
- return `${HEADER5}
32811
+ return `${HEADER2}
32768
32812
  ${emitFieldMap2(entities)}
32769
32813
 
32770
32814
  ${emitOptionMap2(entities)}
@@ -33361,17 +33405,6 @@ Ready. Next steps:`);
33361
33405
  console.error(` # edit src/App.tsx`);
33362
33406
  console.error(` lotics app deploy`);
33363
33407
  }
33364
- var CAPABILITY_GATED_CALLS = {
33365
- comments: ["useComments", "createComment", "updateComment", "deleteComment"]
33366
- };
33367
- function undeclaredCapabilities(sourceText, declared) {
33368
- const used = [];
33369
- for (const [capability, calls] of Object.entries(CAPABILITY_GATED_CALLS)) {
33370
- const isCalled = calls.some((call) => new RegExp(`\\b${call}\\b`).test(sourceText));
33371
- if (isCalled && declared?.[capability] !== true) used.push(capability);
33372
- }
33373
- return used;
33374
- }
33375
33408
  function readAppSourceText(projectDir) {
33376
33409
  const srcDir = path5.join(projectDir, "src");
33377
33410
  if (!fs4.existsSync(srcDir)) return "";
@@ -33492,10 +33525,10 @@ function warnIfUnbranded(app) {
33492
33525
  );
33493
33526
  }
33494
33527
  function warnIfUnboundAliases(app, declaredWorkflows, declaredAgents) {
33495
- const boundWorkflows = new Set(Object.keys(app.workflows ?? {}));
33496
- const boundAgents = new Set(Object.keys(app.agents ?? {}));
33497
- const unboundWorkflows = Object.keys(declaredWorkflows).filter((a) => !boundWorkflows.has(a));
33498
- const unboundAgents = Object.keys(declaredAgents).filter((a) => !boundAgents.has(a));
33528
+ const { workflows: unboundWorkflows, agents: unboundAgents } = unboundAliases(
33529
+ { workflows: Object.keys(declaredWorkflows), agents: Object.keys(declaredAgents) },
33530
+ { workflows: Object.keys(app.workflows ?? {}), agents: Object.keys(app.agents ?? {}) }
33531
+ );
33499
33532
  if (unboundWorkflows.length === 0 && unboundAgents.length === 0) return;
33500
33533
  const lines = [
33501
33534
  "\n\u26A0 The manifest declares aliases that are NOT bound on the server. Deploy ships code +",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.89.1",
3
+ "version": "0.90.0",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {