@lumerahq/cli 0.19.1 → 0.19.2

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.
@@ -25,12 +25,129 @@ import {
25
25
  import "./chunk-PNKVD2UK.js";
26
26
 
27
27
  // src/commands/resources.ts
28
- import pc from "picocolors";
28
+ import pc2 from "picocolors";
29
29
  import prompts from "prompts";
30
30
  import { execFileSync, execSync } from "child_process";
31
31
  import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync } from "fs";
32
32
  import { join, resolve } from "path";
33
+
34
+ // src/lib/lint/rules/llm-import.ts
35
+ var FROM_LUMERA_IMPORT_LLM = /^\s*from\s+lumera\s+import\s+\(?\s*(?:[\w\s,]*?\b)?llm\b/;
36
+ var LUMERA_LLM_SUBMODULE = /^\s*(?:from\s+lumera\.llm\b|import\s+lumera\.llm\b)/;
37
+ var llmImportRule = {
38
+ id: "llm-import",
39
+ description: "Flags imports of 'lumera.llm' \u2014 prefer custom agents for LLM/agentic capabilities.",
40
+ appliesTo: ["automation"],
41
+ check(target) {
42
+ const warnings = [];
43
+ const lines = target.source.split(/\r?\n/);
44
+ let inTriple = false;
45
+ for (let i = 0; i < lines.length; i++) {
46
+ const raw = lines[i];
47
+ if (inTriple) {
48
+ if (raw.includes(inTriple)) inTriple = false;
49
+ continue;
50
+ }
51
+ const tripleMatch = raw.match(/("""|''')/);
52
+ if (tripleMatch) {
53
+ const q = tripleMatch[1];
54
+ const rest = raw.slice(raw.indexOf(q) + 3);
55
+ if (!rest.includes(q)) {
56
+ inTriple = q;
57
+ continue;
58
+ }
59
+ }
60
+ const trimmed = raw.trimStart();
61
+ if (trimmed.startsWith("#")) continue;
62
+ if (FROM_LUMERA_IMPORT_LLM.test(raw) || LUMERA_LLM_SUBMODULE.test(raw)) {
63
+ warnings.push({
64
+ ruleId: "llm-import",
65
+ target,
66
+ line: i + 1,
67
+ snippet: raw.trim(),
68
+ message: "Imports 'lumera.llm'. Prefer a custom agent for LLM/agentic capabilities in new automations."
69
+ });
70
+ }
71
+ }
72
+ return warnings;
73
+ }
74
+ };
75
+
76
+ // src/lib/lint/registry.ts
77
+ var ALL_RULES = [llmImportRule];
78
+
79
+ // src/lib/lint/format.ts
80
+ import { relative } from "path";
81
+ import pc from "picocolors";
82
+ function printLintWarnings(warnings, projectRoot) {
83
+ if (warnings.length === 0) return;
84
+ console.log();
85
+ console.log(pc.bold(" Warnings:"));
86
+ for (const w of warnings) {
87
+ const rel = relative(projectRoot, w.target.filePath);
88
+ const loc = w.line ? `${rel}:${w.line}` : rel;
89
+ console.log(` ${pc.yellow("\u26A0")} ${loc} ${pc.dim(`[${w.ruleId}]`)}`);
90
+ console.log(` ${w.message}`);
91
+ if (w.snippet) console.log(pc.dim(` > ${w.snippet}`));
92
+ }
93
+ console.log();
94
+ const n = warnings.length;
95
+ console.log(pc.dim(` ${n} warning${n === 1 ? "" : "s"} \u2014 advisory, will not block apply.`));
96
+ console.log();
97
+ }
98
+ function serializeLintWarnings(warnings, projectRoot) {
99
+ return warnings.map((w) => ({
100
+ ruleId: w.ruleId,
101
+ target: { kind: w.target.kind, name: w.target.name, filePath: relative(projectRoot, w.target.filePath) },
102
+ message: w.message,
103
+ line: w.line,
104
+ snippet: w.snippet
105
+ }));
106
+ }
107
+
108
+ // src/lib/lint/index.ts
109
+ function runLint(ctx) {
110
+ const out = [];
111
+ for (const rule of ALL_RULES) {
112
+ for (const t of ctx.targets) {
113
+ if (!rule.appliesTo.includes(t.kind)) continue;
114
+ try {
115
+ out.push(...rule.check(t, ctx));
116
+ } catch (err) {
117
+ if (process.env.LUMERA_DEBUG) {
118
+ console.error(`[lint] rule "${rule.id}" threw on ${t.filePath}:`, err);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ return out;
124
+ }
125
+ function buildAutomationTargets(localAutomations) {
126
+ return localAutomations.map((a) => ({
127
+ kind: "automation",
128
+ name: a.automation.external_id,
129
+ filePath: a.filePath,
130
+ source: a.code
131
+ }));
132
+ }
133
+
134
+ // src/commands/resources.ts
33
135
  init_auth();
136
+ function safeLint(projectRoot, localAutomations) {
137
+ try {
138
+ return runLint({ projectRoot, targets: buildAutomationTargets(localAutomations) });
139
+ } catch (err) {
140
+ if (process.env.LUMERA_DEBUG) console.error("[lint] pass failed:", err);
141
+ return [];
142
+ }
143
+ }
144
+ function safePrintLint(warnings, projectRoot) {
145
+ try {
146
+ printLintWarnings(warnings, projectRoot);
147
+ } catch (err) {
148
+ if (process.env.LUMERA_DEBUG) console.error("[lint] print failed:", err);
149
+ }
150
+ }
34
151
  function detectPackageManager() {
35
152
  for (const pm of ["bun", "pnpm", "yarn", "npm"]) {
36
153
  try {
@@ -267,13 +384,13 @@ function normalizeLocalAutomation(config) {
267
384
  }
268
385
  function showPlanHelp() {
269
386
  console.log(`
270
- ${pc.dim("Usage:")}
387
+ ${pc2.dim("Usage:")}
271
388
  lumera plan [resource]
272
389
 
273
- ${pc.dim("Description:")}
390
+ ${pc2.dim("Description:")}
274
391
  Preview changes between local files and remote state.
275
392
 
276
- ${pc.dim("Resources:")}
393
+ ${pc2.dim("Resources:")}
277
394
  (none) Plan all resources
278
395
  collections Plan only collections
279
396
  collections/<name> Plan single collection
@@ -286,7 +403,7 @@ ${pc.dim("Resources:")}
286
403
  mailboxes/<slug> Plan single mailbox
287
404
  app Plan app deployment
288
405
 
289
- ${pc.dim("Examples:")}
406
+ ${pc2.dim("Examples:")}
290
407
  lumera plan # Plan all resources
291
408
  lumera plan collections # Plan only collections
292
409
  lumera plan automations/sync # Plan single automation
@@ -295,13 +412,13 @@ ${pc.dim("Examples:")}
295
412
  }
296
413
  function showApplyHelp() {
297
414
  console.log(`
298
- ${pc.dim("Usage:")}
415
+ ${pc2.dim("Usage:")}
299
416
  lumera apply [resource]
300
417
 
301
- ${pc.dim("Description:")}
418
+ ${pc2.dim("Description:")}
302
419
  Create or update resources from local files.
303
420
 
304
- ${pc.dim("Resources:")}
421
+ ${pc2.dim("Resources:")}
305
422
  (none) Apply all resources
306
423
  collections Apply only collections
307
424
  collections/<name> Apply single collection
@@ -314,11 +431,11 @@ ${pc.dim("Resources:")}
314
431
  mailboxes/<slug> Apply single mailbox
315
432
  app Deploy the frontend app
316
433
 
317
- ${pc.dim("Options:")}
434
+ ${pc2.dim("Options:")}
318
435
  --yes, -y Skip confirmation prompt (for CI/CD)
319
436
  --skip-build Skip build step when applying app
320
437
 
321
- ${pc.dim("Examples:")}
438
+ ${pc2.dim("Examples:")}
322
439
  lumera apply # Apply everything (shows plan, asks to confirm)
323
440
  lumera apply collections # Apply all collections
324
441
  lumera apply collections/users # Apply single collection
@@ -329,18 +446,18 @@ ${pc.dim("Examples:")}
329
446
  }
330
447
  function showPullHelp() {
331
448
  console.log(`
332
- ${pc.dim("Usage:")}
449
+ ${pc2.dim("Usage:")}
333
450
  lumera pull [resource] [--force]
334
451
 
335
- ${pc.dim("Description:")}
452
+ ${pc2.dim("Description:")}
336
453
  Download remote state to local files.
337
454
  Refuses to overwrite local files that have uncommitted changes
338
455
  (use --force to override, or 'lumera diff' to inspect first).
339
456
 
340
- ${pc.dim("Options:")}
457
+ ${pc2.dim("Options:")}
341
458
  --force, -f Overwrite local files even if they have changes
342
459
 
343
- ${pc.dim("Resources:")}
460
+ ${pc2.dim("Resources:")}
344
461
  (none) Pull all resources
345
462
  collections Pull only collections
346
463
  collections/<name> Pull single collection
@@ -352,7 +469,7 @@ ${pc.dim("Resources:")}
352
469
  mailboxes Pull only mailboxes
353
470
  mailboxes/<slug> Pull single mailbox
354
471
 
355
- ${pc.dim("Examples:")}
472
+ ${pc2.dim("Examples:")}
356
473
  lumera pull # Pull all (safe \u2014 warns on conflicts)
357
474
  lumera pull agents # Pull only agents
358
475
  lumera pull --force # Pull all, overwrite local changes
@@ -361,13 +478,13 @@ ${pc.dim("Examples:")}
361
478
  }
362
479
  function showDestroyHelp() {
363
480
  console.log(`
364
- ${pc.dim("Usage:")}
481
+ ${pc2.dim("Usage:")}
365
482
  lumera destroy [resource]
366
483
 
367
- ${pc.dim("Description:")}
484
+ ${pc2.dim("Description:")}
368
485
  Delete resources from remote.
369
486
 
370
- ${pc.dim("Resources:")}
487
+ ${pc2.dim("Resources:")}
371
488
  (none) Destroy all resources
372
489
  collections Destroy only collections
373
490
  collections/<name> Destroy single collection
@@ -378,11 +495,11 @@ ${pc.dim("Resources:")}
378
495
  agents/<name> Destroy single agent
379
496
  app Delete app registration
380
497
 
381
- ${pc.dim("Options:")}
498
+ ${pc2.dim("Options:")}
382
499
  --confirm Skip confirmation prompt
383
500
  --force-cycles Remove relation fields to break circular references before deleting
384
501
 
385
- ${pc.dim("Examples:")}
502
+ ${pc2.dim("Examples:")}
386
503
  lumera destroy # Destroy everything
387
504
  lumera destroy collections/users # Destroy single collection
388
505
  lumera destroy app # Delete app registration
@@ -390,13 +507,13 @@ ${pc.dim("Examples:")}
390
507
  }
391
508
  function showListHelp() {
392
509
  console.log(`
393
- ${pc.dim("Usage:")}
510
+ ${pc2.dim("Usage:")}
394
511
  lumera list [type] [--all]
395
512
 
396
- ${pc.dim("Description:")}
513
+ ${pc2.dim("Description:")}
397
514
  List resources with status. By default, remote-only resources are hidden.
398
515
 
399
- ${pc.dim("Types:")}
516
+ ${pc2.dim("Types:")}
400
517
  (none) List all resources
401
518
  collections List only collections
402
519
  automations List only automations
@@ -404,10 +521,10 @@ ${pc.dim("Types:")}
404
521
  agents List only agents
405
522
  mailboxes List only mailboxes
406
523
 
407
- ${pc.dim("Options:")}
524
+ ${pc2.dim("Options:")}
408
525
  --all Include remote-only resources
409
526
 
410
- ${pc.dim("Examples:")}
527
+ ${pc2.dim("Examples:")}
411
528
  lumera list # List local resources
412
529
  lumera list --all # Include remote-only resources
413
530
  lumera list collections # List only collections
@@ -415,13 +532,13 @@ ${pc.dim("Examples:")}
415
532
  }
416
533
  function showShowHelp() {
417
534
  console.log(`
418
- ${pc.dim("Usage:")}
535
+ ${pc2.dim("Usage:")}
419
536
  lumera show <resource>
420
537
 
421
- ${pc.dim("Description:")}
538
+ ${pc2.dim("Description:")}
422
539
  Show details of a single resource.
423
540
 
424
- ${pc.dim("Resources:")}
541
+ ${pc2.dim("Resources:")}
425
542
  collections/<name> Show collection details
426
543
  automations/<name> Show automation details
427
544
  hooks/<name> Show hook details
@@ -429,7 +546,7 @@ ${pc.dim("Resources:")}
429
546
  mailboxes/<slug> Show mailbox details
430
547
  app Show app details
431
548
 
432
- ${pc.dim("Examples:")}
549
+ ${pc2.dim("Examples:")}
433
550
  lumera show collections/users # Show collection details
434
551
  lumera show automations/sync # Show automation details
435
552
  lumera show app # Show app details
@@ -444,7 +561,7 @@ function parseResource(resourcePath) {
444
561
  const name = parts.slice(1).join("/") || null;
445
562
  const validTypes = ["collections", "automations", "hooks", "agents", "mailboxes", "app"];
446
563
  if (!validTypes.includes(type)) {
447
- console.log(pc.red(` Unknown resource type "${type}". Valid types: ${validTypes.join(", ")}`));
564
+ console.log(pc2.red(` Unknown resource type "${type}". Valid types: ${validTypes.join(", ")}`));
448
565
  process.exit(1);
449
566
  }
450
567
  return { type, name };
@@ -509,9 +626,9 @@ function loadLocalCollections(platformDir, filterName) {
509
626
  }
510
627
  }
511
628
  if (errors.length > 0) {
512
- console.log(pc.red(" Collection errors:"));
629
+ console.log(pc2.red(" Collection errors:"));
513
630
  for (const err of errors) {
514
- console.log(pc.red(` \u2717 ${err}`));
631
+ console.log(pc2.red(` \u2717 ${err}`));
515
632
  }
516
633
  throw new Error(`Found ${errors.length} collection error(s)`);
517
634
  }
@@ -569,15 +686,15 @@ function loadLocalAutomations(platformDir, filterName, appName) {
569
686
  if (appName) {
570
687
  code = code.replaceAll("{{app}}", appName);
571
688
  }
572
- automations.push({ automation: config, code });
689
+ automations.push({ automation: config, code, filePath: mainPath });
573
690
  } catch (e) {
574
691
  errors.push(`${entry.name}: failed to parse config.json - ${e}`);
575
692
  }
576
693
  }
577
694
  if (errors.length > 0) {
578
- console.log(pc.red(" Automation errors:"));
695
+ console.log(pc2.red(" Automation errors:"));
579
696
  for (const err of errors) {
580
- console.log(pc.red(` \u2717 ${err}`));
697
+ console.log(pc2.red(` \u2717 ${err}`));
581
698
  }
582
699
  throw new Error(`Found ${errors.length} automation error(s)`);
583
700
  }
@@ -595,14 +712,14 @@ function loadLocalHooks(platformDir, filterName, appName) {
595
712
  const content = readFileSync(filePath, "utf-8");
596
713
  const config = parseHookConfig(content);
597
714
  if (!config) {
598
- console.log(pc.yellow(` \u26A0 Skipping ${file}: could not parse config export`));
715
+ console.log(pc2.yellow(` \u26A0 Skipping ${file}: could not parse config export`));
599
716
  continue;
600
717
  }
601
718
  if (!config.external_id) {
602
719
  if (appName) {
603
720
  config.external_id = `${appName}:${file.replace(/\.(js|ts)$/, "")}`;
604
721
  } else {
605
- console.log(pc.yellow(` \u26A0 Skipping ${file}: missing external_id in config`));
722
+ console.log(pc2.yellow(` \u26A0 Skipping ${file}: missing external_id in config`));
606
723
  continue;
607
724
  }
608
725
  }
@@ -917,7 +1034,7 @@ function loadLocalMailboxes(platformDir, filterName) {
917
1034
  if (!file.endsWith(".json")) continue;
918
1035
  const slug = file.replace(/\.json$/, "").trim();
919
1036
  if (!slug) {
920
- console.log(pc.yellow(` \u26A0 Skipping ${file}: empty filename`));
1037
+ console.log(pc2.yellow(` \u26A0 Skipping ${file}: empty filename`));
921
1038
  continue;
922
1039
  }
923
1040
  if (filterName && slug !== filterName) {
@@ -928,11 +1045,11 @@ function loadLocalMailboxes(platformDir, filterName) {
928
1045
  try {
929
1046
  raw = JSON.parse(readFileSync(filePath, "utf-8"));
930
1047
  } catch (e) {
931
- console.log(pc.yellow(` \u26A0 Skipping ${file}: invalid JSON (${e.message})`));
1048
+ console.log(pc2.yellow(` \u26A0 Skipping ${file}: invalid JSON (${e.message})`));
932
1049
  continue;
933
1050
  }
934
1051
  if (!isPlainObject(raw)) {
935
- console.log(pc.yellow(` \u26A0 Skipping ${file}: top-level value must be an object`));
1052
+ console.log(pc2.yellow(` \u26A0 Skipping ${file}: top-level value must be an object`));
936
1053
  continue;
937
1054
  }
938
1055
  const descriptionRaw = raw["description"];
@@ -983,17 +1100,17 @@ async function applyMailboxes(api, localMailboxes) {
983
1100
  const localDesc = (mb.description ?? "").trim();
984
1101
  const remoteDesc = (existing.description ?? "").trim();
985
1102
  if (localDesc !== remoteDesc) {
986
- console.log(pc.yellow(" \u26A0"), `mailbox ${mb.slug}: description drift not reconcilable by CLI (no PATCH endpoint yet) \u2014 update in the UI or DB`);
1103
+ console.log(pc2.yellow(" \u26A0"), `mailbox ${mb.slug}: description drift not reconcilable by CLI (no PATCH endpoint yet) \u2014 update in the UI or DB`);
987
1104
  } else {
988
- console.log(pc.green(" \u2713"), pc.dim(`mailbox ${mb.slug} already exists (${existing.email})`));
1105
+ console.log(pc2.green(" \u2713"), pc2.dim(`mailbox ${mb.slug} already exists (${existing.email})`));
989
1106
  }
990
1107
  continue;
991
1108
  }
992
1109
  try {
993
1110
  const created = await api.createMailbox({ slug: mb.slug, description: mb.description });
994
- console.log(pc.green(" \u2713"), `created mailbox ${mb.slug} ${pc.dim(`\u2192 ${created.email}`)}`);
1111
+ console.log(pc2.green(" \u2713"), `created mailbox ${mb.slug} ${pc2.dim(`\u2192 ${created.email}`)}`);
995
1112
  } catch (e) {
996
- console.log(pc.red(" \u2717"), `mailbox ${mb.slug}: ${e.message}`);
1113
+ console.log(pc2.red(" \u2717"), `mailbox ${mb.slug}: ${e.message}`);
997
1114
  errors++;
998
1115
  }
999
1116
  }
@@ -1002,7 +1119,7 @@ async function applyMailboxes(api, localMailboxes) {
1002
1119
  async function pullMailboxes(api, platformDir, filterName) {
1003
1120
  const mailboxes = await api.listMailboxes();
1004
1121
  if (mailboxes.length === 0) {
1005
- console.log(pc.dim(" (no mailboxes)"));
1122
+ console.log(pc2.dim(" (no mailboxes)"));
1006
1123
  return;
1007
1124
  }
1008
1125
  const outDir = join(platformDir, "mailboxes");
@@ -1016,11 +1133,11 @@ async function pullMailboxes(api, platformDir, filterName) {
1016
1133
  if (mb.description) body.description = mb.description;
1017
1134
  const file = join(outDir, `${toSafeFilename(mb.slug)}.json`);
1018
1135
  writeFileSync(file, JSON.stringify(body, null, 2) + "\n");
1019
- console.log(pc.green(" \u2713"), `pulled mailbox ${mb.slug} ${pc.dim(`\u2192 ${file}`)}`);
1136
+ console.log(pc2.green(" \u2713"), `pulled mailbox ${mb.slug} ${pc2.dim(`\u2192 ${file}`)}`);
1020
1137
  count++;
1021
1138
  }
1022
1139
  if (count === 0 && filterName) {
1023
- console.log(pc.yellow(` \u26A0 mailbox '${filterName}' not found on remote`));
1140
+ console.log(pc2.yellow(` \u26A0 mailbox '${filterName}' not found on remote`));
1024
1141
  }
1025
1142
  }
1026
1143
  async function planHooks(api, localHooks, collections) {
@@ -1031,7 +1148,7 @@ async function planHooks(api, localHooks, collections) {
1031
1148
  const remote = remoteByExternalId.get(hook.external_id);
1032
1149
  const collectionId = collections.get(hook.collection);
1033
1150
  if (!collectionId) {
1034
- console.log(pc.yellow(` \u26A0 Skipping ${fileName}: collection '${hook.collection}' not found`));
1151
+ console.log(pc2.yellow(` \u26A0 Skipping ${fileName}: collection '${hook.collection}' not found`));
1035
1152
  continue;
1036
1153
  }
1037
1154
  if (!remote) {
@@ -1079,9 +1196,9 @@ async function applyCollections(api, localCollections) {
1079
1196
  for (const local of localCollections) {
1080
1197
  try {
1081
1198
  await api.ensureCollection(local.name, { id: local.id });
1082
- console.log(pc.green(" \u2713"), `${local.name}`);
1199
+ console.log(pc2.green(" \u2713"), `${local.name}`);
1083
1200
  } catch (e) {
1084
- console.log(pc.red(" \u2717"), `${local.name}: ${e}`);
1201
+ console.log(pc2.red(" \u2717"), `${local.name}: ${e}`);
1085
1202
  pass1Failed.add(local.name);
1086
1203
  errors++;
1087
1204
  }
@@ -1091,9 +1208,9 @@ async function applyCollections(api, localCollections) {
1091
1208
  const apiFormat = convertCollectionToApiFormat(local);
1092
1209
  try {
1093
1210
  await api.ensureCollection(local.name, apiFormat);
1094
- console.log(pc.green(" \u2713"), `${local.name} (schema)`);
1211
+ console.log(pc2.green(" \u2713"), `${local.name} (schema)`);
1095
1212
  } catch (e) {
1096
- console.log(pc.red(" \u2717"), `${local.name} (schema): ${e}`);
1213
+ console.log(pc2.red(" \u2717"), `${local.name} (schema): ${e}`);
1097
1214
  errors++;
1098
1215
  }
1099
1216
  }
@@ -1102,9 +1219,9 @@ async function applyCollections(api, localCollections) {
1102
1219
  const apiFormat = convertCollectionToApiFormat(local);
1103
1220
  try {
1104
1221
  await api.ensureCollection(local.name, apiFormat);
1105
- console.log(pc.green(" \u2713"), `${local.name}`);
1222
+ console.log(pc2.green(" \u2713"), `${local.name}`);
1106
1223
  } catch (e) {
1107
- console.log(pc.red(" \u2717"), `${local.name}: ${e}`);
1224
+ console.log(pc2.red(" \u2717"), `${local.name}: ${e}`);
1108
1225
  errors++;
1109
1226
  }
1110
1227
  }
@@ -1134,11 +1251,11 @@ async function applyAutomations(api, localAutomations, projectId) {
1134
1251
  if (remote) {
1135
1252
  await api.updateAutomation(remote.id, payload);
1136
1253
  automationId = remote.id;
1137
- console.log(pc.green(" \u2713"), `${automation.name} (updated)`);
1254
+ console.log(pc2.green(" \u2713"), `${automation.name} (updated)`);
1138
1255
  } else {
1139
1256
  const created = await api.createAutomation(payload);
1140
1257
  automationId = created.id;
1141
- console.log(pc.green(" \u2713"), `${automation.name} (created)`);
1258
+ console.log(pc2.green(" \u2713"), `${automation.name} (created)`);
1142
1259
  }
1143
1260
  const localPresets = automation.inputs?.presets;
1144
1261
  if (localPresets) {
@@ -1148,7 +1265,7 @@ async function applyAutomations(api, localAutomations, projectId) {
1148
1265
  await setSchedule(api, automationId, automation.schedule, localPresets || {});
1149
1266
  } else if (remote?.schedule) {
1150
1267
  await api.updateAutomation(automationId, { schedule: "", schedule_tz: "" });
1151
- console.log(pc.dim(` Cleared schedule`));
1268
+ console.log(pc2.dim(` Cleared schedule`));
1152
1269
  }
1153
1270
  if (localPresets) {
1154
1271
  const current = await api.getAutomation(automationId).catch(() => null);
@@ -1162,7 +1279,7 @@ async function applyAutomations(api, localAutomations, projectId) {
1162
1279
  }
1163
1280
  }
1164
1281
  } catch (e) {
1165
- console.log(pc.red(" \u2717"), `${automation.name}: ${e}`);
1282
+ console.log(pc2.red(" \u2717"), `${automation.name}: ${e}`);
1166
1283
  errors++;
1167
1284
  }
1168
1285
  }
@@ -1177,13 +1294,13 @@ async function syncPresets(api, automationId, localPresets) {
1177
1294
  try {
1178
1295
  if (existing) {
1179
1296
  await api.updatePreset(existing.id, { name: presetName, inputs: preset.inputs });
1180
- console.log(pc.dim(` Updated preset: ${presetName}`));
1297
+ console.log(pc2.dim(` Updated preset: ${presetName}`));
1181
1298
  } else {
1182
1299
  await api.createPreset(automationId, { name: presetName, inputs: preset.inputs });
1183
- console.log(pc.dim(` Created preset: ${presetName}`));
1300
+ console.log(pc2.dim(` Created preset: ${presetName}`));
1184
1301
  }
1185
1302
  } catch (e) {
1186
- console.log(pc.yellow(` \u26A0 Failed to sync preset ${presetName}: ${e}`));
1303
+ console.log(pc2.yellow(` \u26A0 Failed to sync preset ${presetName}: ${e}`));
1187
1304
  }
1188
1305
  }
1189
1306
  }
@@ -1198,9 +1315,9 @@ async function deleteStalePresets(api, automationId, localPresets, preservePrese
1198
1315
  }
1199
1316
  try {
1200
1317
  await api.deletePreset(remote.id);
1201
- console.log(pc.dim(` Deleted preset: ${remote.name}`));
1318
+ console.log(pc2.dim(` Deleted preset: ${remote.name}`));
1202
1319
  } catch (e) {
1203
- console.log(pc.yellow(` \u26A0 Failed to delete preset ${remote.name}: ${e}`));
1320
+ console.log(pc2.yellow(` \u26A0 Failed to delete preset ${remote.name}: ${e}`));
1204
1321
  }
1205
1322
  }
1206
1323
  }
@@ -1209,7 +1326,7 @@ async function setSchedule(api, automationId, schedule, localPresets) {
1209
1326
  const remotePresets = await api.listPresets(automationId);
1210
1327
  const preset = remotePresets.find((p) => p.name === presetName);
1211
1328
  if (!preset) {
1212
- console.log(pc.yellow(` \u26A0 Schedule preset '${schedule.preset}' not found, skipping schedule`));
1329
+ console.log(pc2.yellow(` \u26A0 Schedule preset '${schedule.preset}' not found, skipping schedule`));
1213
1330
  return;
1214
1331
  }
1215
1332
  try {
@@ -1218,9 +1335,9 @@ async function setSchedule(api, automationId, schedule, localPresets) {
1218
1335
  schedule_tz: schedule.timezone || "UTC",
1219
1336
  schedule_preset_id: preset.id
1220
1337
  });
1221
- console.log(pc.dim(` Set schedule: ${schedule.cron}`));
1338
+ console.log(pc2.dim(` Set schedule: ${schedule.cron}`));
1222
1339
  } catch (e) {
1223
- console.log(pc.yellow(` \u26A0 Failed to set schedule: ${e}`));
1340
+ console.log(pc2.yellow(` \u26A0 Failed to set schedule: ${e}`));
1224
1341
  }
1225
1342
  }
1226
1343
  async function applyHooks(api, localHooks, collections, projectId) {
@@ -1231,7 +1348,7 @@ async function applyHooks(api, localHooks, collections, projectId) {
1231
1348
  const remote = remoteByExternalId.get(hook.external_id);
1232
1349
  const collectionId = collections.get(hook.collection);
1233
1350
  if (!collectionId) {
1234
- console.log(pc.red(` \u2717 ${fileName}: collection '${hook.collection}' not found. Apply the collection first or use 'lumera apply' to apply all resources.`));
1351
+ console.log(pc2.red(` \u2717 ${fileName}: collection '${hook.collection}' not found. Apply the collection first or use 'lumera apply' to apply all resources.`));
1235
1352
  errors++;
1236
1353
  continue;
1237
1354
  }
@@ -1250,13 +1367,13 @@ async function applyHooks(api, localHooks, collections, projectId) {
1250
1367
  try {
1251
1368
  if (remote) {
1252
1369
  await api.updateHook(remote.id, payload);
1253
- console.log(pc.green(" \u2713"), `${payload.name} (updated)`);
1370
+ console.log(pc2.green(" \u2713"), `${payload.name} (updated)`);
1254
1371
  } else {
1255
1372
  await api.createHook(payload);
1256
- console.log(pc.green(" \u2713"), `${payload.name} (created)`);
1373
+ console.log(pc2.green(" \u2713"), `${payload.name} (created)`);
1257
1374
  }
1258
1375
  } catch (e) {
1259
- console.log(pc.red(" \u2717"), `${payload.name}: ${e}`);
1376
+ console.log(pc2.red(" \u2717"), `${payload.name}: ${e}`);
1260
1377
  errors++;
1261
1378
  }
1262
1379
  }
@@ -1271,7 +1388,7 @@ async function applyApp(args) {
1271
1388
  const appTitle = getAppTitle(projectRoot);
1272
1389
  const apiUrl = getApiUrl();
1273
1390
  if (!skipBuild) {
1274
- console.log(pc.dim(" Building..."));
1391
+ console.log(pc2.dim(" Building..."));
1275
1392
  try {
1276
1393
  const pm = detectPackageManager();
1277
1394
  execSync(`${pm} run build`, { cwd: projectRoot, stdio: "inherit" });
@@ -1329,7 +1446,7 @@ async function pullCollections(api, platformDir, filterName, appName) {
1329
1446
  const fileName = toSafeFilename(localName);
1330
1447
  const filePath = join(collectionsDir, `${fileName}.json`);
1331
1448
  writeFileSync(filePath, JSON.stringify(localFormat, null, 2) + "\n");
1332
- console.log(pc.green(" \u2713"), `${localName} \u2192 collections/${fileName}.json`);
1449
+ console.log(pc2.green(" \u2713"), `${localName} \u2192 collections/${fileName}.json`);
1333
1450
  }
1334
1451
  }
1335
1452
  async function pullAutomations(api, platformDir, filterName, projectId) {
@@ -1379,7 +1496,7 @@ async function pullAutomations(api, platformDir, filterName, projectId) {
1379
1496
  }
1380
1497
  writeFileSync(join(automationDir, "config.json"), JSON.stringify(config, null, 2) + "\n");
1381
1498
  writeFileSync(join(automationDir, "main.py"), automation.code || "");
1382
- console.log(pc.green(" \u2713"), `${automation.name} \u2192 automations/${dirName}/`);
1499
+ console.log(pc2.green(" \u2713"), `${automation.name} \u2192 automations/${dirName}/`);
1383
1500
  }
1384
1501
  }
1385
1502
  async function pullHooks(api, platformDir, filterName, appName, projectId) {
@@ -1406,7 +1523,7 @@ ${hook.script.split("\n").map((line) => " " + line).join("\n")}
1406
1523
  }
1407
1524
  `;
1408
1525
  writeFileSync(join(hooksDir, fileName), content);
1409
- console.log(pc.green(" \u2713"), `${hook.name} \u2192 hooks/${fileName}`);
1526
+ console.log(pc2.green(" \u2713"), `${hook.name} \u2192 hooks/${fileName}`);
1410
1527
  }
1411
1528
  }
1412
1529
  function loadLocalAgents(platformDir, filterName, appName) {
@@ -1435,7 +1552,7 @@ function loadLocalAgents(platformDir, filterName, appName) {
1435
1552
  }
1436
1553
  if (config.mcp_servers !== void 0) {
1437
1554
  console.log(
1438
- pc.yellow(
1555
+ pc2.yellow(
1439
1556
  ` \u26A0 ${entry.name}: "mcp_servers" is deprecated and ignored \u2014 MCP servers are now scoped per project in Platform \u2192 Integrations.`
1440
1557
  )
1441
1558
  );
@@ -1464,9 +1581,9 @@ function loadLocalAgents(platformDir, filterName, appName) {
1464
1581
  }
1465
1582
  }
1466
1583
  if (errors.length > 0) {
1467
- console.log(pc.red(" Agent errors:"));
1584
+ console.log(pc2.red(" Agent errors:"));
1468
1585
  for (const err of errors) {
1469
- console.log(pc.red(` \u2717 ${err}`));
1586
+ console.log(pc2.red(` \u2717 ${err}`));
1470
1587
  }
1471
1588
  throw new Error(`Found ${errors.length} agent error(s)`);
1472
1589
  }
@@ -1539,7 +1656,7 @@ async function applyAgents(api, localAgents, projectId) {
1539
1656
  const skills = await api.listAgentSkills();
1540
1657
  skillMap = new Map(skills.map((s) => [s.slug, s.id]));
1541
1658
  } catch (e) {
1542
- console.log(pc.yellow(` \u26A0 Could not fetch skills for resolution: ${e}`));
1659
+ console.log(pc2.yellow(` \u26A0 Could not fetch skills for resolution: ${e}`));
1543
1660
  }
1544
1661
  }
1545
1662
  for (const { agent, systemPrompt, policyScript } of localAgents) {
@@ -1551,7 +1668,7 @@ async function applyAgents(api, localAgents, projectId) {
1551
1668
  if (id) {
1552
1669
  skillIds.push(id);
1553
1670
  } else {
1554
- console.log(pc.yellow(` \u26A0 Skill "${slug}" not found, skipping`));
1671
+ console.log(pc2.yellow(` \u26A0 Skill "${slug}" not found, skipping`));
1555
1672
  }
1556
1673
  }
1557
1674
  }
@@ -1569,14 +1686,14 @@ async function applyAgents(api, localAgents, projectId) {
1569
1686
  try {
1570
1687
  if (remote) {
1571
1688
  await api.updateAgent(remote.id, payload);
1572
- console.log(pc.green(" \u2713"), `${agent.name} (updated)`);
1689
+ console.log(pc2.green(" \u2713"), `${agent.name} (updated)`);
1573
1690
  } else {
1574
1691
  if (projectId) payload.project_id = projectId;
1575
1692
  await api.createAgent(payload);
1576
- console.log(pc.green(" \u2713"), `${agent.name} (created)`);
1693
+ console.log(pc2.green(" \u2713"), `${agent.name} (created)`);
1577
1694
  }
1578
1695
  } catch (e) {
1579
- console.log(pc.red(" \u2717"), `${agent.name}: ${e}`);
1696
+ console.log(pc2.red(" \u2717"), `${agent.name}: ${e}`);
1580
1697
  errors++;
1581
1698
  }
1582
1699
  }
@@ -1620,7 +1737,7 @@ async function pullAgents(api, platformDir, filterName, projectId) {
1620
1737
  if (agent.policy_script) {
1621
1738
  writeFileSync(join(agentDir, "policy.js"), agent.policy_script);
1622
1739
  }
1623
- console.log(pc.green(" \u2713"), `${agent.name} \u2192 agents/${dirName}/`);
1740
+ console.log(pc2.green(" \u2713"), `${agent.name} \u2192 agents/${dirName}/`);
1624
1741
  }
1625
1742
  }
1626
1743
  async function listResources(api, platformDir, filterType, appName, projectId) {
@@ -1886,13 +2003,13 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
1886
2003
  }
1887
2004
  }
1888
2005
  if (toDelete.length === 0) {
1889
- console.log(pc.green(" \u2713 No resources found to delete"));
2006
+ console.log(pc2.green(" \u2713 No resources found to delete"));
1890
2007
  return;
1891
2008
  }
1892
- console.log(pc.bold(" Resources to delete:"));
2009
+ console.log(pc2.bold(" Resources to delete:"));
1893
2010
  console.log();
1894
2011
  for (const item of toDelete) {
1895
- console.log(pc.red(` - ${item.type}: ${item.name}`));
2012
+ console.log(pc2.red(` - ${item.type}: ${item.name}`));
1896
2013
  }
1897
2014
  console.log();
1898
2015
  if (!skipConfirm) {
@@ -1903,7 +2020,7 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
1903
2020
  initial: false
1904
2021
  });
1905
2022
  if (!confirmed) {
1906
- console.log(pc.dim(" Cancelled"));
2023
+ console.log(pc2.dim(" Cancelled"));
1907
2024
  return;
1908
2025
  }
1909
2026
  }
@@ -1915,45 +2032,45 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
1915
2032
  for (const resource of agents) {
1916
2033
  try {
1917
2034
  await api.deleteAgent(resource.remoteId);
1918
- console.log(pc.green(" \u2713"), `Deleted agent: ${resource.name}`);
2035
+ console.log(pc2.green(" \u2713"), `Deleted agent: ${resource.name}`);
1919
2036
  } catch (e) {
1920
- console.log(pc.red(" \u2717"), `Failed to delete agent ${resource.name}: ${e}`);
2037
+ console.log(pc2.red(" \u2717"), `Failed to delete agent ${resource.name}: ${e}`);
1921
2038
  errors++;
1922
2039
  }
1923
2040
  }
1924
2041
  for (const resource of hooks) {
1925
2042
  try {
1926
2043
  await api.deleteHook(resource.remoteId);
1927
- console.log(pc.green(" \u2713"), `Deleted hook: ${resource.name}`);
2044
+ console.log(pc2.green(" \u2713"), `Deleted hook: ${resource.name}`);
1928
2045
  } catch (e) {
1929
- console.log(pc.red(" \u2717"), `Failed to delete hook ${resource.name}: ${e}`);
2046
+ console.log(pc2.red(" \u2717"), `Failed to delete hook ${resource.name}: ${e}`);
1930
2047
  errors++;
1931
2048
  }
1932
2049
  }
1933
2050
  for (const resource of automations) {
1934
2051
  try {
1935
2052
  await api.deleteAutomation(resource.remoteId);
1936
- console.log(pc.green(" \u2713"), `Deleted automation: ${resource.name}`);
2053
+ console.log(pc2.green(" \u2713"), `Deleted automation: ${resource.name}`);
1937
2054
  } catch (e) {
1938
- console.log(pc.red(" \u2717"), `Failed to delete automation ${resource.name}: ${e}`);
2055
+ console.log(pc2.red(" \u2717"), `Failed to delete automation ${resource.name}: ${e}`);
1939
2056
  errors++;
1940
2057
  }
1941
2058
  }
1942
2059
  const deletePlan = planCollectionDelete(collections, platformDir);
1943
2060
  if (deletePlan.cycleNames.length > 0 && !forceCycles) {
1944
2061
  console.log();
1945
- console.log(pc.yellow(" Circular references detected:"));
2062
+ console.log(pc2.yellow(" Circular references detected:"));
1946
2063
  for (const edge of deletePlan.cycleEdges) {
1947
- console.log(pc.yellow(` ${edge.from}.${edge.field} \u2192 ${edge.to}`));
2064
+ console.log(pc2.yellow(` ${edge.from}.${edge.field} \u2192 ${edge.to}`));
1948
2065
  }
1949
2066
  console.log();
1950
- console.log(pc.dim(" To destroy these, relation fields forming the cycle must be removed first."));
1951
- console.log(pc.dim(" Use --force-cycles to proceed."));
2067
+ console.log(pc2.dim(" To destroy these, relation fields forming the cycle must be removed first."));
2068
+ console.log(pc2.dim(" Use --force-cycles to proceed."));
1952
2069
  console.log();
1953
2070
  process.exit(1);
1954
2071
  }
1955
2072
  if (deletePlan.cycleNames.length > 0 && forceCycles) {
1956
- console.log(pc.dim(" Breaking circular references..."));
2073
+ console.log(pc2.dim(" Breaking circular references..."));
1957
2074
  for (const edge of deletePlan.cycleEdges) {
1958
2075
  const resource = collections.find((c) => c.name === edge.from);
1959
2076
  if (!resource?.remoteId) continue;
@@ -1963,10 +2080,10 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
1963
2080
  if (remote) {
1964
2081
  const updatedSchema = remote.schema.filter((f) => f.name !== edge.field);
1965
2082
  await api.ensureCollection(remote.name, { name: remote.name, schema: updatedSchema });
1966
- console.log(pc.green(" \u2713"), `Removed ${edge.from}.${edge.field}`);
2083
+ console.log(pc2.green(" \u2713"), `Removed ${edge.from}.${edge.field}`);
1967
2084
  }
1968
2085
  } catch (e) {
1969
- console.log(pc.red(" \u2717"), `Failed to remove ${edge.from}.${edge.field}: ${e}`);
2086
+ console.log(pc2.red(" \u2717"), `Failed to remove ${edge.from}.${edge.field}: ${e}`);
1970
2087
  errors++;
1971
2088
  }
1972
2089
  }
@@ -1974,9 +2091,9 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
1974
2091
  for (const resource of deletePlan.sorted) {
1975
2092
  try {
1976
2093
  await api.deleteCollection(resource.remoteId);
1977
- console.log(pc.green(" \u2713"), `Deleted collection: ${resource.name}`);
2094
+ console.log(pc2.green(" \u2713"), `Deleted collection: ${resource.name}`);
1978
2095
  } catch (e) {
1979
- console.log(pc.red(" \u2717"), `Failed to delete collection ${resource.name}: ${e}`);
2096
+ console.log(pc2.red(" \u2717"), `Failed to delete collection ${resource.name}: ${e}`);
1980
2097
  errors++;
1981
2098
  }
1982
2099
  }
@@ -2006,10 +2123,10 @@ async function destroyApp(skipConfirm) {
2006
2123
  const data = await searchRes.json();
2007
2124
  const appRecord = data.items?.[0];
2008
2125
  if (!appRecord) {
2009
- console.log(pc.yellow(` App "${appName}" not found in Lumera.`));
2126
+ console.log(pc2.yellow(` App "${appName}" not found in Lumera.`));
2010
2127
  return;
2011
2128
  }
2012
- console.log(pc.dim(` App to delete: ${appRecord.name} (${appRecord.external_id})`));
2129
+ console.log(pc2.dim(` App to delete: ${appRecord.name} (${appRecord.external_id})`));
2013
2130
  console.log();
2014
2131
  if (!skipConfirm) {
2015
2132
  const { confirmed } = await prompts({
@@ -2019,7 +2136,7 @@ async function destroyApp(skipConfirm) {
2019
2136
  initial: false
2020
2137
  });
2021
2138
  if (!confirmed) {
2022
- console.log(pc.dim(" Cancelled"));
2139
+ console.log(pc2.dim(" Cancelled"));
2023
2140
  return;
2024
2141
  }
2025
2142
  }
@@ -2036,7 +2153,7 @@ async function destroyApp(skipConfirm) {
2036
2153
  if (!deleteRes.ok) {
2037
2154
  throw new Error(`Failed to delete app: ${await deleteRes.text()}`);
2038
2155
  }
2039
- console.log(pc.green(" \u2713"), `App "${appRecord.name}" deleted from Lumera.`);
2156
+ console.log(pc2.green(" \u2713"), `App "${appRecord.name}" deleted from Lumera.`);
2040
2157
  }
2041
2158
  async function showResource(api, platformDir, resourceType, resourceName, appName, projectId) {
2042
2159
  if (resourceType === "collections") {
@@ -2045,11 +2162,11 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2045
2162
  const local = localCollections[0];
2046
2163
  const remote = remoteCollections.find((c) => c.name === resourceName || c.id === resourceName);
2047
2164
  if (!local && !remote) {
2048
- console.log(pc.red(` Collection "${resourceName}" not found`));
2165
+ console.log(pc2.red(` Collection "${resourceName}" not found`));
2049
2166
  process.exit(1);
2050
2167
  }
2051
2168
  console.log();
2052
- console.log(pc.bold(` Collection: ${resourceName}`));
2169
+ console.log(pc2.bold(` Collection: ${resourceName}`));
2053
2170
  console.log();
2054
2171
  let collectionStatus;
2055
2172
  let addedFields = [];
@@ -2066,38 +2183,38 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2066
2183
  collectionStatus = "remote-only";
2067
2184
  }
2068
2185
  const statusDisplay = {
2069
- "synced": pc.green("synced"),
2070
- "changed": pc.yellow("changed"),
2071
- "local-only": pc.yellow("local only"),
2072
- "remote-only": pc.cyan("remote only")
2186
+ "synced": pc2.green("synced"),
2187
+ "changed": pc2.yellow("changed"),
2188
+ "local-only": pc2.yellow("local only"),
2189
+ "remote-only": pc2.cyan("remote only")
2073
2190
  };
2074
2191
  console.log(` Status: ${statusDisplay[collectionStatus]}`);
2075
2192
  console.log();
2076
2193
  const addedSet = new Set(addedFields);
2077
2194
  const removedSet = new Set(removedFields);
2078
- console.log(pc.bold(" Fields:"));
2195
+ console.log(pc2.bold(" Fields:"));
2079
2196
  if (local) {
2080
2197
  for (const field of local.fields) {
2081
- const req = field.required ? pc.red("*") : "";
2198
+ const req = field.required ? pc2.red("*") : "";
2082
2199
  if (addedSet.has(field.name)) {
2083
- console.log(` ${pc.green("+")} ${field.name}${req} ${pc.dim(`(${field.type})`)}`);
2200
+ console.log(` ${pc2.green("+")} ${field.name}${req} ${pc2.dim(`(${field.type})`)}`);
2084
2201
  } else {
2085
- console.log(` ${field.name}${req} ${pc.dim(`(${field.type})`)}`);
2202
+ console.log(` ${field.name}${req} ${pc2.dim(`(${field.type})`)}`);
2086
2203
  }
2087
2204
  }
2088
2205
  }
2089
2206
  if (remote) {
2090
2207
  for (const field of remote.schema) {
2091
2208
  if (removedSet.has(field.name)) {
2092
- const req = field.required ? pc.red("*") : "";
2093
- console.log(` ${pc.red("-")} ${field.name}${req} ${pc.dim(`(${field.type})`)}`);
2209
+ const req = field.required ? pc2.red("*") : "";
2210
+ console.log(` ${pc2.red("-")} ${field.name}${req} ${pc2.dim(`(${field.type})`)}`);
2094
2211
  }
2095
2212
  }
2096
2213
  }
2097
2214
  if (!local && remote) {
2098
2215
  for (const field of remote.schema) {
2099
- const req = field.required ? pc.red("*") : "";
2100
- console.log(` ${field.name}${req} ${pc.dim(`(${field.type})`)}`);
2216
+ const req = field.required ? pc2.red("*") : "";
2217
+ console.log(` ${field.name}${req} ${pc2.dim(`(${field.type})`)}`);
2101
2218
  }
2102
2219
  }
2103
2220
  console.log();
@@ -2107,18 +2224,18 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2107
2224
  const local = localAutomations[0];
2108
2225
  const remote = remoteAutomations.find((a) => a.external_id === resourceName || a.name === resourceName);
2109
2226
  if (!local && !remote) {
2110
- console.log(pc.red(` Automation "${resourceName}" not found`));
2227
+ console.log(pc2.red(` Automation "${resourceName}" not found`));
2111
2228
  process.exit(1);
2112
2229
  }
2113
2230
  console.log();
2114
- console.log(pc.bold(` Automation: ${local?.automation.name || remote?.name}`));
2231
+ console.log(pc2.bold(` Automation: ${local?.automation.name || remote?.name}`));
2115
2232
  console.log();
2116
2233
  if (local && remote) {
2117
- console.log(` Status: ${pc.green("synced")}`);
2234
+ console.log(` Status: ${pc2.green("synced")}`);
2118
2235
  } else if (local) {
2119
- console.log(` Status: ${pc.yellow("local only")}`);
2236
+ console.log(` Status: ${pc2.yellow("local only")}`);
2120
2237
  } else {
2121
- console.log(` Status: ${pc.cyan("remote only")}`);
2238
+ console.log(` Status: ${pc2.cyan("remote only")}`);
2122
2239
  }
2123
2240
  if (local?.automation.description || remote?.description) {
2124
2241
  console.log(` Description: ${local?.automation.description || remote?.description}`);
@@ -2130,11 +2247,11 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2130
2247
  const local = localHooks[0];
2131
2248
  const remote = remoteHooks.find((h) => h.external_id === resourceName);
2132
2249
  if (!local && !remote) {
2133
- console.log(pc.red(` Hook "${resourceName}" not found`));
2250
+ console.log(pc2.red(` Hook "${resourceName}" not found`));
2134
2251
  process.exit(1);
2135
2252
  }
2136
2253
  console.log();
2137
- console.log(pc.bold(` Hook: ${local?.hook.external_id || remote?.external_id}`));
2254
+ console.log(pc2.bold(` Hook: ${local?.hook.external_id || remote?.external_id}`));
2138
2255
  console.log();
2139
2256
  console.log(` Collection: ${local?.hook.collection || remote?.collection_name}`);
2140
2257
  console.log(` Trigger: ${local?.hook.trigger || remote?.event}`);
@@ -2146,25 +2263,25 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2146
2263
  const local = localAgents[0];
2147
2264
  const remote = remoteAgents.find((a) => a.external_id === resourceName || a.name === resourceName);
2148
2265
  if (!local && !remote) {
2149
- console.log(pc.red(` Agent "${resourceName}" not found`));
2266
+ console.log(pc2.red(` Agent "${resourceName}" not found`));
2150
2267
  process.exit(1);
2151
2268
  }
2152
2269
  console.log();
2153
- console.log(pc.bold(` Agent: ${local?.agent.name || remote?.name}`));
2270
+ console.log(pc2.bold(` Agent: ${local?.agent.name || remote?.name}`));
2154
2271
  console.log();
2155
2272
  if (local && remote) {
2156
2273
  const promptChanged = (remote.system_prompt || "").trim() !== local.systemPrompt.trim();
2157
2274
  const nameChanged = remote.name !== local.agent.name;
2158
2275
  const descChanged = (remote.description || "") !== (local.agent.description || "");
2159
2276
  if (promptChanged || nameChanged || descChanged) {
2160
- console.log(` Status: ${pc.yellow("changed")}`);
2277
+ console.log(` Status: ${pc2.yellow("changed")}`);
2161
2278
  } else {
2162
- console.log(` Status: ${pc.green("synced")}`);
2279
+ console.log(` Status: ${pc2.green("synced")}`);
2163
2280
  }
2164
2281
  } else if (local) {
2165
- console.log(` Status: ${pc.yellow("local only")}`);
2282
+ console.log(` Status: ${pc2.yellow("local only")}`);
2166
2283
  } else {
2167
- console.log(` Status: ${pc.cyan("remote only")}`);
2284
+ console.log(` Status: ${pc2.cyan("remote only")}`);
2168
2285
  }
2169
2286
  if (local?.agent.external_id || remote?.external_id) {
2170
2287
  console.log(` External ID: ${local?.agent.external_id || remote?.external_id}`);
@@ -2183,19 +2300,19 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2183
2300
  const local = localMailboxes[0];
2184
2301
  const remote = remoteMailboxes.find((m) => m.slug === resourceName);
2185
2302
  if (!local && !remote) {
2186
- console.log(pc.red(` Mailbox "${resourceName}" not found`));
2303
+ console.log(pc2.red(` Mailbox "${resourceName}" not found`));
2187
2304
  process.exit(1);
2188
2305
  }
2189
2306
  console.log();
2190
- console.log(pc.bold(` Mailbox: ${local?.slug || remote?.slug}`));
2307
+ console.log(pc2.bold(` Mailbox: ${local?.slug || remote?.slug}`));
2191
2308
  console.log();
2192
2309
  if (local && remote) {
2193
2310
  const descChanged = (local.description ?? "").trim() !== (remote.description ?? "").trim();
2194
- console.log(` Status: ${descChanged ? pc.yellow("changed") : pc.green("synced")}`);
2311
+ console.log(` Status: ${descChanged ? pc2.yellow("changed") : pc2.green("synced")}`);
2195
2312
  } else if (local) {
2196
- console.log(` Status: ${pc.yellow("local only")}`);
2313
+ console.log(` Status: ${pc2.yellow("local only")}`);
2197
2314
  } else {
2198
- console.log(` Status: ${pc.cyan("remote only")}`);
2315
+ console.log(` Status: ${pc2.cyan("remote only")}`);
2199
2316
  }
2200
2317
  if (remote?.email) console.log(` Email: ${remote.email}`);
2201
2318
  const desc = local?.description || remote?.description;
@@ -2210,7 +2327,7 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2210
2327
  const appTitle = getAppTitle(projectRoot);
2211
2328
  let apiUrl = getApiUrl().replace(/\/+$/, "").replace(/\/api$/, "");
2212
2329
  console.log();
2213
- console.log(pc.bold(` App: ${appTitle || appName2}`));
2330
+ console.log(pc2.bold(` App: ${appTitle || appName2}`));
2214
2331
  console.log();
2215
2332
  console.log(` External ID: ${appName2}`);
2216
2333
  const filterParam = encodeURIComponent(JSON.stringify({ external_id: appName2 }));
@@ -2227,12 +2344,12 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2227
2344
  const data = await searchRes.json();
2228
2345
  const appRecord = data.items?.[0];
2229
2346
  if (appRecord) {
2230
- console.log(` Status: ${pc.green("deployed")}`);
2347
+ console.log(` Status: ${pc2.green("deployed")}`);
2231
2348
  if (appRecord.hosting_type) console.log(` Hosting: ${appRecord.hosting_type}`);
2232
2349
  if (appRecord.current_version) console.log(` Version: ${appRecord.current_version}`);
2233
2350
  if (appRecord.deployed_at) console.log(` Deployed: ${appRecord.deployed_at}`);
2234
2351
  } else {
2235
- console.log(` Status: ${pc.yellow("not deployed")}`);
2352
+ console.log(` Status: ${pc2.yellow("not deployed")}`);
2236
2353
  }
2237
2354
  }
2238
2355
  console.log();
@@ -2253,8 +2370,8 @@ async function plan(args) {
2253
2370
  const positionalArgs = args.filter((a) => !a.startsWith("-"));
2254
2371
  const { type, name } = parseResource(positionalArgs.filter((a) => a !== "--json")[0]);
2255
2372
  console.log();
2256
- console.log(pc.cyan(pc.bold(" Plan")));
2257
- console.log(pc.dim(" Comparing local files to remote state..."));
2373
+ console.log(pc2.cyan(pc2.bold(" Plan")));
2374
+ console.log(pc2.dim(" Comparing local files to remote state..."));
2258
2375
  console.log();
2259
2376
  await syncDeps(projectRoot);
2260
2377
  const allChanges = [];
@@ -2272,8 +2389,9 @@ async function plan(args) {
2272
2389
  allChanges.push(...changes);
2273
2390
  }
2274
2391
  }
2392
+ let localAutomations = [];
2275
2393
  if (!type || type === "automations") {
2276
- const localAutomations = loadLocalAutomations(platformDir, name || void 0, appName);
2394
+ localAutomations = loadLocalAutomations(platformDir, name || void 0, appName);
2277
2395
  if (localAutomations.length > 0) {
2278
2396
  const changes = await planAutomations(api, localAutomations);
2279
2397
  allChanges.push(...changes);
@@ -2300,13 +2418,15 @@ async function plan(args) {
2300
2418
  allChanges.push(...changes);
2301
2419
  }
2302
2420
  }
2421
+ const lintWarnings = safeLint(projectRoot, localAutomations);
2303
2422
  if (allChanges.length === 0) {
2304
2423
  if (jsonOutput) {
2305
- console.log(JSON.stringify({ changes: [], warnings: [] }));
2424
+ console.log(JSON.stringify({ changes: [], warnings: [], lintWarnings: serializeLintWarnings(lintWarnings, projectRoot) }));
2306
2425
  return;
2307
2426
  }
2308
- console.log(pc.green(" \u2713 No changes detected"));
2427
+ console.log(pc2.green(" \u2713 No changes detected"));
2309
2428
  console.log();
2429
+ safePrintLint(lintWarnings, projectRoot);
2310
2430
  return;
2311
2431
  }
2312
2432
  if (jsonOutput) {
@@ -2319,21 +2439,21 @@ async function plan(args) {
2319
2439
  }
2320
2440
  }
2321
2441
  }
2322
- console.log(JSON.stringify({ changes: allChanges, warnings }));
2442
+ console.log(JSON.stringify({ changes: allChanges, warnings, lintWarnings: serializeLintWarnings(lintWarnings, projectRoot) }));
2323
2443
  return;
2324
2444
  }
2325
- console.log(pc.bold(" Changes:"));
2445
+ console.log(pc2.bold(" Changes:"));
2326
2446
  console.log();
2327
2447
  for (const change of allChanges) {
2328
2448
  const icon = change.type === "create" ? "+" : change.type === "update" ? "~" : "-";
2329
- const color = change.type === "create" ? pc.green : change.type === "update" ? pc.yellow : pc.red;
2449
+ const color = change.type === "create" ? pc2.green : change.type === "update" ? pc2.yellow : pc2.red;
2330
2450
  const details = change.details ? ` (${change.details})` : "";
2331
- console.log(` ${color(icon)} ${change.resource}: ${change.name}${pc.dim(details)}`);
2451
+ console.log(` ${color(icon)} ${change.resource}: ${change.name}${pc2.dim(details)}`);
2332
2452
  if (change.fieldDetails && change.fieldDetails.length > 0) {
2333
2453
  for (const field of change.fieldDetails) {
2334
- const fColor = field.action === "+" ? pc.green : pc.red;
2454
+ const fColor = field.action === "+" ? pc2.green : pc2.red;
2335
2455
  const req = field.required ? "*" : "";
2336
- console.log(` ${fColor(field.action)} ${field.name}${req} ${pc.dim(`(${field.type})`)}`);
2456
+ console.log(` ${fColor(field.action)} ${field.name}${req} ${pc2.dim(`(${field.type})`)}`);
2337
2457
  }
2338
2458
  console.log();
2339
2459
  }
@@ -2342,16 +2462,16 @@ async function plan(args) {
2342
2462
  for (const td of change.textDiffs) {
2343
2463
  const diffLines = computeLineDiff(td.oldText, td.newText);
2344
2464
  if (diffLines.length > 0) {
2345
- console.log(pc.dim(` --- ${td.field}`));
2465
+ console.log(pc2.dim(` --- ${td.field}`));
2346
2466
  const shown = diffLines.slice(0, maxDiffLines);
2347
2467
  for (const dl of shown) {
2348
- if (dl.type === "+") console.log(pc.green(` + ${dl.line}`));
2349
- else if (dl.type === "-") console.log(pc.red(` - ${dl.line}`));
2350
- else console.log(pc.dim(` ${dl.line}`));
2468
+ if (dl.type === "+") console.log(pc2.green(` + ${dl.line}`));
2469
+ else if (dl.type === "-") console.log(pc2.red(` - ${dl.line}`));
2470
+ else console.log(pc2.dim(` ${dl.line}`));
2351
2471
  }
2352
2472
  if (diffLines.length > maxDiffLines) {
2353
2473
  const remaining = diffLines.length - maxDiffLines;
2354
- console.log(pc.dim(` ... ${remaining} more lines \u2014 use ${pc.cyan(`lumera diff ${change.resource}s/${change.name}`)} for full diff`));
2474
+ console.log(pc2.dim(` ... ${remaining} more lines \u2014 use ${pc2.cyan(`lumera diff ${change.resource}s/${change.name}`)} for full diff`));
2355
2475
  }
2356
2476
  console.log();
2357
2477
  }
@@ -2359,7 +2479,8 @@ async function plan(args) {
2359
2479
  }
2360
2480
  }
2361
2481
  console.log();
2362
- console.log(pc.dim(` Run 'lumera apply' to apply these changes.`));
2482
+ safePrintLint(lintWarnings, projectRoot);
2483
+ console.log(pc2.dim(` Run 'lumera apply' to apply these changes.`));
2363
2484
  console.log();
2364
2485
  }
2365
2486
  async function apply(args) {
@@ -2378,12 +2499,12 @@ async function apply(args) {
2378
2499
  const autoConfirm = args.includes("--yes") || args.includes("-y") || !!process.env.CI;
2379
2500
  if (type === "app") {
2380
2501
  console.log();
2381
- console.log(pc.cyan(pc.bold(" Apply")));
2502
+ console.log(pc2.cyan(pc2.bold(" Apply")));
2382
2503
  console.log();
2383
- console.log(pc.bold(" App:"));
2504
+ console.log(pc2.bold(" App:"));
2384
2505
  await applyApp(args);
2385
2506
  console.log();
2386
- console.log(pc.green(" Done!"));
2507
+ console.log(pc2.green(" Done!"));
2387
2508
  console.log();
2388
2509
  return;
2389
2510
  }
@@ -2411,7 +2532,7 @@ async function apply(args) {
2411
2532
  const hasLocal = localCollections.length > 0 || localAutomations.length > 0 || localHooks.length > 0 || localAgents.length > 0 || localMailboxes.length > 0;
2412
2533
  if (!hasLocal) {
2413
2534
  console.log();
2414
- console.log(pc.red(` Resource "${name}" not found locally`));
2535
+ console.log(pc2.red(` Resource "${name}" not found locally`));
2415
2536
  process.exit(1);
2416
2537
  }
2417
2538
  }
@@ -2426,35 +2547,37 @@ async function apply(args) {
2426
2547
  }
2427
2548
  if (allChanges.length === 0 && !willDeployApp) {
2428
2549
  console.log();
2429
- console.log(pc.green(" \u2713 Nothing to apply \u2014 local and remote are in sync."));
2550
+ console.log(pc2.green(" \u2713 Nothing to apply \u2014 local and remote are in sync."));
2430
2551
  console.log();
2552
+ safePrintLint(safeLint(projectRoot, localAutomations), projectRoot);
2431
2553
  return;
2432
2554
  }
2433
2555
  console.log();
2434
- console.log(pc.cyan(pc.bold(" Apply")));
2556
+ console.log(pc2.cyan(pc2.bold(" Apply")));
2435
2557
  console.log();
2436
2558
  const creates = allChanges.filter((c) => c.type === "create");
2437
2559
  const updates = allChanges.filter((c) => c.type === "update");
2438
2560
  if (allChanges.length > 0) {
2439
- console.log(pc.bold(" Plan:"));
2561
+ console.log(pc2.bold(" Plan:"));
2440
2562
  for (const change of allChanges) {
2441
2563
  const icon = change.type === "create" ? "+" : "~";
2442
- const color = change.type === "create" ? pc.green : pc.yellow;
2564
+ const color = change.type === "create" ? pc2.green : pc2.yellow;
2443
2565
  const details = change.details ? ` (${change.details})` : "";
2444
- console.log(` ${color(icon)} ${change.resource}: ${change.name}${pc.dim(details)}`);
2566
+ console.log(` ${color(icon)} ${change.resource}: ${change.name}${pc2.dim(details)}`);
2445
2567
  }
2446
- if (willDeployApp) console.log(` ${pc.blue("\u25CF")} app: frontend build + deploy`);
2568
+ if (willDeployApp) console.log(` ${pc2.blue("\u25CF")} app: frontend build + deploy`);
2447
2569
  console.log();
2448
2570
  const parts = [];
2449
- if (creates.length > 0) parts.push(pc.green(`${creates.length} create`));
2450
- if (updates.length > 0) parts.push(pc.yellow(`${updates.length} update`));
2451
- if (willDeployApp) parts.push(pc.blue("1 app deploy"));
2571
+ if (creates.length > 0) parts.push(pc2.green(`${creates.length} create`));
2572
+ if (updates.length > 0) parts.push(pc2.yellow(`${updates.length} update`));
2573
+ if (willDeployApp) parts.push(pc2.blue("1 app deploy"));
2452
2574
  console.log(` ${parts.join(", ")}`);
2453
2575
  console.log();
2454
2576
  } else if (willDeployApp) {
2455
- console.log(pc.dim(" No infrastructure changes \u2014 deploying app only."));
2577
+ console.log(pc2.dim(" No infrastructure changes \u2014 deploying app only."));
2456
2578
  console.log();
2457
2579
  }
2580
+ safePrintLint(safeLint(projectRoot, localAutomations), projectRoot);
2458
2581
  if (!autoConfirm && allChanges.length > 0) {
2459
2582
  const { confirm } = await prompts({
2460
2583
  type: "confirm",
@@ -2463,7 +2586,7 @@ async function apply(args) {
2463
2586
  initial: true
2464
2587
  });
2465
2588
  if (!confirm) {
2466
- console.log(pc.dim(" Cancelled."));
2589
+ console.log(pc2.dim(" Cancelled."));
2467
2590
  console.log();
2468
2591
  return;
2469
2592
  }
@@ -2474,7 +2597,7 @@ async function apply(args) {
2474
2597
  let totalUpdated = 0;
2475
2598
  let totalSkipped = 0;
2476
2599
  if (localCollections.length > 0) {
2477
- console.log(pc.bold(" Collections:"));
2600
+ console.log(pc2.bold(" Collections:"));
2478
2601
  totalErrors += await applyCollections(api, localCollections);
2479
2602
  console.log();
2480
2603
  }
@@ -2485,42 +2608,42 @@ async function apply(args) {
2485
2608
  } catch {
2486
2609
  }
2487
2610
  if (localAutomations.length > 0) {
2488
- console.log(pc.bold(" Automations:"));
2611
+ console.log(pc2.bold(" Automations:"));
2489
2612
  totalErrors += await applyAutomations(api, localAutomations, projectId);
2490
2613
  console.log();
2491
2614
  }
2492
2615
  if (localHooks.length > 0) {
2493
- console.log(pc.bold(" Hooks:"));
2616
+ console.log(pc2.bold(" Hooks:"));
2494
2617
  totalErrors += await applyHooks(api, localHooks, collections, projectId);
2495
2618
  console.log();
2496
2619
  }
2497
2620
  if (localAgents.length > 0) {
2498
- console.log(pc.bold(" Agents:"));
2621
+ console.log(pc2.bold(" Agents:"));
2499
2622
  totalErrors += await applyAgents(api, localAgents, projectId);
2500
2623
  console.log();
2501
2624
  }
2502
2625
  if (localMailboxes.length > 0) {
2503
- console.log(pc.bold(" Mailboxes:"));
2626
+ console.log(pc2.bold(" Mailboxes:"));
2504
2627
  totalErrors += await applyMailboxes(api, localMailboxes);
2505
2628
  console.log();
2506
2629
  }
2507
2630
  if (willDeployApp) {
2508
- console.log(pc.bold(" App:"));
2631
+ console.log(pc2.bold(" App:"));
2509
2632
  await applyApp(args);
2510
2633
  console.log();
2511
2634
  }
2512
2635
  totalCreated = creates.length;
2513
2636
  totalUpdated = updates.length;
2514
2637
  if (totalErrors > 0) {
2515
- console.log(pc.red(` \u2717 ${totalErrors} error${totalErrors > 1 ? "s" : ""} during apply.`));
2638
+ console.log(pc2.red(` \u2717 ${totalErrors} error${totalErrors > 1 ? "s" : ""} during apply.`));
2516
2639
  console.log();
2517
2640
  process.exit(1);
2518
2641
  }
2519
2642
  const summary = [];
2520
- if (totalCreated > 0) summary.push(pc.green(`${totalCreated} created`));
2521
- if (totalUpdated > 0) summary.push(pc.yellow(`${totalUpdated} updated`));
2522
- if (willDeployApp) summary.push(pc.blue("app deployed"));
2523
- console.log(pc.green(" \u2713 Done!") + (summary.length > 0 ? ` ${pc.dim("\u2014")} ${summary.join(", ")}` : ""));
2643
+ if (totalCreated > 0) summary.push(pc2.green(`${totalCreated} created`));
2644
+ if (totalUpdated > 0) summary.push(pc2.yellow(`${totalUpdated} updated`));
2645
+ if (willDeployApp) summary.push(pc2.blue("app deployed"));
2646
+ console.log(pc2.green(" \u2713 Done!") + (summary.length > 0 ? ` ${pc2.dim("\u2014")} ${summary.join(", ")}` : ""));
2524
2647
  console.log();
2525
2648
  }
2526
2649
  async function pull(args) {
@@ -2575,47 +2698,47 @@ async function pull(args) {
2575
2698
  }
2576
2699
  if (conflicts.length > 0) {
2577
2700
  console.log();
2578
- console.log(pc.yellow(` \u26A0 ${conflicts.length} local file${conflicts.length > 1 ? "s have" : " has"} changes that would be lost:`));
2701
+ console.log(pc2.yellow(` \u26A0 ${conflicts.length} local file${conflicts.length > 1 ? "s have" : " has"} changes that would be lost:`));
2579
2702
  for (const f of conflicts) {
2580
- console.log(pc.dim(` ${f}`));
2703
+ console.log(pc2.dim(` ${f}`));
2581
2704
  }
2582
2705
  console.log();
2583
- console.log(pc.dim(` Use ${pc.cyan("lumera diff <resource>")} to inspect changes.`));
2584
- console.log(pc.dim(` Use ${pc.cyan("lumera pull --force")} to overwrite local files.`));
2706
+ console.log(pc2.dim(` Use ${pc2.cyan("lumera diff <resource>")} to inspect changes.`));
2707
+ console.log(pc2.dim(` Use ${pc2.cyan("lumera pull --force")} to overwrite local files.`));
2585
2708
  console.log();
2586
2709
  process.exit(1);
2587
2710
  }
2588
2711
  }
2589
2712
  console.log();
2590
- console.log(pc.cyan(pc.bold(" Pull")));
2591
- console.log(pc.dim(` Downloading remote state to ${platformDir}/...`));
2713
+ console.log(pc2.cyan(pc2.bold(" Pull")));
2714
+ console.log(pc2.dim(` Downloading remote state to ${platformDir}/...`));
2592
2715
  console.log();
2593
2716
  if (!type || type === "collections") {
2594
- console.log(pc.bold(" Collections:"));
2717
+ console.log(pc2.bold(" Collections:"));
2595
2718
  await pullCollections(api, platformDir, name || void 0, appName);
2596
2719
  console.log();
2597
2720
  }
2598
2721
  if (!type || type === "automations") {
2599
- console.log(pc.bold(" Automations:"));
2722
+ console.log(pc2.bold(" Automations:"));
2600
2723
  await pullAutomations(api, platformDir, name || void 0, projectId);
2601
2724
  console.log();
2602
2725
  }
2603
2726
  if (!type || type === "hooks") {
2604
- console.log(pc.bold(" Hooks:"));
2727
+ console.log(pc2.bold(" Hooks:"));
2605
2728
  await pullHooks(api, platformDir, name || void 0, appName, projectId);
2606
2729
  console.log();
2607
2730
  }
2608
2731
  if (!type || type === "agents") {
2609
- console.log(pc.bold(" Agents:"));
2732
+ console.log(pc2.bold(" Agents:"));
2610
2733
  await pullAgents(api, platformDir, name || void 0, projectId);
2611
2734
  console.log();
2612
2735
  }
2613
2736
  if (!type || type === "mailboxes") {
2614
- console.log(pc.bold(" Mailboxes:"));
2737
+ console.log(pc2.bold(" Mailboxes:"));
2615
2738
  await pullMailboxes(api, platformDir, name || void 0);
2616
2739
  console.log();
2617
2740
  }
2618
- console.log(pc.green(" Done!"));
2741
+ console.log(pc2.green(" Done!"));
2619
2742
  console.log();
2620
2743
  }
2621
2744
  async function destroy(args) {
@@ -2633,7 +2756,7 @@ async function destroy(args) {
2633
2756
  const skipConfirm = args.includes("--confirm");
2634
2757
  const forceCycles = args.includes("--force-cycles");
2635
2758
  console.log();
2636
- console.log(pc.red(pc.bold(" Destroy")));
2759
+ console.log(pc2.red(pc2.bold(" Destroy")));
2637
2760
  console.log();
2638
2761
  if (type === "app") {
2639
2762
  await destroyApp(skipConfirm);
@@ -2657,19 +2780,19 @@ async function list(args) {
2657
2780
  const positionalArgs = args.filter((a) => !a.startsWith("--"));
2658
2781
  const filterType = positionalArgs[0];
2659
2782
  console.log();
2660
- console.log(pc.cyan(pc.bold(" Resources")));
2783
+ console.log(pc2.cyan(pc2.bold(" Resources")));
2661
2784
  console.log();
2662
2785
  const allResources = await listResources(api, platformDir, filterType, appName, projectId);
2663
2786
  const remoteOnlyCount = allResources.filter((r) => r.status === "remote-only").length;
2664
2787
  const resources = showAll ? allResources : allResources.filter((r) => r.status !== "remote-only");
2665
2788
  if (resources.length === 0 && remoteOnlyCount === 0) {
2666
- console.log(pc.dim(" No resources found"));
2789
+ console.log(pc2.dim(" No resources found"));
2667
2790
  console.log();
2668
2791
  return;
2669
2792
  }
2670
2793
  if (resources.length === 0 && remoteOnlyCount > 0) {
2671
- console.log(pc.dim(" No local resources found"));
2672
- console.log(pc.dim(` ${remoteOnlyCount} remote-only resource(s) hidden. Use --all to show.`));
2794
+ console.log(pc2.dim(" No local resources found"));
2795
+ console.log(pc2.dim(` ${remoteOnlyCount} remote-only resource(s) hidden. Use --all to show.`));
2673
2796
  console.log();
2674
2797
  return;
2675
2798
  }
@@ -2679,29 +2802,29 @@ async function list(args) {
2679
2802
  byType.get(r.type).push(r);
2680
2803
  }
2681
2804
  for (const [type, items] of byType) {
2682
- console.log(pc.bold(` ${type.charAt(0).toUpperCase() + type.slice(1)}:`));
2805
+ console.log(pc2.bold(` ${type.charAt(0).toUpperCase() + type.slice(1)}:`));
2683
2806
  for (const item of items) {
2684
2807
  let icon;
2685
2808
  let color;
2686
2809
  switch (item.status) {
2687
2810
  case "synced":
2688
2811
  icon = "\u2713";
2689
- color = pc.green;
2812
+ color = pc2.green;
2690
2813
  break;
2691
2814
  case "changed":
2692
2815
  icon = "~";
2693
- color = pc.yellow;
2816
+ color = pc2.yellow;
2694
2817
  break;
2695
2818
  case "local-only":
2696
2819
  icon = "+";
2697
- color = pc.cyan;
2820
+ color = pc2.cyan;
2698
2821
  break;
2699
2822
  case "remote-only":
2700
2823
  icon = "?";
2701
- color = pc.dim;
2824
+ color = pc2.dim;
2702
2825
  break;
2703
2826
  }
2704
- const details = item.details ? pc.dim(` (${item.details})`) : "";
2827
+ const details = item.details ? pc2.dim(` (${item.details})`) : "";
2705
2828
  console.log(` ${color(icon)} ${item.name}${details}`);
2706
2829
  }
2707
2830
  console.log();
@@ -2711,14 +2834,14 @@ async function list(args) {
2711
2834
  const localOnly = resources.filter((r) => r.status === "local-only").length;
2712
2835
  const displayedRemoteOnly = resources.filter((r) => r.status === "remote-only").length;
2713
2836
  const summary = [];
2714
- if (synced > 0) summary.push(pc.green(`${synced} synced`));
2715
- if (changed > 0) summary.push(pc.yellow(`${changed} changed`));
2716
- if (localOnly > 0) summary.push(pc.cyan(`${localOnly} local-only`));
2717
- if (displayedRemoteOnly > 0) summary.push(pc.dim(`${displayedRemoteOnly} remote-only`));
2837
+ if (synced > 0) summary.push(pc2.green(`${synced} synced`));
2838
+ if (changed > 0) summary.push(pc2.yellow(`${changed} changed`));
2839
+ if (localOnly > 0) summary.push(pc2.cyan(`${localOnly} local-only`));
2840
+ if (displayedRemoteOnly > 0) summary.push(pc2.dim(`${displayedRemoteOnly} remote-only`));
2718
2841
  console.log(` ${summary.join(" | ")}`);
2719
- console.log(pc.dim(` ${pc.green("\u2713")} synced ${pc.yellow("~")} changed ${pc.cyan("+")} local-only ? remote-only`));
2842
+ console.log(pc2.dim(` ${pc2.green("\u2713")} synced ${pc2.yellow("~")} changed ${pc2.cyan("+")} local-only ? remote-only`));
2720
2843
  if (!showAll && remoteOnlyCount > 0) {
2721
- console.log(pc.dim(` ${remoteOnlyCount} remote-only resource(s) hidden. Use --all to show.`));
2844
+ console.log(pc2.dim(` ${remoteOnlyCount} remote-only resource(s) hidden. Use --all to show.`));
2722
2845
  }
2723
2846
  console.log();
2724
2847
  }
@@ -2736,15 +2859,15 @@ async function show(args) {
2736
2859
  const projectId = getProjectId(projectRoot);
2737
2860
  const { type, name } = parseResource(args[0]);
2738
2861
  if (!type) {
2739
- console.log(pc.red(` Invalid resource path: ${args[0]}`));
2740
- console.log(pc.dim(" Use format: <type>/<name> (e.g., collections/users)"));
2862
+ console.log(pc2.red(` Invalid resource path: ${args[0]}`));
2863
+ console.log(pc2.dim(" Use format: <type>/<name> (e.g., collections/users)"));
2741
2864
  process.exit(1);
2742
2865
  }
2743
2866
  if (type === "app") {
2744
2867
  await showResource(api, platformDir, "app", "", appName, projectId);
2745
2868
  } else if (!name) {
2746
- console.log(pc.red(` Resource name required`));
2747
- console.log(pc.dim(" Use format: <type>/<name> (e.g., collections/users)"));
2869
+ console.log(pc2.red(` Resource name required`));
2870
+ console.log(pc2.dim(" Use format: <type>/<name> (e.g., collections/users)"));
2748
2871
  process.exit(1);
2749
2872
  } else {
2750
2873
  await showResource(api, platformDir, type, name, appName, projectId);
@@ -2752,17 +2875,17 @@ async function show(args) {
2752
2875
  }
2753
2876
  function showDiffHelp() {
2754
2877
  console.log(`
2755
- ${pc.bold("lumera diff")} - Show full diff between local and remote state
2878
+ ${pc2.bold("lumera diff")} - Show full diff between local and remote state
2756
2879
 
2757
- ${pc.dim("Usage:")}
2880
+ ${pc2.dim("Usage:")}
2758
2881
  lumera diff <resource>
2759
2882
 
2760
- ${pc.dim("Resources:")}
2883
+ ${pc2.dim("Resources:")}
2761
2884
  agents/<name> Diff agent (system_prompt, policy_script)
2762
2885
  automations/<name> Diff automation code
2763
2886
  hooks/<name> Diff hook script
2764
2887
 
2765
- ${pc.dim("Examples:")}
2888
+ ${pc2.dim("Examples:")}
2766
2889
  lumera diff agents/bank_activity_matcher
2767
2890
  lumera diff automations/sync
2768
2891
  lumera diff hooks/encoding_protect_create
@@ -2771,14 +2894,14 @@ ${pc.dim("Examples:")}
2771
2894
  function renderFullDiff(field, oldText, newText) {
2772
2895
  const diffLines = computeLineDiff(oldText, newText);
2773
2896
  if (diffLines.length === 0) {
2774
- console.log(pc.dim(` ${field}: no changes`));
2897
+ console.log(pc2.dim(` ${field}: no changes`));
2775
2898
  return;
2776
2899
  }
2777
- console.log(pc.bold(` --- ${field}`));
2900
+ console.log(pc2.bold(` --- ${field}`));
2778
2901
  for (const dl of diffLines) {
2779
- if (dl.type === "+") console.log(pc.green(` + ${dl.line}`));
2780
- else if (dl.type === "-") console.log(pc.red(` - ${dl.line}`));
2781
- else console.log(pc.dim(` ${dl.line}`));
2902
+ if (dl.type === "+") console.log(pc2.green(` + ${dl.line}`));
2903
+ else if (dl.type === "-") console.log(pc2.red(` - ${dl.line}`));
2904
+ else console.log(pc2.dim(` ${dl.line}`));
2782
2905
  }
2783
2906
  console.log();
2784
2907
  }
@@ -2796,8 +2919,8 @@ async function diff(args) {
2796
2919
  const projectId = getProjectId(projectRoot);
2797
2920
  const { type, name } = parseResource(args[0]);
2798
2921
  if (!type || !name) {
2799
- console.log(pc.red(` Invalid resource path: ${args[0]}`));
2800
- console.log(pc.dim(" Use format: <type>/<name> (e.g., agents/bank_activity_matcher)"));
2922
+ console.log(pc2.red(` Invalid resource path: ${args[0]}`));
2923
+ console.log(pc2.dim(" Use format: <type>/<name> (e.g., agents/bank_activity_matcher)"));
2801
2924
  process.exit(1);
2802
2925
  }
2803
2926
  console.log();
@@ -2810,31 +2933,31 @@ async function diff(args) {
2810
2933
  (a) => a.external_id === name || a.name === name || localExtId && a.external_id === localExtId
2811
2934
  );
2812
2935
  if (!local && !remote) {
2813
- console.log(pc.red(` Agent "${name}" not found locally or remotely`));
2936
+ console.log(pc2.red(` Agent "${name}" not found locally or remotely`));
2814
2937
  process.exit(1);
2815
2938
  }
2816
2939
  if (!local) {
2817
- console.log(pc.cyan(` Agent "${name}" exists only remotely (not in local files)`));
2940
+ console.log(pc2.cyan(` Agent "${name}" exists only remotely (not in local files)`));
2818
2941
  process.exit(0);
2819
2942
  }
2820
2943
  if (!remote) {
2821
- console.log(pc.yellow(` Agent "${name}" exists only locally (not yet deployed)`));
2944
+ console.log(pc2.yellow(` Agent "${name}" exists only locally (not yet deployed)`));
2822
2945
  process.exit(0);
2823
2946
  }
2824
- console.log(pc.bold(` Agent: ${local.agent.name}`));
2947
+ console.log(pc2.bold(` Agent: ${local.agent.name}`));
2825
2948
  console.log();
2826
2949
  if (remote.name !== local.agent.name)
2827
- console.log(` name: ${pc.red(remote.name)} \u2192 ${pc.green(local.agent.name)}`);
2950
+ console.log(` name: ${pc2.red(remote.name)} \u2192 ${pc2.green(local.agent.name)}`);
2828
2951
  if ((remote.description || "") !== (local.agent.description || ""))
2829
- console.log(` description: ${pc.red(remote.description || "(empty)")} \u2192 ${pc.green(local.agent.description || "(empty)")}`);
2952
+ console.log(` description: ${pc2.red(remote.description || "(empty)")} \u2192 ${pc2.green(local.agent.description || "(empty)")}`);
2830
2953
  if ((remote.model || "") !== (local.agent.model || ""))
2831
- console.log(` model: ${pc.red(remote.model || "(default)")} \u2192 ${pc.green(local.agent.model || "(default)")}`);
2954
+ console.log(` model: ${pc2.red(remote.model || "(default)")} \u2192 ${pc2.green(local.agent.model || "(default)")}`);
2832
2955
  if ((remote.policy_enabled || false) !== (local.agent.policy_enabled || false))
2833
- console.log(` policy_enabled: ${pc.red(String(remote.policy_enabled || false))} \u2192 ${pc.green(String(local.agent.policy_enabled || false))}`);
2956
+ console.log(` policy_enabled: ${pc2.red(String(remote.policy_enabled || false))} \u2192 ${pc2.green(String(local.agent.policy_enabled || false))}`);
2834
2957
  const promptChanged = (remote.system_prompt || "").trim() !== local.systemPrompt.trim();
2835
2958
  const policyChanged = (remote.policy_script || "").trim() !== (local.policyScript || "").trim();
2836
2959
  if (!promptChanged && !policyChanged && remote.name === local.agent.name && (remote.description || "") === (local.agent.description || "") && (remote.model || "") === (local.agent.model || "") && (remote.policy_enabled || false) === (local.agent.policy_enabled || false)) {
2837
- console.log(pc.green(` \u2713 No changes`));
2960
+ console.log(pc2.green(` \u2713 No changes`));
2838
2961
  } else {
2839
2962
  if (promptChanged) renderFullDiff("system_prompt.md", remote.system_prompt || "", local.systemPrompt);
2840
2963
  if (policyChanged) renderFullDiff("policy.js", remote.policy_script || "", local.policyScript);
@@ -2848,24 +2971,24 @@ async function diff(args) {
2848
2971
  (a) => a.external_id === name || a.name === name || localExtId && a.external_id === localExtId
2849
2972
  );
2850
2973
  if (!local && !remote) {
2851
- console.log(pc.red(` Automation "${name}" not found locally or remotely`));
2974
+ console.log(pc2.red(` Automation "${name}" not found locally or remotely`));
2852
2975
  process.exit(1);
2853
2976
  }
2854
2977
  if (!local) {
2855
- console.log(pc.cyan(` Automation "${name}" exists only remotely`));
2978
+ console.log(pc2.cyan(` Automation "${name}" exists only remotely`));
2856
2979
  process.exit(0);
2857
2980
  }
2858
2981
  if (!remote) {
2859
- console.log(pc.yellow(` Automation "${name}" exists only locally (not yet deployed)`));
2982
+ console.log(pc2.yellow(` Automation "${name}" exists only locally (not yet deployed)`));
2860
2983
  process.exit(0);
2861
2984
  }
2862
- console.log(pc.bold(` Automation: ${local.automation.name}`));
2985
+ console.log(pc2.bold(` Automation: ${local.automation.name}`));
2863
2986
  console.log();
2864
2987
  if (remote.name !== local.automation.name)
2865
- console.log(` name: ${pc.red(remote.name)} \u2192 ${pc.green(local.automation.name)}`);
2988
+ console.log(` name: ${pc2.red(remote.name)} \u2192 ${pc2.green(local.automation.name)}`);
2866
2989
  const codeChanged = (remote.code || "") !== local.code;
2867
2990
  if (!codeChanged && remote.name === local.automation.name) {
2868
- console.log(pc.green(` \u2713 No changes`));
2991
+ console.log(pc2.green(` \u2713 No changes`));
2869
2992
  } else if (codeChanged) {
2870
2993
  renderFullDiff("main.py", remote.code || "", local.code);
2871
2994
  }
@@ -2878,29 +3001,29 @@ async function diff(args) {
2878
3001
  (h) => h.external_id === name || h.name === name || localExtId && h.external_id === localExtId
2879
3002
  );
2880
3003
  if (!local && !remote) {
2881
- console.log(pc.red(` Hook "${name}" not found locally or remotely`));
3004
+ console.log(pc2.red(` Hook "${name}" not found locally or remotely`));
2882
3005
  process.exit(1);
2883
3006
  }
2884
3007
  if (!local) {
2885
- console.log(pc.cyan(` Hook "${name}" exists only remotely`));
3008
+ console.log(pc2.cyan(` Hook "${name}" exists only remotely`));
2886
3009
  process.exit(0);
2887
3010
  }
2888
3011
  if (!remote) {
2889
- console.log(pc.yellow(` Hook "${name}" exists only locally (not yet deployed)`));
3012
+ console.log(pc2.yellow(` Hook "${name}" exists only locally (not yet deployed)`));
2890
3013
  process.exit(0);
2891
3014
  }
2892
- console.log(pc.bold(` Hook: ${local.hook.external_id}`));
3015
+ console.log(pc2.bold(` Hook: ${local.hook.external_id}`));
2893
3016
  console.log();
2894
3017
  if (remote.event !== local.hook.trigger)
2895
- console.log(` trigger: ${pc.red(remote.event)} \u2192 ${pc.green(local.hook.trigger)}`);
3018
+ console.log(` trigger: ${pc2.red(remote.event)} \u2192 ${pc2.green(local.hook.trigger)}`);
2896
3019
  const scriptChanged = (remote.script || "").trim() !== local.script.trim();
2897
3020
  if (!scriptChanged && remote.event === local.hook.trigger) {
2898
- console.log(pc.green(` \u2713 No changes`));
3021
+ console.log(pc2.green(` \u2713 No changes`));
2899
3022
  } else if (scriptChanged) {
2900
3023
  renderFullDiff(local.fileName, remote.script || "", local.script);
2901
3024
  }
2902
3025
  } else {
2903
- console.log(pc.red(` Diff not supported for "${type}" \u2014 use agents, automations, or hooks`));
3026
+ console.log(pc2.red(` Diff not supported for "${type}" \u2014 use agents, automations, or hooks`));
2904
3027
  process.exit(1);
2905
3028
  }
2906
3029
  console.log();