@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 +162 -156
- package/docs/knowledge_docs.md +3 -1
- package/package.json +1 -1
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 = "
|
|
30646
|
-
var STARTER_FALLBACK_SDK_VERSION = "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
|
-
//
|
|
30847
|
-
//
|
|
30848
|
-
//
|
|
30849
|
-
//
|
|
30850
|
-
//
|
|
30851
|
-
//
|
|
30852
|
-
//
|
|
30853
|
-
//
|
|
30854
|
-
|
|
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
|
|
31207
|
-
// these to lucide-react at
|
|
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/
|
|
32270
|
-
var
|
|
32271
|
-
|
|
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
|
|
32425
|
-
|
|
32426
|
-
|
|
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
|
-
|
|
32430
|
-
|
|
32431
|
-
|
|
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 \`
|
|
32434
|
-
// augmenting the @lotics/app-sdk \`
|
|
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
|
|
32439
|
-
const entries = Object.entries(
|
|
32430
|
+
function generateAppWorkflowsDts(workflows) {
|
|
32431
|
+
const entries = Object.entries(workflows ?? {});
|
|
32440
32432
|
if (entries.length === 0) {
|
|
32441
|
-
return `${
|
|
32442
|
-
// No
|
|
32443
|
-
// Add an entry to enable typed
|
|
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
|
|
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
|
|
32453
|
+
interface AppWorkflowResults {
|
|
32462
32454
|
${resultLines.join("\n")}
|
|
32463
32455
|
}` : "";
|
|
32464
|
-
return `${
|
|
32456
|
+
return `${WORKFLOWS_HEADER}
|
|
32465
32457
|
declare module "@lotics/app-sdk" {
|
|
32466
|
-
interface
|
|
32458
|
+
interface AppWorkflows {
|
|
32467
32459
|
${inputLines.join("\n")}
|
|
32468
32460
|
}${resultsBlock}
|
|
32469
32461
|
}
|
|
32470
32462
|
`;
|
|
32471
32463
|
}
|
|
32472
|
-
|
|
32473
|
-
//
|
|
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 \`
|
|
32478
|
-
// augmenting the @lotics/app-sdk \`
|
|
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
|
|
32483
|
-
const entries = Object.entries(
|
|
32472
|
+
function generateAppAgentsDts(agents) {
|
|
32473
|
+
const entries = Object.entries(agents ?? {});
|
|
32484
32474
|
if (entries.length === 0) {
|
|
32485
|
-
return `${
|
|
32486
|
-
// No
|
|
32487
|
-
// Add an entry to enable typed
|
|
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
|
|
32479
|
+
interface AppAgents {}
|
|
32490
32480
|
}
|
|
32491
32481
|
`;
|
|
32492
32482
|
}
|
|
32493
32483
|
entries.sort(([a], [b]) => a.localeCompare(b));
|
|
32494
|
-
const
|
|
32484
|
+
const inputLines = [];
|
|
32485
|
+
const resultLines = [];
|
|
32495
32486
|
for (const [alias, declaration] of entries) {
|
|
32496
|
-
const valueType = inputsToType(declaration.
|
|
32487
|
+
const valueType = declaration.inputs ? inputsToType(declaration.inputs) : "Record<string, unknown>";
|
|
32497
32488
|
const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
|
|
32498
|
-
|
|
32489
|
+
inputLines.push(` ${aliasKey}: ${valueType};`);
|
|
32490
|
+
if (declaration.outputs) {
|
|
32491
|
+
resultLines.push(` ${aliasKey}: ${objectFieldsToType(declaration.outputs)};`);
|
|
32492
|
+
}
|
|
32499
32493
|
}
|
|
32500
|
-
|
|
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
|
|
32503
|
-
${
|
|
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
|
|
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 `${
|
|
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 `${
|
|
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
|
|
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 `${
|
|
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
|
|
33496
|
-
|
|
33497
|
-
|
|
33498
|
-
|
|
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 +",
|
package/docs/knowledge_docs.md
CHANGED
|
@@ -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).
|
|
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
|
|