@lumerahq/cli 0.19.14 → 0.19.15

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/index.js CHANGED
@@ -219,25 +219,25 @@ async function main() {
219
219
  switch (command) {
220
220
  // Resource commands
221
221
  case "plan":
222
- await import("./resources-UZ3TNZ4K.js").then((m) => m.plan(args.slice(1)));
222
+ await import("./resources-3XXGL25Z.js").then((m) => m.plan(args.slice(1)));
223
223
  break;
224
224
  case "apply":
225
- await import("./resources-UZ3TNZ4K.js").then((m) => m.apply(args.slice(1)));
225
+ await import("./resources-3XXGL25Z.js").then((m) => m.apply(args.slice(1)));
226
226
  break;
227
227
  case "pull":
228
- await import("./resources-UZ3TNZ4K.js").then((m) => m.pull(args.slice(1)));
228
+ await import("./resources-3XXGL25Z.js").then((m) => m.pull(args.slice(1)));
229
229
  break;
230
230
  case "destroy":
231
- await import("./resources-UZ3TNZ4K.js").then((m) => m.destroy(args.slice(1)));
231
+ await import("./resources-3XXGL25Z.js").then((m) => m.destroy(args.slice(1)));
232
232
  break;
233
233
  case "list":
234
- await import("./resources-UZ3TNZ4K.js").then((m) => m.list(args.slice(1)));
234
+ await import("./resources-3XXGL25Z.js").then((m) => m.list(args.slice(1)));
235
235
  break;
236
236
  case "show":
237
- await import("./resources-UZ3TNZ4K.js").then((m) => m.show(args.slice(1)));
237
+ await import("./resources-3XXGL25Z.js").then((m) => m.show(args.slice(1)));
238
238
  break;
239
239
  case "diff":
240
- await import("./resources-UZ3TNZ4K.js").then((m) => m.diff(args.slice(1)));
240
+ await import("./resources-3XXGL25Z.js").then((m) => m.diff(args.slice(1)));
241
241
  break;
242
242
  // Development
243
243
  case "dev":
@@ -34,12 +34,67 @@ import { join as join2, resolve } from "path";
34
34
 
35
35
  // src/lib/lint/index.ts
36
36
  import { existsSync, readFileSync, readdirSync } from "fs";
37
- import { basename, join } from "path";
37
+ import { basename, dirname, join } from "path";
38
38
 
39
- // src/lib/lint/rules/collection-schema.ts
39
+ // src/lib/lint/rules/automation-config.ts
40
40
  function isRecord(value) {
41
41
  return typeof value === "object" && value !== null && !Array.isArray(value);
42
42
  }
43
+ function warn(target, message) {
44
+ return {
45
+ ruleId: "automation-config",
46
+ target,
47
+ severity: "warning",
48
+ message
49
+ };
50
+ }
51
+ var automationConfigRule = {
52
+ id: "automation-config",
53
+ description: "Validates that automation config.json input schema uses the function-wrapped format the Run UI expects.",
54
+ appliesTo: ["automation"],
55
+ check(target) {
56
+ const schema = target.config;
57
+ const at = typeof target.configFilePath === "string" ? { ...target, filePath: target.configFilePath } : target;
58
+ if (schema === void 0 || schema === null) return [];
59
+ if (!isRecord(schema)) {
60
+ return [warn(at, 'config.json "inputs.schema" must be a JSON object.')];
61
+ }
62
+ const issues = [];
63
+ if (schema.type !== "function") {
64
+ issues.push(
65
+ warn(
66
+ at,
67
+ 'config.json "inputs.schema" is missing `"type": "function"`. Without it the Run-Automation UI shows "requires no inputs". Wrap it as { "type": "function", "function": { "name": "main", "parameters": { \u2026 } } }.'
68
+ )
69
+ );
70
+ }
71
+ const fn = schema.function;
72
+ if (!isRecord(fn)) {
73
+ issues.push(warn(at, 'config.json "inputs.schema.function" object is missing.'));
74
+ return issues;
75
+ }
76
+ if (typeof fn.name !== "string" || fn.name.trim() === "") {
77
+ issues.push(warn(at, 'config.json "inputs.schema.function.name" should be the entry-point function name (usually "main").'));
78
+ }
79
+ const params = fn.parameters;
80
+ if (!isRecord(params)) {
81
+ issues.push(warn(at, 'config.json "inputs.schema.function.parameters" object is missing.'));
82
+ } else {
83
+ if (params.type !== "object") {
84
+ issues.push(warn(at, 'config.json "inputs.schema.function.parameters.type" should be "object".'));
85
+ }
86
+ if (!isRecord(params.properties)) {
87
+ issues.push(warn(at, 'config.json "inputs.schema.function.parameters.properties" object is missing.'));
88
+ }
89
+ }
90
+ return issues;
91
+ }
92
+ };
93
+
94
+ // src/lib/lint/rules/collection-schema.ts
95
+ function isRecord2(value) {
96
+ return typeof value === "object" && value !== null && !Array.isArray(value);
97
+ }
43
98
  function error(target, message, snippet) {
44
99
  return {
45
100
  ruleId: "collection-schema",
@@ -61,7 +116,7 @@ var collectionSchemaRule = {
61
116
  const message = err instanceof Error ? err.message : String(err);
62
117
  return [error(target, `Invalid JSON: ${message}`)];
63
118
  }
64
- if (!isRecord(parsed)) {
119
+ if (!isRecord2(parsed)) {
65
120
  return [error(target, "Collection file must contain a JSON object.")];
66
121
  }
67
122
  const issues = [];
@@ -83,11 +138,12 @@ var collectionSchemaRule = {
83
138
  }
84
139
  }
85
140
  if (!Array.isArray(fields)) {
86
- issues.push(error(target, 'Missing required array field "fields".'));
141
+ const hint = Array.isArray(parsed.schema) ? ' Use "fields" (not "schema") for the field array \u2014 the JSON file format differs from the pb.ensure_collection() SDK shape. Use [] when the collection has no fields.' : " It must be an array (use [] when the collection has no fields).";
142
+ issues.push(error(target, `Missing required array field "fields".${hint}`));
87
143
  } else {
88
144
  for (let i = 0; i < fields.length; i++) {
89
145
  const field = fields[i];
90
- if (!isRecord(field)) {
146
+ if (!isRecord2(field)) {
91
147
  issues.push(error(target, `Field at index ${i} must be an object.`));
92
148
  continue;
93
149
  }
@@ -105,8 +161,9 @@ var collectionSchemaRule = {
105
161
  } else {
106
162
  for (let i = 0; i < indexes.length; i++) {
107
163
  const index = indexes[i];
108
- if (!isRecord(index)) {
109
- issues.push(error(target, `Index at index ${i} must be an object.`));
164
+ if (!isRecord2(index)) {
165
+ const hint = typeof index === "string" ? ' Indexes are objects like { "fields": ["title"], "unique": true }, not CREATE INDEX SQL strings.' : "";
166
+ issues.push(error(target, `Index at index ${i} must be an object.${hint}`));
110
167
  continue;
111
168
  }
112
169
  if (!Array.isArray(index.fields) || !index.fields.every((field) => typeof field === "string" && field.trim() !== "")) {
@@ -498,7 +555,7 @@ var llmImportRule = {
498
555
  };
499
556
 
500
557
  // src/lib/lint/registry.ts
501
- var ALL_RULES = [collectionSchemaRule, hookVerifyRule, llmImportRule];
558
+ var ALL_RULES = [automationConfigRule, collectionSchemaRule, hookVerifyRule, llmImportRule];
502
559
 
503
560
  // src/lib/lint/format.ts
504
561
  import { relative } from "path";
@@ -565,7 +622,10 @@ function buildAutomationTargets(localAutomations) {
565
622
  kind: "automation",
566
623
  name: a.automation.external_id,
567
624
  filePath: a.filePath,
568
- source: a.code
625
+ source: a.code,
626
+ config: a.automation.inputs?.schema,
627
+ // a.filePath is main.py; config.json is its sibling.
628
+ configFilePath: join(dirname(a.filePath), "config.json")
569
629
  }));
570
630
  }
571
631
  function buildCollectionTargets(platformDir, _filterName) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.19.14",
3
+ "version": "0.19.15",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {