@lotics/cli 0.89.1 → 0.91.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/src/cli.js CHANGED
@@ -30642,8 +30642,8 @@ import { spawn as spawn2 } from "node:child_process";
30642
30642
  import { tmpdir } from "node:os";
30643
30643
 
30644
30644
  // src/starter_template.ts
30645
- var STARTER_FALLBACK_UI_VERSION = "6.1.0";
30646
- var STARTER_FALLBACK_SDK_VERSION = "0.51.0";
30645
+ var STARTER_FALLBACK_UI_VERSION = "12.1.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,7 +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";
30798
+ import { loticsOptimizeDeps } from "@lotics/ui/vite";
30799
+
30800
+ // @lotics/ui/icon.tsx deep-imports \`lucide-react-native/dist/esm/icons/<name>\`.
30801
+ // lucide-react-native's \`exports\` map lists only "." and "./icons", so a strict
30802
+ // resolver (the sandbox's vite dev optimizer) blocks the deep path with
30803
+ // \`Missing "./dist/esm/icons/<name>" specifier\`. lucide-react ships the same
30804
+ // per-icon files with NO exports map, so redirect there. A \`resolveId\` PLUGIN
30805
+ // (not \`resolve.alias\`) is required: the dep-optimizer SCAN runs plugin
30806
+ // resolveId hooks but does NOT apply regex \`resolve.alias\`, so the alias alone
30807
+ // fixes the production build but leaves the dev preview broken.
30808
+ function lucideIconsWebAlias(): Plugin {
30809
+ return {
30810
+ name: "lucide-icons-web-alias",
30811
+ enforce: "pre",
30812
+ async resolveId(source, importer, options) {
30813
+ const m = /^lucide-react-native\\/dist\\/esm\\/icons\\/(.+)$/.exec(source);
30814
+ if (!m) return null;
30815
+ return this.resolve(\`lucide-react/dist/esm/icons/\${m[1]}\`, importer, {
30816
+ ...options,
30817
+ skipSelf: true,
30818
+ });
30819
+ },
30820
+ };
30821
+ }
30797
30822
 
30798
30823
  // Vite default base (/) emits absolute asset URLs in index.html. Lotics's
30799
30824
  // render endpoint rewrites those to /v1/apps/{id}/asset/... so the bundle
@@ -30804,14 +30829,8 @@ import react from "@vitejs/plugin-react";
30804
30829
  // (View, Text, Pressable, StyleSheet, etc.) render in a pure-web environment.
30805
30830
  // .web.tsx is prioritized in resolve.extensions so per-target variants
30806
30831
  // (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
30832
  export default defineConfig({
30814
- plugins: [react()],
30833
+ plugins: [lucideIconsWebAlias(), react()],
30815
30834
  // RN libraries reference globals Metro injects but Vite does not \u2014 undefined
30816
30835
  // \u21D2 the bundle throws. \`__DEV__\` (react-native-web, @react-native-picker's
30817
30836
  // UnimplementedView): throws at load, blank iframe. \`global\` (rn-web
@@ -30822,13 +30841,7 @@ export default defineConfig({
30822
30841
  // is safe. Define both so dev and the deployed build behave identically.
30823
30842
  define: { __DEV__: "false", global: "globalThis" },
30824
30843
  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
- ],
30844
+ alias: [{ find: "react-native", replacement: "react-native-web" }],
30832
30845
  // \`.web.js\` resolves the web build of RN packages that ship \`X.js\` (native)
30833
30846
  // beside \`X.web.js\` (web) \u2014 e.g. @react-native-picker/picker, whose compiled
30834
30847
  // \`Picker.web.js\` renders a real <select>. Without it the extensionless
@@ -30843,43 +30856,15 @@ export default defineConfig({
30843
30856
  dedupe: ["react", "react-dom", "react-native-web"],
30844
30857
  },
30845
30858
  optimizeDeps: {
30846
- // \`react-native-svg\` (used by @lotics/ui's svg charts \u2014 PieChart, LineChart,
30847
- // Sparkline, RingGauge) ships a named-export entry Vite's dev optimizer won't
30848
- // resolve unbundled ("does not provide an export named 'parse'"), blanking the
30849
- // iframe the moment one of those charts renders. Pre-bundling it fixes the
30850
- // interop. Production build (rollup) resolves it without this \u2014 dev-only.
30851
- //
30852
- // react-native-web itself is force-prebundled (folds its core CJS deps like
30853
- // @react-native/normalize-colors into one interop'd chunk), and the deep
30854
- // subpaths it reaches via *default* imports (e.g. @react-native-picker's web
30855
- // <select> build) are each pre-bundled into an ESM shim \u2014 Vite's dev optimizer
30856
- // otherwise serves them without a synthesized default export ("does not
30857
- // provide an export named 'default'"), blanking the iframe. (Production/rollup
30858
- // resolves the interop already, so this is dev-only.)
30859
- //
30860
- // \`react-markdown\` (@lotics/ui's Markdown renderer, reached by AgentRun and
30861
- // any markdown surface) pulls a transitive CJS dep, \`style-to-js\`, whose
30862
- // default export the dev optimizer won't synthesize unbundled ("does not
30863
- // provide an export named 'default'") \u2014 blanking the iframe the moment a
30864
- // markdown component mounts. Pre-bundling react-markdown folds the whole
30865
- // subtree (incl. style-to-js) into one interop'd chunk. It is a regular dep
30866
- // of @lotics/ui (hoisted), so it needs no package.json entry here. (The GFM
30867
- // plugin @lotics/ui composes is pure ESM \u2014 no CJS interop to force.)
30868
- include: [
30869
- "react-native-svg",
30870
- "react-markdown",
30871
- "react-native-web", "@react-native/normalize-colors",
30872
- "inline-style-prefixer/lib/createPrefixer",
30873
- "inline-style-prefixer/lib/plugins/crossFade",
30874
- "inline-style-prefixer/lib/plugins/imageSet",
30875
- "inline-style-prefixer/lib/plugins/logical",
30876
- "inline-style-prefixer/lib/plugins/position",
30877
- "inline-style-prefixer/lib/plugins/sizing",
30878
- "inline-style-prefixer/lib/plugins/transition",
30879
- "postcss-value-parser", "fbjs/lib/invariant", "fbjs/lib/warning",
30880
- "styleq", "styleq/transform-localize-style",
30881
- "react", "react-dom", "react-dom/client", "nullthrows",
30882
- ],
30859
+ // The dev dep-optimizer must pre-bundle @lotics/ui's RN-ecosystem + markdown
30860
+ // CJS-interop deps or \`lotics app dev\` blanks the iframe ("does not provide an
30861
+ // export named 'default'/'parse'"). Dev-ONLY: the prod rollup build resolves the
30862
+ // interop without it, so typecheck/lint/build stay green while the dev iframe
30863
+ // goes blank. The canonical list ships WITH @lotics/ui as \`loticsOptimizeDeps\`
30864
+ // (imported above) so it can never drift from what the kit's transitive deps
30865
+ // require across a major bump \u2014 the per-family rationale lives in that module.
30866
+ // To add app-specific entries, spread: include: [...loticsOptimizeDeps, "my-dep"].
30867
+ include: loticsOptimizeDeps,
30883
30868
  // The dep optimizer pre-bundles deps with a SEPARATE esbuild pass that
30884
30869
  // top-level \`define\` doesn't always reach, so a pre-bundled RN dep can
30885
30870
  // still hit \`__DEV__ is not defined\` under \`lotics app dev\`. Define it
@@ -30907,6 +30892,12 @@ export default defineConfig({
30907
30892
  // iframe loads modules from api.lotics.ai which already permits null
30908
30893
  // origin via CORS.
30909
30894
  cors: { origin: "*" },
30895
+ // Chat-authoring previews reach this dev server through the sandbox proxy
30896
+ // at \`5173-<id>-<token>.lotics-sandbox.app\`. Vite \u22655.4.12 rejects HMR
30897
+ // WebSocket upgrades whose Origin doesn't match a trusted host (its
30898
+ // cross-site WS hijack fix) \u2014 without this entry the proxied preview page
30899
+ // loads over HTTP but HMR never connects, so edits stop live-updating.
30900
+ allowedHosts: [".lotics-sandbox.app"],
30910
30901
  // @lotics/ui/fonts.css references the API's /iframe/fonts/*.woff2 files
30911
30902
  // by root-relative URL. A deployed app is served from the API origin so
30912
30903
  // they resolve directly; under \`lotics app dev\` the app runs on
@@ -31050,6 +31041,7 @@ mount(
31050
31041
  import { View } from "react-native";
31051
31042
  import { useNavigate, useParams } from "react-router-dom";
31052
31043
  import { AppRouter } from "@lotics/app-sdk/router";
31044
+ import { useAiContext } from "@lotics/app-sdk";
31053
31045
  import { Card } from "@lotics/ui/card";
31054
31046
  import { Text } from "@lotics/ui/text";
31055
31047
  import { Button } from "@lotics/ui/button";
@@ -31114,6 +31106,16 @@ function ItemDetailScreen() {
31114
31106
  const { id } = useParams();
31115
31107
  const navigate = useNavigate();
31116
31108
  const item = ITEMS.find((i) => i.id === id);
31109
+ // Tell the member's ambient chat agent what this screen is showing, so a
31110
+ // question like "summarise this" has context. This is PUSH-ONLY: a snapshot of
31111
+ // what the app rendered to the member, never a channel for chat to pull app
31112
+ // data \u2014 the text lands in the prompt as labeled data (not instructions) and
31113
+ // any record refs would act only within the member's own IAM. Pass null to
31114
+ // clear the slot (here: nothing to describe when the item isn't found).
31115
+ useAiContext(
31116
+ "item_detail",
31117
+ item ? { description: \`Viewing item "\${item.name}".\`, data: { id: item.id } } : null,
31118
+ );
31117
31119
  return (
31118
31120
  <Screen>
31119
31121
  {/* An in-app Back control; navigate(-1) walks the history (the browser Back
@@ -31203,9 +31205,9 @@ each alias lives in \`package.json#lotics.workflows.<alias>\`.
31203
31205
  path: "src/lucide-react-native.d.ts",
31204
31206
  content: `// Type shim for lucide-react-native's deep-icon imports
31205
31207
  // (\`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.
31208
+ // files without per-file .d.ts. The lucideIconsWebAlias() plugin in
31209
+ // vite.config.ts redirects these to lucide-react at resolve time; this
31210
+ // declaration covers the TypeScript compile-time gap.
31209
31211
  declare module "lucide-react-native/dist/esm/icons/*" {
31210
31212
  import type { ComponentType } from "react";
31211
31213
  const Icon: ComponentType<{
@@ -32266,48 +32268,10 @@ function openBrowser(url) {
32266
32268
  child.unref();
32267
32269
  }
32268
32270
 
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
- `;
32271
+ // ../shared/src/app_dts.ts
32272
+ var IDENTIFIER_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
32273
+ function isValidIdentifier(name) {
32274
+ return IDENTIFIER_REGEX.test(name);
32311
32275
  }
32312
32276
  function inputsToType(inputs, opts) {
32313
32277
  const nullableOptional = opts?.nullableOptional === true;
@@ -32421,28 +32385,56 @@ function outputDeclToTsType(decl) {
32421
32385
  return "unknown";
32422
32386
  }
32423
32387
  }
32424
- var IDENTIFIER_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
32425
- function isValidIdentifier(name) {
32426
- return IDENTIFIER_REGEX.test(name);
32427
- }
32388
+ var QUERIES_HEADER = `// Auto-generated by 'lotics app pull/dev/deploy'.
32389
+ // DO NOT EDIT \u2014 regenerated from package.json#lotics.queries.
32390
+ //
32391
+ // This file gives \`useQuery("alias", params)\` typed params at call sites by
32392
+ // augmenting the @lotics/app-sdk \`AppQueries\` interface.
32428
32393
 
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.
32394
+ import "@lotics/app-sdk";
32395
+ `;
32396
+ function generateAppQueriesDts(queries) {
32397
+ const entries = Object.entries(queries ?? {});
32398
+ if (entries.length === 0) {
32399
+ return `${QUERIES_HEADER}
32400
+ // No queries declared in package.json#lotics.queries.
32401
+ // Add an entry to enable typed useQuery("alias", params) at call sites.
32402
+ declare module "@lotics/app-sdk" {
32403
+ interface AppQueries {}
32404
+ }
32405
+ `;
32406
+ }
32407
+ entries.sort(([a], [b]) => a.localeCompare(b));
32408
+ const lines = [];
32409
+ for (const [alias, declaration] of entries) {
32410
+ const valueType = inputsToType(declaration.params ?? {});
32411
+ const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
32412
+ lines.push(` ${aliasKey}: ${valueType};`);
32413
+ }
32414
+ return `${QUERIES_HEADER}
32415
+ declare module "@lotics/app-sdk" {
32416
+ interface AppQueries {
32417
+ ${lines.join("\n")}
32418
+ }
32419
+ }
32420
+ `;
32421
+ }
32422
+ var WORKFLOWS_HEADER = `// Auto-generated by 'lotics app pull/dev/deploy'.
32423
+ // DO NOT EDIT \u2014 regenerated from package.json#lotics.workflows.
32432
32424
  //
32433
- // This file gives \`useAgentRun("alias")\` typed input + output at call sites by
32434
- // augmenting the @lotics/app-sdk \`AppAgents\` / \`AppAgentResults\` interfaces.
32425
+ // This file gives \`useWorkflow("alias")\` a typed input parameter at call
32426
+ // sites by augmenting the @lotics/app-sdk \`AppWorkflows\` interface.
32435
32427
 
32436
32428
  import "@lotics/app-sdk";
32437
32429
  `;
32438
- function generateAppAgentsDts(agents) {
32439
- const entries = Object.entries(agents ?? {});
32430
+ function generateAppWorkflowsDts(workflows) {
32431
+ const entries = Object.entries(workflows ?? {});
32440
32432
  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.
32433
+ return `${WORKFLOWS_HEADER}
32434
+ // No workflows declared in package.json#lotics.workflows.
32435
+ // Add an entry to enable typed useWorkflow<"alias"> at call sites.
32444
32436
  declare module "@lotics/app-sdk" {
32445
- interface AppAgents {}
32437
+ interface AppWorkflows {}
32446
32438
  }
32447
32439
  `;
32448
32440
  }
@@ -32450,7 +32442,7 @@ declare module "@lotics/app-sdk" {
32450
32442
  const inputLines = [];
32451
32443
  const resultLines = [];
32452
32444
  for (const [alias, declaration] of entries) {
32453
- const valueType = declaration.inputs ? inputsToType(declaration.inputs) : "Record<string, unknown>";
32445
+ const valueType = declaration.inputs ? inputsToType(declaration.inputs, { nullableOptional: true }) : "Record<string, unknown>";
32454
32446
  const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
32455
32447
  inputLines.push(` ${aliasKey}: ${valueType};`);
32456
32448
  if (declaration.outputs) {
@@ -32458,53 +32450,78 @@ declare module "@lotics/app-sdk" {
32458
32450
  }
32459
32451
  }
32460
32452
  const resultsBlock = resultLines.length > 0 ? `
32461
- interface AppAgentResults {
32453
+ interface AppWorkflowResults {
32462
32454
  ${resultLines.join("\n")}
32463
32455
  }` : "";
32464
- return `${HEADER2}
32456
+ return `${WORKFLOWS_HEADER}
32465
32457
  declare module "@lotics/app-sdk" {
32466
- interface AppAgents {
32458
+ interface AppWorkflows {
32467
32459
  ${inputLines.join("\n")}
32468
32460
  }${resultsBlock}
32469
32461
  }
32470
32462
  `;
32471
32463
  }
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.
32464
+ var AGENTS_HEADER = `// Auto-generated by 'lotics app pull/dev/deploy'.
32465
+ // DO NOT EDIT \u2014 regenerated from package.json#lotics.agents.
32476
32466
  //
32477
- // This file gives \`useQuery("alias", params)\` typed params at call sites by
32478
- // augmenting the @lotics/app-sdk \`AppQueries\` interface.
32467
+ // This file gives \`useAgentRun("alias")\` typed input + output at call sites by
32468
+ // augmenting the @lotics/app-sdk \`AppAgents\` / \`AppAgentResults\` interfaces.
32479
32469
 
32480
32470
  import "@lotics/app-sdk";
32481
32471
  `;
32482
- function generateAppQueriesDts(queries) {
32483
- const entries = Object.entries(queries ?? {});
32472
+ function generateAppAgentsDts(agents) {
32473
+ const entries = Object.entries(agents ?? {});
32484
32474
  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.
32475
+ return `${AGENTS_HEADER}
32476
+ // No agents declared in package.json#lotics.agents.
32477
+ // Add an entry to enable typed useAgentRun<"alias"> at call sites.
32488
32478
  declare module "@lotics/app-sdk" {
32489
- interface AppQueries {}
32479
+ interface AppAgents {}
32490
32480
  }
32491
32481
  `;
32492
32482
  }
32493
32483
  entries.sort(([a], [b]) => a.localeCompare(b));
32494
- const lines = [];
32484
+ const inputLines = [];
32485
+ const resultLines = [];
32495
32486
  for (const [alias, declaration] of entries) {
32496
- const valueType = inputsToType(declaration.params ?? {});
32487
+ const valueType = declaration.inputs ? inputsToType(declaration.inputs) : "Record<string, unknown>";
32497
32488
  const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
32498
- lines.push(` ${aliasKey}: ${valueType};`);
32489
+ inputLines.push(` ${aliasKey}: ${valueType};`);
32490
+ if (declaration.outputs) {
32491
+ resultLines.push(` ${aliasKey}: ${objectFieldsToType(declaration.outputs)};`);
32492
+ }
32499
32493
  }
32500
- return `${HEADER3}
32494
+ const resultsBlock = resultLines.length > 0 ? `
32495
+ interface AppAgentResults {
32496
+ ${resultLines.join("\n")}
32497
+ }` : "";
32498
+ return `${AGENTS_HEADER}
32501
32499
  declare module "@lotics/app-sdk" {
32502
- interface AppQueries {
32503
- ${lines.join("\n")}
32504
- }
32500
+ interface AppAgents {
32501
+ ${inputLines.join("\n")}
32502
+ }${resultsBlock}
32505
32503
  }
32506
32504
  `;
32507
32505
  }
32506
+ var CAPABILITY_GATED_CALLS = {
32507
+ comments: ["useComments", "createComment", "updateComment", "deleteComment"]
32508
+ };
32509
+ function undeclaredCapabilities(sourceText, declared) {
32510
+ const used = [];
32511
+ for (const [capability, calls] of Object.entries(CAPABILITY_GATED_CALLS)) {
32512
+ const isCalled = calls.some((call) => new RegExp(`\\b${call}\\b`).test(sourceText));
32513
+ if (isCalled && declared?.[capability] !== true) used.push(capability);
32514
+ }
32515
+ return used;
32516
+ }
32517
+ function unboundAliases(declared, bound) {
32518
+ const boundWorkflows = new Set(bound.workflows ?? []);
32519
+ const boundAgents = new Set(bound.agents ?? []);
32520
+ return {
32521
+ workflows: [...declared.workflows ?? []].filter((a) => !boundWorkflows.has(a)),
32522
+ agents: [...declared.agents ?? []].filter((a) => !boundAgents.has(a))
32523
+ };
32524
+ }
32508
32525
 
32509
32526
  // ../shared/src/app_query_ast.ts
32510
32527
  function collectQueryTableIds(node) {
@@ -32545,7 +32562,7 @@ function walk(node, visit) {
32545
32562
  }
32546
32563
 
32547
32564
  // src/generate_app_fields.ts
32548
- var HEADER4 = `// Auto-generated by 'lotics app codegen' (and app pull/dev/deploy).
32565
+ var HEADER = `// Auto-generated by 'lotics app codegen' (and app pull/dev/deploy).
32549
32566
  // DO NOT EDIT \u2014 regenerated from the workspace schema.
32550
32567
  //
32551
32568
  // Runtime field + option ids addressed by stable display-name aliases:
@@ -32639,7 +32656,7 @@ ${tableBlocks.join("\n")}
32639
32656
  }
32640
32657
  function generateAppFields(tables) {
32641
32658
  if (tables.length === 0) {
32642
- return `${HEADER4}
32659
+ return `${HEADER}
32643
32660
  export const F = {} as const;
32644
32661
 
32645
32662
  export const OPT = {} as const;
@@ -32651,7 +32668,7 @@ export type AppOptions = typeof OPT;
32651
32668
  `;
32652
32669
  }
32653
32670
  const aliased = aliasTables(tables);
32654
- return `${HEADER4}
32671
+ return `${HEADER}
32655
32672
  ${emitFieldMap(aliased)}
32656
32673
 
32657
32674
  ${emitOptionMap(aliased)}
@@ -32664,7 +32681,7 @@ export type AppOptions = typeof OPT;
32664
32681
  }
32665
32682
 
32666
32683
  // src/generate_package_fields.ts
32667
- var HEADER5 = `// Auto-generated by 'lotics app codegen' (linked/published app; also app pull/dev/deploy).
32684
+ var HEADER2 = `// Auto-generated by 'lotics app codegen' (linked/published app; also app pull/dev/deploy).
32668
32685
  // DO NOT EDIT \u2014 regenerated from the installation's live binding.
32669
32686
  //
32670
32687
  // A package installation resolves F/OPT/ROLE at MODULE LOAD from its binding
@@ -32764,7 +32781,7 @@ ${lines.join("\n")}
32764
32781
  }
32765
32782
  function generatePackageAppFields(binding) {
32766
32783
  const { entities, roles } = parseBinding(binding);
32767
- return `${HEADER5}
32784
+ return `${HEADER2}
32768
32785
  ${emitFieldMap2(entities)}
32769
32786
 
32770
32787
  ${emitOptionMap2(entities)}
@@ -33361,17 +33378,6 @@ Ready. Next steps:`);
33361
33378
  console.error(` # edit src/App.tsx`);
33362
33379
  console.error(` lotics app deploy`);
33363
33380
  }
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
33381
  function readAppSourceText(projectDir) {
33376
33382
  const srcDir = path5.join(projectDir, "src");
33377
33383
  if (!fs4.existsSync(srcDir)) return "";
@@ -33492,10 +33498,10 @@ function warnIfUnbranded(app) {
33492
33498
  );
33493
33499
  }
33494
33500
  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));
33501
+ const { workflows: unboundWorkflows, agents: unboundAgents } = unboundAliases(
33502
+ { workflows: Object.keys(declaredWorkflows), agents: Object.keys(declaredAgents) },
33503
+ { workflows: Object.keys(app.workflows ?? {}), agents: Object.keys(app.agents ?? {}) }
33504
+ );
33499
33505
  if (unboundWorkflows.length === 0 && unboundAgents.length === 0) return;
33500
33506
  const lines = [
33501
33507
  "\n\u26A0 The manifest declares aliases that are NOT bound on the server. Deploy ships code +",
@@ -86,7 +86,9 @@ question without ever loading the rest. Structure your content so it works:
86
86
 
87
87
  Send only the fields you're changing. Content edits are **diffs**, not a full rewrite: pass an
88
88
  `edits` array (replace / insert / append operations) plus the `expected_version` you got from
89
- `read_knowledge` (optimistic concurrency — a stale version is rejected). Refine structure as you
89
+ `read_knowledge` (optimistic concurrency — a stale version is rejected). Over the CLI, the default
90
+ `read_knowledge` text output omits the version — read `current_version` from `lotics run read_knowledge … --json`.
91
+ Refine structure as you
90
92
  learn what users actually ask: add the synonym that failed to match, split the section that was
91
93
  too coarse to grep. See `lotics tools update_knowledge` for the edit shape.
92
94
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.89.1",
3
+ "version": "0.91.0",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {