@lotics/cli 0.113.0 → 0.114.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
@@ -64471,12 +64471,6 @@ var TIER_MODELS = {
64471
64471
  var RESOLVED_MODEL_IDS = MODEL_TIERS.map(
64472
64472
  (tier) => TIER_MODELS[tier]
64473
64473
  );
64474
- function tierForModelId(modelId) {
64475
- for (const tier of MODEL_TIERS) {
64476
- if (modelId.startsWith(`claude-${tier}-`)) return tier;
64477
- }
64478
- return null;
64479
- }
64480
64474
  var DEFAULT_MODEL_TIER = "sonnet";
64481
64475
  var UTILITY_MODEL_TIER = "haiku";
64482
64476
  var DEFAULT_MODEL_ID = TIER_MODELS[DEFAULT_MODEL_TIER];
@@ -64944,15 +64938,6 @@ var appAgentDeclarationSchema = zod_default.object({
64944
64938
  model_tier: zod_default.enum(MODEL_TIERS).optional().describe(
64945
64939
  "Model tier the agent runs on \u2014 `haiku`, `sonnet`, or `opus`. Omit to follow the platform default tier, resolved at run time: the preferred choice. A tier names capability, not a version, so the generation behind it moves with the platform and this declaration never needs a rewrite. Pin only a deliberate, tested choice."
64946
64940
  ),
64947
- /**
64948
- * LEGACY, read-only. A version pin written by a release from before tiers.
64949
- * Parsed so a declaration an older release wrote during the rollout window
64950
- * still resolves (via `tierForModelId`) instead of reading as unpinned
64951
- * and silently dropping to the default. Never written by this release, and
64952
- * rejected on the write surface. Deleted with the strip migration, once no
64953
- * deployed release writes it.
64954
- */
64955
- model_id: zod_default.string().min(1).optional(),
64956
64941
  effort_level: zod_default.enum(EFFORT_LEVELS).optional().describe(
64957
64942
  "Reasoning depth for adaptive-thinking tiers \u2014 one of the chosen tier's supported levels (validated against model_tier at declare time). Omit to use the model default; ignored on tiers without adaptive thinking."
64958
64943
  ),
@@ -65094,8 +65079,6 @@ var agentStepSchema = stepBaseSchema.extend({
65094
65079
  input: zod_default.record(zod_default.string(), toolInputValueSchema),
65095
65080
  tool_names: zod_default.array(zod_default.string().min(1)),
65096
65081
  model_tier: zod_default.enum(MODEL_TIERS).optional(),
65097
- /** LEGACY, read-only — see `appAgentDeclarationSchema.model_id`. */
65098
- model_id: zod_default.string().min(1).optional(),
65099
65082
  output: agentOutputSpecSchema
65100
65083
  });
65101
65084
  var breakStepSchema = stepBaseSchema.extend({
@@ -69719,7 +69702,7 @@ function walkAgentInvocation(call, scope, stepId, description) {
69719
69702
  let model_tier;
69720
69703
  if (modelNode) {
69721
69704
  const literal2 = readStaticString(modelNode, "agent `model`");
69722
- const tier = MODEL_TIERS.includes(literal2) ? literal2 : tierForModelId(literal2);
69705
+ const tier = MODEL_TIERS.includes(literal2) ? literal2 : null;
69723
69706
  if (!tier) {
69724
69707
  fail(
69725
69708
  modelNode,
@@ -70275,7 +70258,7 @@ function agentFilePath2(projectDir, alias) {
70275
70258
  }
70276
70259
  var CLI_AGENT_NOTES = [
70277
70260
  "Pulled from the LIVE app row; edit here, then: lotics app agent set <alias>",
70278
- "The typed fields (inputs/outputs/tool_names/model_id) live in package.json#lotics.agents"
70261
+ "The typed fields (inputs/outputs/tool_names/model_tier) live in package.json#lotics.agents"
70279
70262
  ];
70280
70263
  function writeAgentFile(projectDir, alias, instructions) {
70281
70264
  fs4.mkdirSync(path5.join(projectDir, AGENTS_DIR), { recursive: true });
@@ -71446,7 +71429,7 @@ async function appAgentSet(client, args) {
71446
71429
  process.exit(1);
71447
71430
  }
71448
71431
  console.error(
71449
- `Set agent "${args.alias}" (${instructions.length} chars of instructions` + (live.model_id ? `, ${live.model_id}` : "") + `). Typed fields left as they are.`
71432
+ `Set agent "${args.alias}" (${instructions.length} chars of instructions` + (live.model_tier ? `, ${live.model_tier}` : "") + `). Typed fields left as they are.`
71450
71433
  );
71451
71434
  }
71452
71435
  async function appWorkflowSet(client, args) {
@@ -233,7 +233,7 @@ export declare class LoticsClient {
233
233
  agents?: Record<string, {
234
234
  instructions?: string;
235
235
  tool_names?: string[];
236
- model_id?: string;
236
+ model_tier?: string;
237
237
  inputs?: Record<string, unknown>;
238
238
  outputs?: Record<string, unknown>;
239
239
  }> | null;
@@ -29,7 +29,7 @@ Per-command syntax, flags, contracts, and gotchas for the public `lotics` CLI. S
29
29
  | `lotics knowledge update <id> [--from <file.md> \| --content <str>] [--name <n>] [--description <d>]` | Call `update_knowledge` with **only** the provided fields (a body from --from/--content becomes `content`; the tool diffs + CASes the content change internally, so the CLI passes no `expected_content_file_id`). At least one field required; --from and --content are mutually exclusive. |
30
30
  | `lotics knowledge rm <id>` | Archive the doc via `delete_knowledge` (`{ knowledge_doc_id }`). The REST execute path does not gate `needsApproval`, so this runs unattended. |
31
31
  | `lotics app create <name> [path]` | Scaffold a Vite+React+TS custom-code app project; POST /v1/apps; npm install; vite build; upload as v1 |
32
- | `lotics app pull <app_id> [path]` | Download source archive from R2 (presigned), extract, npm install, stamp package.json's `lotics` field. With no `[path]`: refresh the cwd IN PLACE when it's already this app's own project (its manifest `app_id` matches — the documented `cd <app> && lotics app pull` flow), else clone into an `<name>/` subdir; this avoids the stray nested `./<name>/` subdir a pull-from-inside-the-app used to drop. — `workflows` and `agents` are sourced from the live App row (NOT the archived manifest), so `set_app_workflow` / `set_app_agent` authoring survives the pull. Regenerates `.lotics/app_{workflows,queries,agents}.d.ts` so `useWorkflow` / `useQuery` / `useAgentRun` stay typed, AND the runtime `.lotics/app_fields.ts` (the same linked-vs-bespoke branch `app codegen` runs, off the app row already fetched — see that row for the two forms). That one is not optional: `app deploy` tars source with `--exclude=.lotics`, so no archive can carry it, and a pulled project whose `src/` imports `F`/`OPT` would fail to build with `Could not resolve "../../.lotics/app_fields"` until `app codegen` was run by hand. The write NAMES the form and the reason, because an in-place pull can FLIP a project between them (`opctl app publish` links an origin, `package eject` unlinks it) and that changes what the module does at load. Skipped under `--view-as` (the schema is read as that member and silently drops tables they cannot see — a narrowed `F` map compiles and then throws at runtime, worse than the missing module). A binding/schema fetch failure is non-fatal and names the right recovery for what is on disk: an existing file is kept, an ABSENT one warns about the build error and points at `app codegen`. Pull GENERATES but never RECONCILES `.lotics/` — deleting a companion whose alias the manifest no longer declares is `app codegen`'s alone, since pull's authority is the server's alias set and a declared-but-not-yet-`set` alias is supported. Also writes one `src/workflows/<alias>.ts` per bound workflow (faithful body from `get_app_workflow`) and one `src/agents/<alias>.md` per bound agent (its instructions, straight off the live row) — so the prose an author actually edits lives in a file, and pull always overwrites it from live, leaving no second copy to drift. A legacy workflow alias with no rendered source, or an agent with no instructions, warns and is skipped. The stamped `lotics.agents` map carries the TYPED half only (`inputs`/`outputs`/`tool_names`/`model_id`/…) — an agent's prose lives solely in its `.md`, so there is never a second local copy to desync; a stale `instructions` left by an older CLI is inert and disappears on the next pull |
32
+ | `lotics app pull <app_id> [path]` | Download source archive from R2 (presigned), extract, npm install, stamp package.json's `lotics` field. With no `[path]`: refresh the cwd IN PLACE when it's already this app's own project (its manifest `app_id` matches — the documented `cd <app> && lotics app pull` flow), else clone into an `<name>/` subdir; this avoids the stray nested `./<name>/` subdir a pull-from-inside-the-app used to drop. — `workflows` and `agents` are sourced from the live App row (NOT the archived manifest), so `set_app_workflow` / `set_app_agent` authoring survives the pull. Regenerates `.lotics/app_{workflows,queries,agents}.d.ts` so `useWorkflow` / `useQuery` / `useAgentRun` stay typed, AND the runtime `.lotics/app_fields.ts` (the same linked-vs-bespoke branch `app codegen` runs, off the app row already fetched — see that row for the two forms). That one is not optional: `app deploy` tars source with `--exclude=.lotics`, so no archive can carry it, and a pulled project whose `src/` imports `F`/`OPT` would fail to build with `Could not resolve "../../.lotics/app_fields"` until `app codegen` was run by hand. The write NAMES the form and the reason, because an in-place pull can FLIP a project between them (`opctl app publish` links an origin, `package eject` unlinks it) and that changes what the module does at load. Skipped under `--view-as` (the schema is read as that member and silently drops tables they cannot see — a narrowed `F` map compiles and then throws at runtime, worse than the missing module). A binding/schema fetch failure is non-fatal and names the right recovery for what is on disk: an existing file is kept, an ABSENT one warns about the build error and points at `app codegen`. Pull GENERATES but never RECONCILES `.lotics/` — deleting a companion whose alias the manifest no longer declares is `app codegen`'s alone, since pull's authority is the server's alias set and a declared-but-not-yet-`set` alias is supported. Also writes one `src/workflows/<alias>.ts` per bound workflow (faithful body from `get_app_workflow`) and one `src/agents/<alias>.md` per bound agent (its instructions, straight off the live row) — so the prose an author actually edits lives in a file, and pull always overwrites it from live, leaving no second copy to drift. A legacy workflow alias with no rendered source, or an agent with no instructions, warns and is skipped. The stamped `lotics.agents` map carries the TYPED half only (`inputs`/`outputs`/`tool_names`/`model_tier`/…) — an agent's prose lives solely in its `.md`, so there is never a second local copy to desync; a stale `instructions` left by an older CLI is inert and disappears on the next pull |
33
33
  | `lotics app deploy -m <message>` | **`-m` is REQUIRED** (CLI errors without a non-empty message) — each deploy is a version row read back by `lotics app versions`, so a blank message loses the audit trail. npm run build; tar source + dist; POST /v1/apps/{id}/versions multipart. Carries code + capabilities only — **neither queries nor workflow/agent bindings are a deploy concern** (`set_app_workflow` / `remove_app_workflow` own `apps.workflows`; the manifest's `workflows` map is a pulled reflection, read by `useWorkflow` codegen and by `app workflow set`, never written by a deploy). Deploy DOES send the manifest's `lotics.workflows` alias KEYS (not the bindings) as `workflow_aliases`, recorded on the version row so `remove_app_workflow` can refuse to unbind an alias the served version still declares. It also reports any `lotics.queries` alias whose declaration DIFFERS from the app's, naming both recoveries (`app query set --all` to push yours, `app pull` to adopt the app's) — a deploy no longer writes them, so the two are allowed to drift. After a successful deploy it **warns loudly about any alias the source CALLS that is NOT bound on the server** (a `getApp` diff via `warnIfUnboundAliases`) — since deploy never binds them, that would otherwise throw only at the app's first `useWorkflow` / `useAgentRun` call; the warning points to `lotics app workflow set` / `set_app_agent`. Advisory only (never fails the deploy). |
34
34
  | `lotics app versions [app_id]` | `GET /v1/apps/{id}/versions` — print deploy history newest-first (version number, timestamp, deployer name, build status, the `-m` message; `*` marks the currently-served version). app_id from the local manifest, or pass one to inspect any app without pulling it. Admin-only server-side (mirrors deploy + source download). Answers "what shipped, when, by whom" — e.g. whether a fix was live at an incident's time. The deploy pipeline already persisted all of this in `app_versions`; this is the read surface. Title → stderr, table → stdout (pipeable). |
35
35
  | `lotics app codegen [path]` | Regenerate `.lotics/*` from the manifest + workspace schema **without a deploy**. The three `.d.ts` companions (`app_{workflows,queries,agents}.d.ts`) are always rewritten (synchronous, no network). When credentials resolve, also rewrites the **runtime** `.lotics/app_fields.ts` — **branched on whether the app is a package installation** (`getApp().package_id` set, from `generate_package_fields.ts`): a **linked/published** app emits the BINDING form (`F`/`OPT`/`ROLE` resolved from the installation's LIVE binding — via `appBinding` / the `binding` RPC — at module load through `getAppBinding()` + top-level await, so the source stays portable across every install); a **bespoke** app emits the BAKED form (`generate_app_fields.ts`) — a real `.ts` exporting `F` (table→field→`"fld_…"`) + `OPT` (table→select-field→option→`"opt_…"`) keyed by display-name aliases, for the tables the app's queries reference (+ optional `package.json#lotics.codegen.tables` allowlist). Both forms share the `F`/`OPT` shape (contract aliases derive from the same slugified display names), so a published origin's deployed source compiles unchanged. Writing the BINDING form also heals the project's vitest setup (`ensureAppVitestSetup`, folded into the same write boundary): the binding form awaits `getAppBinding()` (a network call) at module load, so without a stub `npm test` fails to collect any test that imports the app graph — the heal writes `vitest.setup.ts` (mocks only `getAppBinding`, returning an echo binding: any alias → a self-identifying `fld:test:…`/`opt:test:…`/`grp:test:…` id) if absent, and warns the one-liner to add to `vite.config.ts`'s `test.setupFiles` if the wiring is missing (TS source isn't safely munged, mirroring `ensureAppTsconfig`'s JSONC-tsconfig warn). New scaffolds ship both. Also refreshes each bound workflow's `.lotics/workflows/<alias>.globals.d.ts` + re-wraps its EXISTING `src/workflows/<alias>.ts` body in the current envelope (strips + re-wraps; never re-fetches the body, so local edits survive). **`.lotics/` is reconciled to the manifest, not merely added to** — a `<alias>.globals.d.ts` whose alias the manifest no longer declares is DELETED (that directory is read as the app's alias inventory, so a companion for a binding nobody can reach misreports what the app has). Only that exact filename shape is removed; anything else in the directory is left alone. The reconcile runs before the credential branch, so it happens offline too. The authored counterpart is never deleted — a `src/workflows/<alias>.ts` the manifest does not declare is NAMED instead (`check` and `set` both take their alias set from the manifest, so editing an undeclared body is a silent no-op). A getApp / binding / schema / dts-fetch failure is non-fatal (warns, keeps the last-generated files). **Re-silvers `package.json#lotics.agents`** from the live app row whenever its `inputs`/`outputs` disagree, then rewrites the agent `.d.ts` from the refreshed block: that block is a mirror AND the offline seed for `useAgentRun` typings, so a stale copy types the app against an agent that does not exist. Refreshing here makes the divergence self-healing on a command already in the loop and keeps the remedy off `app pull` (which rewrites `src/workflows/*.ts` and would eat uncommitted body edits). The write is surgical and order-preserving (`orderedLike`), so it changes only the fields that actually differ. A hand edit to that block is therefore reverted — it never changed the agent anyway; to change one, `set_app_agent`. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.113.0",
3
+ "version": "0.114.0",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {