@jay-framework/jay-stack-cli 0.24.1 → 0.24.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.
package/dist/index.js CHANGED
@@ -3,21 +3,26 @@ import express from "express";
3
3
  import http from "node:http";
4
4
  import { mkDevServer, createViteForCli } from "@jay-framework/dev-server";
5
5
  import getPort from "get-port";
6
- import path from "path";
7
- import fs, { promises } from "fs";
6
+ import path$1 from "path";
7
+ import fs$1, { promises } from "fs";
8
8
  import YAML from "yaml";
9
9
  import { getLogger, setDevLogger, createDevLogger } from "@jay-framework/logger";
10
- import { parseJayFile, JAY_IMPORT_RESOLVER, generateElementDefinitionFile, parseContract, generateElementFile, generateServerElementFile, htmlElementTagNameMap, loadLinkedContract, getLinkedContractDir } from "@jay-framework/compiler-jay-html";
11
- import { scanPlugins, listContracts, materializeContracts, SetupNeedsAnswerError, discoverPluginsWithSetup, sortPluginsByDependencies, discoverPluginsWithInit, executePluginSetup, executePluginServerInits, runInitCallbacks } from "@jay-framework/stack-server-runtime";
12
- import { listContracts as listContracts2, materializeContracts as materializeContracts2 } from "@jay-framework/stack-server-runtime";
10
+ import { parseJayFile, JAY_IMPORT_RESOLVER, generateElementDefinitionFile, parseAction, parseContract, generateElementFile, generateServerElementFile, htmlElementTagNameMap, loadLinkedContract, getLinkedContractDir } from "@jay-framework/compiler-jay-html";
11
+ import fs$2 from "node:fs/promises";
12
+ import * as path from "node:path";
13
+ import path__default from "node:path";
14
+ import { createRequire } from "module";
15
+ import jsBeautify from "js-beautify";
16
+ import { scanPlugins, sortPluginsByDependencies, getServiceRegistry, actionRegistry, resolveServices, ActionRegistry, discoverPluginsWithInit, executePluginServerInits, runInitCallbacks, registerService } from "@jay-framework/stack-server-runtime";
17
+ import "node:crypto";
18
+ import * as fs from "node:fs";
19
+ import fs__default from "node:fs";
20
+ import { createRequire as createRequire$1 } from "node:module";
21
+ import { isJayAction, isJayStreamAction, isJayCliCommand, CONSOLE_CONTEXT } from "@jay-framework/fullstack-component";
13
22
  import { Command } from "commander";
14
23
  import chalk from "chalk";
15
- import path$1 from "node:path";
16
- import fs$1 from "node:fs/promises";
17
- import { loadPluginManifest, JAY_EXTENSION, RuntimeMode, GenerateTarget, JAY_CONTRACT_EXTENSION, findDynamicContract } from "@jay-framework/compiler-shared";
18
- import { createRequire } from "module";
24
+ import { loadPluginManifest as loadPluginManifest$1, JAY_EXTENSION, RuntimeMode as RuntimeMode$1, GenerateTarget, JAY_CONTRACT_EXTENSION, findDynamicContract } from "@jay-framework/compiler-shared";
19
25
  import { glob } from "glob";
20
- import fsSync from "node:fs";
21
26
  import { fileURLToPath } from "node:url";
22
27
  import { select, confirm, input } from "@inquirer/prompts";
23
28
  const DEFAULT_CONFIG = {
@@ -29,13 +34,13 @@ const DEFAULT_CONFIG = {
29
34
  configBase: "./config"
30
35
  }
31
36
  };
32
- function loadConfig() {
33
- const configPath = path.resolve(".jay");
34
- if (!fs.existsSync(configPath)) {
37
+ function loadConfig(projectRoot) {
38
+ const configPath = projectRoot ? path$1.resolve(projectRoot, ".jay") : path$1.resolve(".jay");
39
+ if (!fs$1.existsSync(configPath)) {
35
40
  return DEFAULT_CONFIG;
36
41
  }
37
42
  try {
38
- const configContent = fs.readFileSync(configPath, "utf-8");
43
+ const configContent = fs$1.readFileSync(configPath, "utf-8");
39
44
  const userConfig = YAML.parse(configContent);
40
45
  return {
41
46
  devServer: {
@@ -62,7 +67,7 @@ function getConfigWithDefaults(config) {
62
67
  };
63
68
  }
64
69
  function updateConfig(updates) {
65
- const configPath = path.resolve(".jay");
70
+ const configPath = path$1.resolve(".jay");
66
71
  try {
67
72
  const existingConfig = loadConfig();
68
73
  const updatedConfig = {
@@ -78,7 +83,7 @@ function updateConfig(updates) {
78
83
  }
79
84
  };
80
85
  const yamlContent = YAML.stringify(updatedConfig, { indent: 2 });
81
- fs.writeFileSync(configPath, yamlContent);
86
+ fs$1.writeFileSync(configPath, yamlContent);
82
87
  } catch (error) {
83
88
  getLogger().warn(`Failed to update .jay config file: ${error}`);
84
89
  }
@@ -86,14 +91,14 @@ function updateConfig(updates) {
86
91
  async function generatePageDefinitionFiles(routes, tsConfigPath, projectRoot) {
87
92
  for (const route of routes) {
88
93
  const jayHtmlPath = route.fsRoute.jayHtmlPath;
89
- if (!fs.existsSync(jayHtmlPath)) {
94
+ if (!fs$1.existsSync(jayHtmlPath)) {
90
95
  continue;
91
96
  }
92
97
  const definitionFilePath = jayHtmlPath + ".d.ts";
93
98
  try {
94
99
  const [sourceStats, defStats] = await Promise.all([
95
- fs.promises.stat(jayHtmlPath),
96
- fs.promises.stat(definitionFilePath).catch(() => null)
100
+ fs$1.promises.stat(jayHtmlPath),
101
+ fs$1.promises.stat(definitionFilePath).catch(() => null)
97
102
  ]);
98
103
  if (defStats && defStats.mtime >= sourceStats.mtime) {
99
104
  continue;
@@ -101,9 +106,9 @@ async function generatePageDefinitionFiles(routes, tsConfigPath, projectRoot) {
101
106
  } catch (error) {
102
107
  }
103
108
  try {
104
- const jayHtml = await fs.promises.readFile(jayHtmlPath, "utf-8");
105
- const filename = path.basename(jayHtmlPath);
106
- const dirname = path.dirname(jayHtmlPath);
109
+ const jayHtml = await fs$1.promises.readFile(jayHtmlPath, "utf-8");
110
+ const filename = path$1.basename(jayHtmlPath);
111
+ const dirname = path$1.dirname(jayHtmlPath);
107
112
  const parsedJayHtml = await parseJayFile(
108
113
  jayHtml,
109
114
  filename,
@@ -119,7 +124,7 @@ async function generatePageDefinitionFiles(routes, tsConfigPath, projectRoot) {
119
124
  );
120
125
  } else {
121
126
  const definitionFilePath2 = jayHtmlPath + ".d.ts";
122
- await fs.promises.writeFile(definitionFilePath2, definitionFile.val, "utf-8");
127
+ await fs$1.promises.writeFile(definitionFilePath2, definitionFile.val, "utf-8");
123
128
  getLogger().info(`šŸ“¦ Generated definition file: ${definitionFilePath2}`);
124
129
  }
125
130
  } catch (error) {
@@ -143,7 +148,7 @@ async function startDevServer(options = {}) {
143
148
  const devServerPort = await getPort({ port: resolvedConfig.devServer.portRange });
144
149
  const log = getLogger();
145
150
  const { server, viteServer, routes, service } = await mkDevServer({
146
- pagesRootFolder: path.resolve(resolvedConfig.devServer.pagesBase),
151
+ pagesRootFolder: path$1.resolve(resolvedConfig.devServer.pagesBase),
147
152
  projectRootFolder: process.cwd(),
148
153
  publicBaseUrlPath: "/",
149
154
  jayRollupConfig: jayOptions,
@@ -151,15 +156,15 @@ async function startDevServer(options = {}) {
151
156
  httpServer
152
157
  });
153
158
  app.use(server);
154
- const publicPath = path.resolve(resolvedConfig.devServer.publicFolder);
155
- if (!fs.existsSync(path.join(publicPath, "sitemap.xml"))) {
159
+ const publicPath = path$1.resolve(resolvedConfig.devServer.publicFolder);
160
+ if (!fs$1.existsSync(path$1.join(publicPath, "sitemap.xml"))) {
156
161
  app.get("/sitemap.xml", (_req, res) => {
157
162
  res.type("application/xml").send(
158
163
  '<?xml version="1.0" encoding="UTF-8"?>\n<!-- Sitemap is generated by the production server from the route manifest. -->\n<!-- Run jay-stack build && jay-stack serve to see the full sitemap. -->\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" />\n'
159
164
  );
160
165
  });
161
166
  }
162
- if (fs.existsSync(publicPath)) {
167
+ if (fs$1.existsSync(publicPath)) {
163
168
  app.use(express.static(publicPath));
164
169
  } else {
165
170
  log.important(`āš ļø Public folder not found: ${resolvedConfig.devServer.publicFolder}`);
@@ -177,7 +182,7 @@ async function startDevServer(options = {}) {
177
182
  log.important(`šŸš€ Jay Stack dev server started successfully!`);
178
183
  log.important(`šŸ“± Dev Server: http://localhost:${devServerPort}`);
179
184
  log.important(`šŸ“ Pages directory: ${resolvedConfig.devServer.pagesBase}`);
180
- if (fs.existsSync(publicPath)) {
185
+ if (fs$1.existsSync(publicPath)) {
181
186
  log.important(`šŸ“ Public folder: ${resolvedConfig.devServer.publicFolder}`);
182
187
  }
183
188
  if (options.testMode) {
@@ -222,12 +227,1294 @@ async function startDevServer(options = {}) {
222
227
  process.on("SIGTERM", shutdown);
223
228
  process.on("SIGINT", shutdown);
224
229
  }
230
+ createRequire(import.meta.url);
231
+ var __defProp2 = Object.defineProperty;
232
+ var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
233
+ var __publicField2 = (obj, key, value) => __defNormalProp2(obj, key + "", value);
234
+ class JayAtomicType {
235
+ constructor(name) {
236
+ __publicField2(this, "kind", 0);
237
+ this.name = name;
238
+ }
239
+ }
240
+ new JayAtomicType("string");
241
+ new JayAtomicType("string");
242
+ new JayAtomicType("number");
243
+ new JayAtomicType("boolean");
244
+ new JayAtomicType("Date");
245
+ new JayAtomicType("file");
246
+ new JayAtomicType("Unknown");
247
+ class JayObjectType {
248
+ constructor(name, props) {
249
+ __publicField2(this, "kind", 8);
250
+ this.name = name;
251
+ this.props = props;
252
+ }
253
+ }
254
+ new JayObjectType("Error", {
255
+ message: new JayAtomicType("string"),
256
+ name: new JayAtomicType("string"),
257
+ stack: new JayAtomicType("string")
258
+ });
259
+ function isOptionalType(aType) {
260
+ return aType.kind === 14;
261
+ }
262
+ function isAtomicType(aType) {
263
+ return aType.kind === 0;
264
+ }
265
+ function isEnumType(aType) {
266
+ return aType.kind === 2;
267
+ }
268
+ function isImportedType(aType) {
269
+ return aType.kind === 4;
270
+ }
271
+ function isObjectType(aType) {
272
+ return aType.kind === 8;
273
+ }
274
+ function isArrayType(aType) {
275
+ return aType.kind === 9;
276
+ }
277
+ function isRecordType(aType) {
278
+ return aType.kind === 11;
279
+ }
280
+ function jayTypeToJsonSchema(type) {
281
+ if (isOptionalType(type)) {
282
+ return jayTypeToJsonSchema(type.innerType);
283
+ }
284
+ if (isAtomicType(type)) {
285
+ const name = type.name.toLowerCase();
286
+ if (name === "string" || name === "number" || name === "boolean") {
287
+ return { type: name };
288
+ }
289
+ if (name === "file") {
290
+ return { type: "string", description: "Binary file upload (JayFile)" };
291
+ }
292
+ return { type: "string" };
293
+ }
294
+ if (isEnumType(type)) {
295
+ return { type: "string", enum: type.values };
296
+ }
297
+ if (isImportedType(type)) {
298
+ return { type: "object", description: `Contract: ${type.name}` };
299
+ }
300
+ if (isArrayType(type)) {
301
+ const itemSchema = jayTypeToJsonSchema(type.itemType);
302
+ if (itemSchema) {
303
+ return { type: "array", items: itemSchema };
304
+ }
305
+ return { type: "array" };
306
+ }
307
+ if (isRecordType(type)) {
308
+ const valueSchema = jayTypeToJsonSchema(type.itemType);
309
+ if (valueSchema) {
310
+ return { type: "object", additionalProperties: valueSchema };
311
+ }
312
+ return { type: "object" };
313
+ }
314
+ if (isObjectType(type)) {
315
+ const properties = {};
316
+ const required = [];
317
+ for (const [key, propType] of Object.entries(type.props)) {
318
+ const isOpt = isOptionalType(propType);
319
+ const schema = jayTypeToJsonSchema(propType);
320
+ if (schema) {
321
+ properties[key] = schema;
322
+ if (!isOpt) {
323
+ required.push(key);
324
+ }
325
+ }
326
+ }
327
+ return {
328
+ type: "object",
329
+ properties,
330
+ ...required.length > 0 && { required }
331
+ };
332
+ }
333
+ return null;
334
+ }
335
+ var RuntimeMode = /* @__PURE__ */ ((RuntimeMode2) => {
336
+ RuntimeMode2["MainTrusted"] = "mainTrusted";
337
+ RuntimeMode2["MainSandbox"] = "mainSandbox";
338
+ RuntimeMode2["WorkerTrusted"] = "workerTrusted";
339
+ RuntimeMode2["WorkerSandbox"] = "workerSandbox";
340
+ return RuntimeMode2;
341
+ })(RuntimeMode || {});
342
+ const TS_EXTENSION = ".ts";
343
+ const JAY_QUERY_PREFIX = "?jay-";
344
+ const JAY_QUERY_HYDRATE = `${JAY_QUERY_PREFIX}hydrate`;
345
+ [
346
+ // Hydrate target
347
+ {
348
+ pattern: JAY_QUERY_HYDRATE,
349
+ buildEnv: "client",
350
+ isHydrate: true
351
+ },
352
+ // Build environments
353
+ {
354
+ pattern: `${JAY_QUERY_PREFIX}${"client"}`,
355
+ buildEnv: "client"
356
+ /* Client */
357
+ },
358
+ {
359
+ pattern: `${JAY_QUERY_PREFIX}${"server"}`,
360
+ buildEnv: "server"
361
+ /* Server */
362
+ },
363
+ // Runtime modes (with .ts suffix)
364
+ {
365
+ pattern: `${JAY_QUERY_PREFIX}${RuntimeMode.MainSandbox}${TS_EXTENSION}`,
366
+ runtimeMode: RuntimeMode.MainSandbox
367
+ },
368
+ {
369
+ pattern: `${JAY_QUERY_PREFIX}${RuntimeMode.WorkerTrusted}${TS_EXTENSION}`,
370
+ runtimeMode: RuntimeMode.WorkerTrusted
371
+ },
372
+ {
373
+ pattern: `${JAY_QUERY_PREFIX}${RuntimeMode.WorkerSandbox}${TS_EXTENSION}`,
374
+ runtimeMode: RuntimeMode.WorkerSandbox
375
+ },
376
+ // Runtime modes (without .ts suffix)
377
+ {
378
+ pattern: `${JAY_QUERY_PREFIX}${RuntimeMode.MainSandbox}`,
379
+ runtimeMode: RuntimeMode.MainSandbox
380
+ },
381
+ {
382
+ pattern: `${JAY_QUERY_PREFIX}${RuntimeMode.WorkerTrusted}`,
383
+ runtimeMode: RuntimeMode.WorkerTrusted
384
+ },
385
+ {
386
+ pattern: `${JAY_QUERY_PREFIX}${RuntimeMode.WorkerSandbox}`,
387
+ runtimeMode: RuntimeMode.WorkerSandbox
388
+ }
389
+ ];
390
+ const { html: htmlBeautify } = jsBeautify;
391
+ createRequire(import.meta.url);
392
+ function normalizeActionEntry(entry) {
393
+ if (typeof entry === "string") {
394
+ return { name: entry };
395
+ }
396
+ return { name: entry.name, action: entry.action };
397
+ }
398
+ function loadPluginManifest(pluginDir) {
399
+ const pluginYamlPath = path$1.join(pluginDir, "plugin.yaml");
400
+ if (!fs$1.existsSync(pluginYamlPath)) {
401
+ return null;
402
+ }
403
+ try {
404
+ const yamlContent = fs$1.readFileSync(pluginYamlPath, "utf-8");
405
+ return YAML.parse(yamlContent);
406
+ } catch (error) {
407
+ return null;
408
+ }
409
+ }
410
+ const s$1 = createRequire(import.meta.url), e$1 = s$1("typescript");
411
+ new Proxy(e$1, {
412
+ get(t, r) {
413
+ return t[r];
414
+ }
415
+ });
416
+ function parseActionMetadata(yamlContent, fileName) {
417
+ try {
418
+ const parsed = parseAction(yamlContent, fileName);
419
+ if (parsed.validations.length > 0) {
420
+ getLogger().warn(
421
+ `[ActionMetadata] ${fileName}: validation errors: ${parsed.validations.join(", ")}`
422
+ );
423
+ return null;
424
+ }
425
+ if (!parsed.val) {
426
+ getLogger().warn(`[ActionMetadata] ${fileName}: parsing returned no result`);
427
+ return null;
428
+ }
429
+ const action = parsed.val;
430
+ const inputJsonSchema = jayTypeToJsonSchema(action.inputType);
431
+ let inputSchema;
432
+ if (inputJsonSchema && inputJsonSchema.type === "object") {
433
+ inputSchema = {
434
+ type: "object",
435
+ properties: inputJsonSchema.properties || {},
436
+ ...inputJsonSchema.required && inputJsonSchema.required.length > 0 && { required: inputJsonSchema.required }
437
+ };
438
+ } else {
439
+ inputSchema = { type: "object", properties: {} };
440
+ }
441
+ const metadata = {
442
+ name: action.name,
443
+ description: action.description,
444
+ inputSchema
445
+ };
446
+ if (action.outputType) {
447
+ const outputJsonSchema = jayTypeToJsonSchema(action.outputType);
448
+ if (outputJsonSchema) {
449
+ metadata.outputSchema = outputJsonSchema;
450
+ }
451
+ }
452
+ return metadata;
453
+ } catch (error) {
454
+ getLogger().error(
455
+ `[ActionMetadata] Failed to parse ${fileName}: ${error instanceof Error ? error.message : error}`
456
+ );
457
+ return null;
458
+ }
459
+ }
460
+ function loadActionMetadata(filePath) {
461
+ if (!fs.existsSync(filePath)) {
462
+ getLogger().warn(`[ActionMetadata] File not found: ${filePath}`);
463
+ return null;
464
+ }
465
+ const yamlContent = fs.readFileSync(filePath, "utf-8");
466
+ const fileName = path.basename(filePath);
467
+ return parseActionMetadata(yamlContent, fileName);
468
+ }
469
+ function resolveActionMetadataPath(actionPath, pluginDir) {
470
+ return path.resolve(pluginDir, actionPath);
471
+ }
472
+ const require$2 = createRequire$1(import.meta.url);
473
+ async function discoverAndRegisterActions(options) {
474
+ const {
475
+ projectRoot,
476
+ actionsDir = "src/actions",
477
+ registry = actionRegistry,
478
+ verbose = false,
479
+ viteServer
480
+ } = options;
481
+ const result = {
482
+ actionCount: 0,
483
+ actionNames: [],
484
+ scannedFiles: []
485
+ };
486
+ const actionsPath = path.resolve(projectRoot, actionsDir);
487
+ if (!fs.existsSync(actionsPath)) {
488
+ if (verbose) {
489
+ getLogger().info(`[Actions] No actions directory found at ${actionsPath}`);
490
+ }
491
+ return result;
492
+ }
493
+ const actionFiles = await findActionFiles(actionsPath);
494
+ if (verbose) {
495
+ getLogger().info(`[Actions] Found ${actionFiles.length} action file(s)`);
496
+ }
497
+ for (const filePath of actionFiles) {
498
+ result.scannedFiles.push(filePath);
499
+ try {
500
+ let module;
501
+ if (viteServer) {
502
+ module = await viteServer.ssrLoadModule(filePath);
503
+ } else {
504
+ module = await import(filePath);
505
+ }
506
+ for (const [exportName, exportValue] of Object.entries(module)) {
507
+ if (isJayAction(exportValue)) {
508
+ registry.register(exportValue);
509
+ result.actionNames.push(exportValue.actionName);
510
+ result.actionCount++;
511
+ if (verbose) {
512
+ getLogger().info(
513
+ `[Actions] Registered: ${exportValue.actionName}`
514
+ );
515
+ }
516
+ } else if (isJayStreamAction(exportValue)) {
517
+ registry.registerStream(exportValue);
518
+ result.actionNames.push(exportValue.actionName);
519
+ result.actionCount++;
520
+ if (verbose) {
521
+ getLogger().info(
522
+ `[Actions] Registered stream: ${exportValue.actionName}`
523
+ );
524
+ }
525
+ }
526
+ }
527
+ } catch (error) {
528
+ getLogger().error(`[Actions] Failed to import ${filePath}: ${error}`);
529
+ }
530
+ }
531
+ return result;
532
+ }
533
+ async function findActionFiles(dir) {
534
+ const files = [];
535
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
536
+ for (const entry of entries) {
537
+ const fullPath = path.join(dir, entry.name);
538
+ if (entry.isDirectory()) {
539
+ const subFiles = await findActionFiles(fullPath);
540
+ files.push(...subFiles);
541
+ } else if (entry.isFile() && entry.name.endsWith(".actions.ts")) {
542
+ files.push(fullPath);
543
+ }
544
+ }
545
+ return files;
546
+ }
547
+ async function discoverAllPluginActions(options) {
548
+ const { projectRoot, registry = actionRegistry, verbose = false, viteServer } = options;
549
+ const allActions = [];
550
+ const localPluginsPath = path.join(projectRoot, "src/plugins");
551
+ if (fs.existsSync(localPluginsPath)) {
552
+ const pluginDirs = await fs.promises.readdir(localPluginsPath, { withFileTypes: true });
553
+ for (const entry of pluginDirs) {
554
+ if (entry.isDirectory()) {
555
+ const pluginPath = path.join(localPluginsPath, entry.name);
556
+ const actions = await discoverPluginActions(
557
+ pluginPath,
558
+ projectRoot,
559
+ registry,
560
+ verbose,
561
+ viteServer
562
+ );
563
+ allActions.push(...actions);
564
+ }
565
+ }
566
+ }
567
+ const npmActions = await discoverNpmPluginActions(projectRoot, registry, verbose, viteServer);
568
+ allActions.push(...npmActions);
569
+ return allActions;
570
+ }
571
+ async function discoverNpmPluginActions(projectRoot, registry, verbose, viteServer) {
572
+ const allActions = [];
573
+ const packageJsonPath = path.join(projectRoot, "package.json");
574
+ if (!fs.existsSync(packageJsonPath)) {
575
+ return allActions;
576
+ }
577
+ try {
578
+ const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, "utf-8"));
579
+ const dependencies = {
580
+ ...packageJson.dependencies,
581
+ ...packageJson.devDependencies
582
+ };
583
+ for (const packageName of Object.keys(dependencies)) {
584
+ try {
585
+ const pluginYamlPath = tryResolvePluginYaml(packageName, projectRoot);
586
+ if (!pluginYamlPath) {
587
+ continue;
588
+ }
589
+ const pluginDir = path.dirname(pluginYamlPath);
590
+ const pluginConfig = loadPluginManifest(pluginDir);
591
+ if (!pluginConfig || !pluginConfig.actions || !Array.isArray(pluginConfig.actions)) {
592
+ continue;
593
+ }
594
+ if (verbose) {
595
+ getLogger().info(
596
+ `[Actions] NPM plugin "${packageName}" declares actions: ${JSON.stringify(pluginConfig.actions)}`
597
+ );
598
+ }
599
+ const actions = await registerNpmPluginActions(
600
+ packageName,
601
+ pluginConfig,
602
+ pluginDir,
603
+ registry,
604
+ verbose,
605
+ viteServer
606
+ );
607
+ allActions.push(...actions);
608
+ } catch {
609
+ continue;
610
+ }
611
+ }
612
+ } catch (error) {
613
+ getLogger().error(`[Actions] Failed to read project package.json: ${error}`);
614
+ }
615
+ return allActions;
616
+ }
617
+ function tryResolvePluginYaml(packageName, projectRoot) {
618
+ try {
619
+ return require$2.resolve(`${packageName}/plugin.yaml`, {
620
+ paths: [projectRoot]
621
+ });
622
+ } catch {
623
+ return null;
624
+ }
625
+ }
626
+ function resolveNpmActionMetadataPath(actionPath, packageName, pluginDir) {
627
+ if (!actionPath.startsWith(".")) {
628
+ try {
629
+ return require$2.resolve(`${packageName}/${actionPath}`, {
630
+ paths: [pluginDir]
631
+ });
632
+ } catch {
633
+ }
634
+ }
635
+ const resolved = resolveActionMetadataPath(actionPath, pluginDir);
636
+ if (fs.existsSync(resolved)) {
637
+ return resolved;
638
+ }
639
+ getLogger().warn(
640
+ `[Actions] Could not resolve .jay-action file "${actionPath}" for package "${packageName}"`
641
+ );
642
+ return null;
643
+ }
644
+ async function registerNpmPluginActions(packageName, pluginConfig, pluginDir, registry, verbose, viteServer) {
645
+ const registeredActions = [];
646
+ try {
647
+ let pluginModule;
648
+ if (viteServer) {
649
+ pluginModule = await viteServer.ssrLoadModule(packageName);
650
+ } else {
651
+ pluginModule = await import(packageName);
652
+ }
653
+ for (const entry of pluginConfig.actions) {
654
+ const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
655
+ const actionExport = pluginModule[actionName];
656
+ if (actionExport && isJayAction(actionExport)) {
657
+ registry.register(actionExport);
658
+ const registeredName = actionExport.actionName;
659
+ registeredActions.push(registeredName);
660
+ if (actionPath) {
661
+ const metadataFilePath = resolveNpmActionMetadataPath(
662
+ actionPath,
663
+ packageName,
664
+ pluginDir
665
+ );
666
+ if (metadataFilePath) {
667
+ const metadata = loadActionMetadata(metadataFilePath);
668
+ if (metadata) {
669
+ registry.setMetadata(registeredName, metadata);
670
+ if (verbose) {
671
+ getLogger().info(
672
+ `[Actions] Loaded metadata for "${registeredName}" from ${actionPath}`
673
+ );
674
+ }
675
+ }
676
+ }
677
+ }
678
+ if (verbose) {
679
+ getLogger().info(`[Actions] Registered NPM plugin action: ${registeredName}`);
680
+ }
681
+ } else if (actionExport && isJayStreamAction(actionExport)) {
682
+ registry.registerStream(actionExport);
683
+ const registeredName = actionExport.actionName;
684
+ registeredActions.push(registeredName);
685
+ if (verbose) {
686
+ getLogger().info(`[Actions] Registered NPM plugin stream: ${registeredName}`);
687
+ }
688
+ } else {
689
+ getLogger().warn(
690
+ `[Actions] NPM plugin "${packageName}" declares action "${actionName}" but it's not exported or not a JayAction`
691
+ );
692
+ }
693
+ }
694
+ } catch (importError) {
695
+ getLogger().error(`[Actions] Failed to import NPM plugin "${packageName}": ${importError}`);
696
+ }
697
+ return registeredActions;
698
+ }
699
+ async function discoverPluginActions(pluginPath, projectRoot, registry = actionRegistry, verbose = false, viteServer) {
700
+ const pluginConfig = loadPluginManifest(pluginPath);
701
+ if (!pluginConfig) {
702
+ return [];
703
+ }
704
+ if (!pluginConfig.actions || !Array.isArray(pluginConfig.actions)) {
705
+ return [];
706
+ }
707
+ const registeredActions = [];
708
+ const pluginName = pluginConfig.name || path.basename(pluginPath);
709
+ if (verbose) {
710
+ getLogger().info(
711
+ `[Actions] Plugin "${pluginName}" declares actions: ${JSON.stringify(pluginConfig.actions)}`
712
+ );
713
+ }
714
+ let modulePath = pluginConfig.module ? path.join(pluginPath, pluginConfig.module) : path.join(pluginPath, "index.ts");
715
+ if (!fs.existsSync(modulePath)) {
716
+ const tsPath = modulePath + ".ts";
717
+ const jsPath = modulePath + ".js";
718
+ if (fs.existsSync(tsPath)) {
719
+ modulePath = tsPath;
720
+ } else if (fs.existsSync(jsPath)) {
721
+ modulePath = jsPath;
722
+ } else {
723
+ getLogger().warn(`[Actions] Plugin "${pluginName}" module not found at ${modulePath}`);
724
+ return [];
725
+ }
726
+ }
727
+ try {
728
+ let pluginModule;
729
+ if (viteServer) {
730
+ pluginModule = await viteServer.ssrLoadModule(modulePath);
731
+ } else {
732
+ pluginModule = await import(modulePath);
733
+ }
734
+ for (const entry of pluginConfig.actions) {
735
+ const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
736
+ const actionExport = pluginModule[actionName];
737
+ if (actionExport && isJayAction(actionExport)) {
738
+ registry.register(actionExport);
739
+ const registeredName = actionExport.actionName;
740
+ registeredActions.push(registeredName);
741
+ if (actionPath) {
742
+ const metadataFilePath = resolveActionMetadataPath(actionPath, pluginPath);
743
+ const metadata = loadActionMetadata(metadataFilePath);
744
+ if (metadata) {
745
+ registry.setMetadata(registeredName, metadata);
746
+ if (verbose) {
747
+ getLogger().info(
748
+ `[Actions] Loaded metadata for "${registeredName}" from ${actionPath}`
749
+ );
750
+ }
751
+ }
752
+ }
753
+ if (verbose) {
754
+ getLogger().info(`[Actions] Registered plugin action: ${registeredName}`);
755
+ }
756
+ } else if (actionExport && isJayStreamAction(actionExport)) {
757
+ registry.registerStream(actionExport);
758
+ const registeredName = actionExport.actionName;
759
+ registeredActions.push(registeredName);
760
+ if (verbose) {
761
+ getLogger().info(`[Actions] Registered plugin stream: ${registeredName}`);
762
+ }
763
+ } else {
764
+ getLogger().warn(
765
+ `[Actions] Plugin "${pluginName}" declares action "${actionName}" but it's not exported or not a JayAction`
766
+ );
767
+ }
768
+ }
769
+ } catch (importError) {
770
+ getLogger().error(
771
+ `[Actions] Failed to import plugin module at ${modulePath}: ${importError}`
772
+ );
773
+ }
774
+ return registeredActions;
775
+ }
776
+ const require$1 = createRequire(import.meta.url);
777
+ async function executeDynamicGenerator(plugin, config, projectRoot, services, verbose, viteServer) {
778
+ const { pluginPath, name: pluginName, isLocal, packageName } = plugin;
779
+ if (!config.generator) {
780
+ throw new Error(
781
+ `Plugin "${pluginName}" has dynamic_contracts entry but no generator specified`
782
+ );
783
+ }
784
+ const isFilePath = config.generator.startsWith("./") || config.generator.startsWith("/") || config.generator.includes(".ts") || config.generator.includes(".js");
785
+ let generator;
786
+ if (isFilePath) {
787
+ let generatorPath;
788
+ if (!isLocal) {
789
+ try {
790
+ generatorPath = require$1.resolve(`${packageName}/${config.generator}`, {
791
+ paths: [projectRoot]
792
+ });
793
+ } catch {
794
+ generatorPath = path.join(pluginPath, config.generator);
795
+ }
796
+ } else {
797
+ generatorPath = path.join(pluginPath, config.generator);
798
+ }
799
+ if (!fs.existsSync(generatorPath)) {
800
+ const withTs = generatorPath + ".ts";
801
+ const withJs = generatorPath + ".js";
802
+ if (fs.existsSync(withTs)) {
803
+ generatorPath = withTs;
804
+ } else if (fs.existsSync(withJs)) {
805
+ generatorPath = withJs;
806
+ }
807
+ }
808
+ if (!fs.existsSync(generatorPath)) {
809
+ throw new Error(
810
+ `Generator file not found for plugin "${pluginName}": ${config.generator}`
811
+ );
812
+ }
813
+ if (verbose) {
814
+ getLogger().info(` Loading generator from file: ${generatorPath}`);
815
+ }
816
+ let generatorModule;
817
+ if (viteServer) {
818
+ generatorModule = await viteServer.ssrLoadModule(generatorPath);
819
+ } else {
820
+ generatorModule = await import(generatorPath);
821
+ }
822
+ generator = generatorModule.generator || generatorModule.default;
823
+ } else {
824
+ if (verbose) {
825
+ getLogger().info(
826
+ ` Loading generator export: ${config.generator} from ${packageName}`
827
+ );
828
+ }
829
+ let pluginModule;
830
+ if (viteServer) {
831
+ pluginModule = await viteServer.ssrLoadModule(packageName);
832
+ } else {
833
+ pluginModule = await import(packageName);
834
+ }
835
+ generator = pluginModule[config.generator];
836
+ if (!generator) {
837
+ throw new Error(
838
+ `Generator "${config.generator}" not exported from plugin "${pluginName}". Ensure it's exported from the package's index.ts`
839
+ );
840
+ }
841
+ }
842
+ if (!generator || typeof generator.generate !== "function") {
843
+ throw new Error(
844
+ `Generator "${config.generator}" for plugin "${pluginName}" must have a 'generate' function. Use makeContractGenerator() to create valid generators.`
845
+ );
846
+ }
847
+ const resolvedServices = [];
848
+ for (const marker of generator.services) {
849
+ const service = services.get(marker);
850
+ if (!service) {
851
+ const markerName = marker.description ?? "unknown";
852
+ throw new Error(
853
+ `Service "${markerName}" required by ${pluginName} generator not found. Ensure it's registered in init.ts`
854
+ );
855
+ }
856
+ resolvedServices.push(service);
857
+ }
858
+ if (verbose) {
859
+ getLogger().info(` Executing generator...`);
860
+ }
861
+ return await generator.generate(...resolvedServices);
862
+ }
863
+ function resolveStaticContractPath(plugin, contractSpec, projectRoot) {
864
+ const { pluginPath, isLocal, packageName } = plugin;
865
+ if (!isLocal) {
866
+ try {
867
+ return require$1.resolve(`${packageName}/${contractSpec}`, {
868
+ paths: [projectRoot]
869
+ });
870
+ } catch {
871
+ const possiblePaths = [
872
+ path.join(pluginPath, "dist", contractSpec),
873
+ path.join(pluginPath, "lib", contractSpec),
874
+ path.join(pluginPath, contractSpec)
875
+ ];
876
+ const found = possiblePaths.find((p) => fs.existsSync(p));
877
+ return found || possiblePaths[0];
878
+ }
879
+ } else {
880
+ return path.join(pluginPath, contractSpec);
881
+ }
882
+ }
883
+ function resolveActionFilePath(actionPath, packageName, pluginPath, isLocal, projectRoot) {
884
+ if (!isLocal && !actionPath.startsWith(".")) {
885
+ try {
886
+ return require$1.resolve(`${packageName}/${actionPath}`, {
887
+ paths: [projectRoot]
888
+ });
889
+ } catch {
890
+ const possiblePaths = [
891
+ path.join(pluginPath, "dist", actionPath),
892
+ path.join(pluginPath, "lib", actionPath),
893
+ path.join(pluginPath, actionPath)
894
+ ];
895
+ const found = possiblePaths.find((p) => fs.existsSync(p));
896
+ return found || null;
897
+ }
898
+ }
899
+ const resolved = resolveActionMetadataPath(actionPath, pluginPath);
900
+ return fs.existsSync(resolved) ? resolved : null;
901
+ }
902
+ function toKebabCase(str) {
903
+ return str.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
904
+ }
905
+ async function materializeContracts(options, services = /* @__PURE__ */ new Map()) {
906
+ const {
907
+ projectRoot,
908
+ outputDir = path.join(projectRoot, "agent-kit", "materialized-contracts"),
909
+ dynamicOnly = false,
910
+ pluginFilter,
911
+ verbose = false,
912
+ viteServer
913
+ } = options;
914
+ const pluginsIndexMap = /* @__PURE__ */ new Map();
915
+ let staticCount = 0;
916
+ let dynamicCount = 0;
917
+ if (verbose) {
918
+ getLogger().info("Scanning for plugins...");
919
+ }
920
+ const plugins = await scanPlugins({
921
+ projectRoot,
922
+ verbose,
923
+ includeDevDeps: true
924
+ // Include dev deps for contract discovery
925
+ });
926
+ if (verbose) {
927
+ getLogger().info(`Found ${plugins.size} plugin(s)`);
928
+ }
929
+ for (const [pluginKey, plugin] of plugins) {
930
+ if (pluginFilter && plugin.name !== pluginFilter && pluginKey !== pluginFilter) continue;
931
+ if (verbose) {
932
+ getLogger().info(`
933
+ šŸ“¦ Processing plugin: ${plugin.name}`);
934
+ }
935
+ const { manifest } = plugin;
936
+ const pluginRelPath = path.relative(projectRoot, plugin.pluginPath);
937
+ if (!pluginsIndexMap.has(plugin.name)) {
938
+ const entry = {
939
+ path: "./" + pluginRelPath.replace(/\\/g, "/"),
940
+ contracts: [],
941
+ actions: []
942
+ };
943
+ if (manifest.services?.length) {
944
+ entry.services = manifest.services.map((s2) => {
945
+ const docPath = s2.doc ? "./" + path.relative(projectRoot, path.resolve(plugin.pluginPath, s2.doc)) : void 0;
946
+ return {
947
+ name: s2.name,
948
+ marker: s2.marker,
949
+ ...s2.description && { description: s2.description },
950
+ ...docPath && { doc: docPath }
951
+ };
952
+ });
953
+ }
954
+ if (manifest.contexts?.length) {
955
+ entry.contexts = manifest.contexts.map((c) => {
956
+ const docPath = c.doc ? "./" + path.relative(projectRoot, path.resolve(plugin.pluginPath, c.doc)) : void 0;
957
+ return {
958
+ name: c.name,
959
+ marker: c.marker,
960
+ ...c.description && { description: c.description },
961
+ ...docPath && { doc: docPath }
962
+ };
963
+ });
964
+ }
965
+ if (manifest.routes?.length) {
966
+ entry.routes = manifest.routes.map((r) => ({
967
+ path: r.path,
968
+ ...r.description && { description: r.description }
969
+ }));
970
+ }
971
+ if (manifest.commands?.length) {
972
+ entry.commands = manifest.commands.map((c) => {
973
+ let description;
974
+ if (c.command) {
975
+ try {
976
+ const cmdPath = path.resolve(plugin.pluginPath, c.command);
977
+ const cmdContent = fs.readFileSync(cmdPath, "utf-8");
978
+ const parsed = YAML.parse(cmdContent);
979
+ description = parsed?.description;
980
+ } catch {
981
+ }
982
+ }
983
+ return {
984
+ name: c.name,
985
+ ...description && { description }
986
+ };
987
+ });
988
+ }
989
+ pluginsIndexMap.set(plugin.name, entry);
990
+ }
991
+ if (!dynamicOnly && manifest.contracts) {
992
+ for (const contract of manifest.contracts) {
993
+ const contractPath = resolveStaticContractPath(
994
+ plugin,
995
+ contract.contract,
996
+ projectRoot
997
+ );
998
+ const relativePath = path.relative(projectRoot, contractPath);
999
+ let description = contract.description;
1000
+ if (!description) {
1001
+ try {
1002
+ const contractContent = fs.readFileSync(contractPath, "utf-8");
1003
+ const parsed = YAML.parse(contractContent);
1004
+ if (parsed?.description && typeof parsed.description === "string") {
1005
+ description = parsed.description;
1006
+ }
1007
+ } catch {
1008
+ }
1009
+ }
1010
+ pluginsIndexMap.get(plugin.name).contracts.push({
1011
+ name: contract.name,
1012
+ ...description && { description },
1013
+ type: "static",
1014
+ path: "./" + relativePath
1015
+ });
1016
+ staticCount++;
1017
+ if (verbose) {
1018
+ getLogger().info(` šŸ“„ Static: ${contract.name}`);
1019
+ }
1020
+ }
1021
+ }
1022
+ if (manifest.dynamic_contracts) {
1023
+ const dynamicConfigs = Array.isArray(manifest.dynamic_contracts) ? manifest.dynamic_contracts : [manifest.dynamic_contracts];
1024
+ const pluginOutputDir = path.join(outputDir, plugin.name.replace(/[@/]/g, "_"));
1025
+ fs.mkdirSync(pluginOutputDir, { recursive: true });
1026
+ for (const config of dynamicConfigs) {
1027
+ if (verbose) {
1028
+ getLogger().info(` ⚔ Dynamic contracts (prefix: ${config.prefix})`);
1029
+ }
1030
+ try {
1031
+ const generatedContracts = await executeDynamicGenerator(
1032
+ plugin,
1033
+ config,
1034
+ projectRoot,
1035
+ services,
1036
+ verbose,
1037
+ viteServer
1038
+ );
1039
+ const prefix = config.prefix;
1040
+ if (generatedContracts.length > 1) {
1041
+ const missing = generatedContracts.filter((c) => !c.name);
1042
+ if (missing.length > 0) {
1043
+ getLogger().error(
1044
+ ` āŒ Dynamic contract generator for "${prefix}" returned ${generatedContracts.length} contracts but ${missing.length} are missing a name. Names are required when a generator returns multiple contracts.`
1045
+ );
1046
+ continue;
1047
+ }
1048
+ }
1049
+ for (const generated of generatedContracts) {
1050
+ const kebabName = generated.name ? toKebabCase(generated.name) : null;
1051
+ const fullName = kebabName ? `${prefix}/${kebabName}` : prefix;
1052
+ const fileName = kebabName ? `${prefix}-${kebabName}.jay-contract` : `${prefix}.jay-contract`;
1053
+ const filePath = path.join(pluginOutputDir, fileName);
1054
+ fs.writeFileSync(filePath, generated.yaml, "utf-8");
1055
+ const relativePath = path.relative(projectRoot, filePath);
1056
+ let dynDescription;
1057
+ try {
1058
+ const parsedYaml = YAML.parse(generated.yaml);
1059
+ if (parsedYaml?.description && typeof parsedYaml.description === "string") {
1060
+ dynDescription = parsedYaml.description;
1061
+ }
1062
+ } catch {
1063
+ }
1064
+ const contractEntry = {
1065
+ name: fullName,
1066
+ ...dynDescription && { description: dynDescription },
1067
+ type: "dynamic",
1068
+ path: "./" + relativePath,
1069
+ ...generated.metadata && { metadata: generated.metadata }
1070
+ };
1071
+ pluginsIndexMap.get(plugin.name).contracts.push(contractEntry);
1072
+ dynamicCount++;
1073
+ if (verbose) {
1074
+ getLogger().info(` ⚔ Materialized: ${fullName}`);
1075
+ }
1076
+ }
1077
+ } catch (error) {
1078
+ getLogger().error(
1079
+ ` āŒ Failed to materialize dynamic contracts for ${plugin.name} (${config.prefix}): ${error}`
1080
+ );
1081
+ }
1082
+ }
1083
+ }
1084
+ if (manifest.actions && Array.isArray(manifest.actions)) {
1085
+ for (const entry of manifest.actions) {
1086
+ const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
1087
+ if (!actionPath) continue;
1088
+ const metadataFilePath = resolveActionFilePath(
1089
+ actionPath,
1090
+ plugin.packageName,
1091
+ plugin.pluginPath,
1092
+ plugin.isLocal,
1093
+ projectRoot
1094
+ );
1095
+ if (!metadataFilePath) continue;
1096
+ const metadata = loadActionMetadata(metadataFilePath);
1097
+ if (!metadata) continue;
1098
+ const actionRelPath = path.relative(projectRoot, metadataFilePath);
1099
+ const pluginEntry = pluginsIndexMap.get(plugin.name);
1100
+ if (!pluginEntry.actions) pluginEntry.actions = [];
1101
+ pluginEntry.actions.push({
1102
+ name: metadata.name,
1103
+ description: metadata.description,
1104
+ path: "./" + actionRelPath.replace(/\\/g, "/")
1105
+ });
1106
+ if (verbose) {
1107
+ getLogger().info(` šŸ”§ Action: ${metadata.name} (${actionPath})`);
1108
+ }
1109
+ }
1110
+ }
1111
+ }
1112
+ const pluginsIndex = {
1113
+ plugins: Array.from(pluginsIndexMap.entries()).map(([name, data]) => ({
1114
+ name,
1115
+ path: data.path,
1116
+ contracts: data.contracts,
1117
+ ...data.actions && data.actions.length > 0 && { actions: data.actions },
1118
+ ...data.services?.length && { services: data.services },
1119
+ ...data.contexts?.length && { contexts: data.contexts },
1120
+ ...data.routes?.length && { routes: data.routes },
1121
+ ...data.commands?.length && { commands: data.commands }
1122
+ }))
1123
+ };
1124
+ fs.mkdirSync(outputDir, { recursive: true });
1125
+ const agentKitDir = path.dirname(outputDir);
1126
+ const pluginsIndexPath = path.join(agentKitDir, "plugins-index.yaml");
1127
+ fs.writeFileSync(pluginsIndexPath, YAML.stringify(pluginsIndex), "utf-8");
1128
+ if (verbose) {
1129
+ getLogger().info(`
1130
+ āœ… Plugins index written to: ${pluginsIndexPath}`);
1131
+ }
1132
+ return {
1133
+ pluginsIndex,
1134
+ staticCount,
1135
+ dynamicCount,
1136
+ outputDir
1137
+ };
1138
+ }
1139
+ async function listContracts(options) {
1140
+ const { projectRoot, dynamicOnly = false, pluginFilter } = options;
1141
+ const pluginsMap = /* @__PURE__ */ new Map();
1142
+ const plugins = await scanPlugins({
1143
+ projectRoot,
1144
+ includeDevDeps: true
1145
+ });
1146
+ for (const [pluginKey, plugin] of plugins) {
1147
+ if (pluginFilter && plugin.name !== pluginFilter && pluginKey !== pluginFilter) continue;
1148
+ const { manifest } = plugin;
1149
+ const pluginRelPath = path.relative(projectRoot, plugin.pluginPath);
1150
+ if (!pluginsMap.has(plugin.name)) {
1151
+ const entry = {
1152
+ path: "./" + pluginRelPath.replace(/\\/g, "/"),
1153
+ contracts: []
1154
+ };
1155
+ if (manifest.services?.length) {
1156
+ entry.services = manifest.services.map((s2) => {
1157
+ const docPath = s2.doc ? "./" + path.relative(projectRoot, path.resolve(plugin.pluginPath, s2.doc)) : void 0;
1158
+ return {
1159
+ name: s2.name,
1160
+ marker: s2.marker,
1161
+ ...s2.description && { description: s2.description },
1162
+ ...docPath && { doc: docPath }
1163
+ };
1164
+ });
1165
+ }
1166
+ if (manifest.contexts?.length) {
1167
+ entry.contexts = manifest.contexts.map((c) => {
1168
+ const docPath = c.doc ? "./" + path.relative(projectRoot, path.resolve(plugin.pluginPath, c.doc)) : void 0;
1169
+ return {
1170
+ name: c.name,
1171
+ marker: c.marker,
1172
+ ...c.description && { description: c.description },
1173
+ ...docPath && { doc: docPath }
1174
+ };
1175
+ });
1176
+ }
1177
+ if (manifest.routes?.length) {
1178
+ entry.routes = manifest.routes.map((r) => ({
1179
+ path: r.path,
1180
+ ...r.description && { description: r.description }
1181
+ }));
1182
+ }
1183
+ if (manifest.commands?.length) {
1184
+ entry.commands = manifest.commands.map((c) => {
1185
+ let description;
1186
+ if (c.command) {
1187
+ try {
1188
+ const cmdPath = path.resolve(plugin.pluginPath, c.command);
1189
+ const cmdContent = fs.readFileSync(cmdPath, "utf-8");
1190
+ const parsed = YAML.parse(cmdContent);
1191
+ description = parsed?.description;
1192
+ } catch {
1193
+ }
1194
+ }
1195
+ return {
1196
+ name: c.name,
1197
+ ...description && { description }
1198
+ };
1199
+ });
1200
+ }
1201
+ pluginsMap.set(plugin.name, entry);
1202
+ }
1203
+ if (!dynamicOnly && manifest.contracts) {
1204
+ for (const contract of manifest.contracts) {
1205
+ const contractPath = resolveStaticContractPath(
1206
+ plugin,
1207
+ contract.contract,
1208
+ projectRoot
1209
+ );
1210
+ const relativePath = path.relative(projectRoot, contractPath);
1211
+ let listDescription = contract.description;
1212
+ if (!listDescription) {
1213
+ try {
1214
+ const contractContent = fs.readFileSync(contractPath, "utf-8");
1215
+ const parsed = YAML.parse(contractContent);
1216
+ if (parsed?.description && typeof parsed.description === "string") {
1217
+ listDescription = parsed.description;
1218
+ }
1219
+ } catch {
1220
+ }
1221
+ }
1222
+ pluginsMap.get(plugin.name).contracts.push({
1223
+ name: contract.name,
1224
+ ...listDescription && { description: listDescription },
1225
+ type: "static",
1226
+ path: "./" + relativePath
1227
+ });
1228
+ }
1229
+ }
1230
+ if (manifest.dynamic_contracts) {
1231
+ const dynamicConfigs = Array.isArray(manifest.dynamic_contracts) ? manifest.dynamic_contracts : [manifest.dynamic_contracts];
1232
+ for (const config of dynamicConfigs) {
1233
+ pluginsMap.get(plugin.name).contracts.push({
1234
+ name: `${config.prefix}/*`,
1235
+ type: "dynamic",
1236
+ path: "(run materialization to generate)"
1237
+ });
1238
+ }
1239
+ }
1240
+ }
1241
+ return {
1242
+ plugins: Array.from(pluginsMap.entries()).map(([name, data]) => ({
1243
+ name,
1244
+ path: data.path,
1245
+ contracts: data.contracts,
1246
+ ...data.services?.length && { services: data.services },
1247
+ ...data.contexts?.length && { contexts: data.contexts },
1248
+ ...data.routes?.length && { routes: data.routes },
1249
+ ...data.commands?.length && { commands: data.commands }
1250
+ }))
1251
+ };
1252
+ }
1253
+ async function discoverPluginCommands(options) {
1254
+ const { projectRoot, verbose, pluginFilter } = options;
1255
+ const allPlugins = await scanPlugins({
1256
+ projectRoot,
1257
+ verbose,
1258
+ discoverTransitive: true,
1259
+ includeDevDeps: true
1260
+ });
1261
+ const commands = [];
1262
+ for (const [packageName, plugin] of allPlugins) {
1263
+ if (!plugin.manifest.commands || plugin.manifest.commands.length === 0) continue;
1264
+ if (pluginFilter && plugin.name !== pluginFilter && packageName !== pluginFilter) {
1265
+ continue;
1266
+ }
1267
+ for (const cmd of plugin.manifest.commands) {
1268
+ let metadata;
1269
+ let metadataPath;
1270
+ if (cmd.command) {
1271
+ metadataPath = path.resolve(plugin.pluginPath, cmd.command);
1272
+ metadata = loadCommandMetadata(metadataPath);
1273
+ }
1274
+ commands.push({
1275
+ pluginName: plugin.name,
1276
+ pluginPath: plugin.pluginPath,
1277
+ packageName: plugin.packageName,
1278
+ isLocal: plugin.isLocal,
1279
+ commandName: cmd.name,
1280
+ handlerExport: cmd.name,
1281
+ pluginModule: plugin.manifest.module,
1282
+ metadata,
1283
+ metadataPath
1284
+ });
1285
+ if (verbose) {
1286
+ getLogger().info(`[Commands] Found ${plugin.name}/${cmd.name}`);
1287
+ }
1288
+ }
1289
+ }
1290
+ return commands;
1291
+ }
1292
+ function loadCommandMetadata(filePath) {
1293
+ try {
1294
+ const content = fs.readFileSync(filePath, "utf-8");
1295
+ return YAML.parse(content);
1296
+ } catch {
1297
+ return void 0;
1298
+ }
1299
+ }
1300
+ function commandSchemaToFlags(inputSchema) {
1301
+ const flags = [];
1302
+ for (const [field, type] of Object.entries(inputSchema)) {
1303
+ const isOptional = field.endsWith("?");
1304
+ const cleanName = isOptional ? field.slice(0, -1) : field;
1305
+ const kebabName = camelToKebab(cleanName);
1306
+ const cleanType = type.toLowerCase().trim();
1307
+ const isBoolean = cleanType === "boolean";
1308
+ flags.push({
1309
+ flag: isBoolean ? `--${kebabName}` : `--${kebabName} <value>`,
1310
+ description: "",
1311
+ required: !isOptional,
1312
+ type: cleanType === "number" ? "number" : isBoolean ? "boolean" : "string"
1313
+ });
1314
+ }
1315
+ return flags;
1316
+ }
1317
+ function camelToKebab(str) {
1318
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
1319
+ }
1320
+ function parseInputFromFlags(rawOptions, schema) {
1321
+ const input2 = {};
1322
+ for (const [field, type] of Object.entries(schema)) {
1323
+ const isOptional = field.endsWith("?");
1324
+ const cleanName = isOptional ? field.slice(0, -1) : field;
1325
+ const kebabName = camelToKebab(cleanName);
1326
+ const value = rawOptions[kebabName];
1327
+ if (value === void 0) {
1328
+ if (!isOptional) {
1329
+ throw new Error(`Missing required flag: --${kebabName}`);
1330
+ }
1331
+ continue;
1332
+ }
1333
+ const cleanType = type.toLowerCase().trim();
1334
+ if (cleanType === "number") {
1335
+ const parsed = Number(value);
1336
+ if (isNaN(parsed)) throw new Error(`Flag --${kebabName} must be a number`);
1337
+ input2[cleanName] = parsed;
1338
+ } else if (cleanType === "boolean") {
1339
+ input2[cleanName] = value === true || value === "true";
1340
+ } else {
1341
+ input2[cleanName] = String(value);
1342
+ }
1343
+ }
1344
+ return input2;
1345
+ }
1346
+ async function executePluginCommand(command, input2, viteServer) {
1347
+ const cliCommand = await loadCommandHandler(command, viteServer);
1348
+ const services = resolveServices(cliCommand.services);
1349
+ return cliCommand.handler(input2, ...services);
1350
+ }
1351
+ async function loadCommandHandler(command, viteServer) {
1352
+ let module;
1353
+ if (command.isLocal) {
1354
+ const moduleFile = command.pluginModule || "index";
1355
+ const modulePath = path.resolve(command.pluginPath, moduleFile);
1356
+ if (viteServer) {
1357
+ module = await viteServer.ssrLoadModule(modulePath);
1358
+ } else {
1359
+ module = await import(modulePath);
1360
+ }
1361
+ } else {
1362
+ if (viteServer) {
1363
+ module = await viteServer.ssrLoadModule(command.packageName);
1364
+ } else {
1365
+ module = await import(command.packageName);
1366
+ }
1367
+ }
1368
+ for (const [, exported] of Object.entries(module)) {
1369
+ if (isJayCliCommand(exported) && exported.commandName === command.commandName) {
1370
+ return exported;
1371
+ }
1372
+ }
1373
+ const byName = module[command.handlerExport];
1374
+ if (byName && isJayCliCommand(byName)) {
1375
+ return byName;
1376
+ }
1377
+ throw new Error(
1378
+ `CLI command "${command.commandName}" not found as export in "${command.isLocal ? command.pluginPath : command.packageName}". Available exports: ${Object.keys(module).join(", ")}`
1379
+ );
1380
+ }
1381
+ class SetupNeedsAnswerError extends Error {
1382
+ constructor(plugin, key, type, promptMessage, choices) {
1383
+ super(`Setup needs answer for "${key}": ${promptMessage}`);
1384
+ this.plugin = plugin;
1385
+ this.key = key;
1386
+ this.type = type;
1387
+ this.promptMessage = promptMessage;
1388
+ this.choices = choices;
1389
+ this.name = "SetupNeedsAnswerError";
1390
+ }
1391
+ }
1392
+ async function discoverPluginsWithSetup(options) {
1393
+ const { projectRoot, verbose, pluginFilter } = options;
1394
+ const allPlugins = await scanPlugins({
1395
+ projectRoot,
1396
+ verbose,
1397
+ includeDevDeps: true,
1398
+ discoverTransitive: true
1399
+ });
1400
+ const pluginsWithSetup = [];
1401
+ for (const [packageName, plugin] of allPlugins) {
1402
+ if (!plugin.manifest.setup) continue;
1403
+ if (pluginFilter && plugin.name !== pluginFilter && packageName !== pluginFilter) {
1404
+ continue;
1405
+ }
1406
+ pluginsWithSetup.push({
1407
+ name: plugin.name,
1408
+ pluginPath: plugin.pluginPath,
1409
+ packageName: plugin.packageName,
1410
+ isLocal: plugin.isLocal,
1411
+ setupHandler: plugin.manifest.setup,
1412
+ setupDescription: plugin.manifest.description,
1413
+ dependencies: plugin.dependencies
1414
+ });
1415
+ if (verbose) {
1416
+ getLogger().info(`[Setup] Found plugin with setup: ${plugin.name}`);
1417
+ }
1418
+ }
1419
+ return sortPluginsByDependencies(pluginsWithSetup);
1420
+ }
1421
+ async function discoverPluginsWithAgentKit(options) {
1422
+ const { projectRoot, verbose, pluginFilter } = options;
1423
+ const allPlugins = await scanPlugins({
1424
+ projectRoot,
1425
+ verbose,
1426
+ includeDevDeps: true,
1427
+ discoverTransitive: true
1428
+ });
1429
+ const pluginsWithAgentKit = [];
1430
+ for (const [packageName, plugin] of allPlugins) {
1431
+ if (!plugin.manifest.agentkit) continue;
1432
+ if (pluginFilter && plugin.name !== pluginFilter && packageName !== pluginFilter) {
1433
+ continue;
1434
+ }
1435
+ pluginsWithAgentKit.push({
1436
+ name: plugin.name,
1437
+ pluginPath: plugin.pluginPath,
1438
+ packageName: plugin.packageName,
1439
+ isLocal: plugin.isLocal,
1440
+ agentKitHandler: plugin.manifest.agentkit,
1441
+ dependencies: plugin.dependencies
1442
+ });
1443
+ if (verbose) {
1444
+ getLogger().info(`[AgentKit] Found plugin with agent-kit handler: ${plugin.name}`);
1445
+ }
1446
+ }
1447
+ return sortPluginsByDependencies(pluginsWithAgentKit);
1448
+ }
1449
+ async function executePluginSetup(plugin, options) {
1450
+ const { projectRoot, configDir, force, interactive, prompt, initError, viteServer } = options;
1451
+ const context = {
1452
+ pluginName: plugin.name,
1453
+ projectRoot,
1454
+ configDir,
1455
+ services: getServiceRegistry(),
1456
+ initError,
1457
+ force,
1458
+ interactive,
1459
+ prompt
1460
+ };
1461
+ const handler = await loadHandler(plugin, plugin.setupHandler, viteServer);
1462
+ return handler(context);
1463
+ }
1464
+ async function executePluginAgentKit(plugin, options) {
1465
+ const { projectRoot, force, initError, viteServer } = options;
1466
+ const referencesDir = path.join(projectRoot, "agent-kit", "references", plugin.name);
1467
+ const context = {
1468
+ pluginName: plugin.name,
1469
+ projectRoot,
1470
+ referencesDir,
1471
+ services: getServiceRegistry(),
1472
+ initError,
1473
+ force
1474
+ };
1475
+ const handler = await loadHandler(
1476
+ plugin,
1477
+ plugin.agentKitHandler,
1478
+ viteServer
1479
+ );
1480
+ return handler(context);
1481
+ }
1482
+ async function loadHandler(plugin, handlerName, viteServer) {
1483
+ let module;
1484
+ if (plugin.isLocal) {
1485
+ const handlerPath = path.resolve(plugin.pluginPath, handlerName);
1486
+ if (viteServer) {
1487
+ module = await viteServer.ssrLoadModule(handlerPath);
1488
+ } else {
1489
+ module = await import(handlerPath);
1490
+ }
1491
+ if (typeof module[handlerName] === "function") return module[handlerName];
1492
+ if (typeof module.agentkit === "function") return module.agentkit;
1493
+ if (typeof module.setup === "function") return module.setup;
1494
+ if (typeof module.default === "function") return module.default;
1495
+ throw new Error(
1496
+ `Handler "${handlerName}" not found in "${plugin.pluginPath}". Available exports: ${Object.keys(module).join(", ")}`
1497
+ );
1498
+ } else {
1499
+ if (viteServer) {
1500
+ module = await viteServer.ssrLoadModule(plugin.packageName);
1501
+ } else {
1502
+ module = await import(plugin.packageName);
1503
+ }
1504
+ if (typeof module[handlerName] !== "function") {
1505
+ throw new Error(
1506
+ `Handler "${handlerName}" not found as export in "${plugin.packageName}". Available exports: ${Object.keys(module).join(", ")}`
1507
+ );
1508
+ }
1509
+ return module[handlerName];
1510
+ }
1511
+ }
225
1512
  async function initializeServicesForCli(projectRoot, viteServer, quiet = false) {
226
1513
  const path2 = await import("node:path");
227
1514
  const fs2 = await import("node:fs");
228
1515
  const {
229
1516
  runInitCallbacks: runInitCallbacks2,
230
- getServiceRegistry,
1517
+ getServiceRegistry: getServiceRegistry2,
231
1518
  discoverPluginsWithInit: discoverPluginsWithInit2,
232
1519
  sortPluginsByDependencies: sortPluginsByDependencies2,
233
1520
  executePluginServerInits: executePluginServerInits2
@@ -260,7 +1547,7 @@ async function initializeServicesForCli(projectRoot, viteServer, quiet = false)
260
1547
  getLogger().warn(chalk.yellow(`āš ļø Service initialization failed: ${error.message}`));
261
1548
  getLogger().warn(chalk.gray(" Static contracts will still be listed."));
262
1549
  }
263
- return { services: getServiceRegistry(), initErrors };
1550
+ return { services: getServiceRegistry2(), initErrors };
264
1551
  }
265
1552
  async function runDev(projectPath, options) {
266
1553
  const logLevel = options.quiet ? "silent" : options.verbose ? "verbose" : "info";
@@ -274,12 +1561,12 @@ async function runDev(projectPath, options) {
274
1561
  });
275
1562
  }
276
1563
  async function resolveProductionContext(projectPath, versionOverride) {
277
- const resolvedPath = path$1.resolve(projectPath || process.cwd());
278
- const jayConfigPath = path$1.join(resolvedPath, ".jay");
1564
+ const resolvedPath = path__default.resolve(projectPath || process.cwd());
1565
+ const jayConfigPath = path__default.join(resolvedPath, ".jay");
279
1566
  let pagesBase = "./src/pages";
280
1567
  let siteBaseUrl;
281
1568
  try {
282
- const jayConfig = YAML.parse(await fs$1.readFile(jayConfigPath, "utf-8"));
1569
+ const jayConfig = YAML.parse(await fs$2.readFile(jayConfigPath, "utf-8"));
283
1570
  pagesBase = jayConfig?.devServer?.pagesBase || pagesBase;
284
1571
  siteBaseUrl = jayConfig?.site?.baseUrl;
285
1572
  } catch {
@@ -287,17 +1574,17 @@ async function resolveProductionContext(projectPath, versionOverride) {
287
1574
  const version = versionOverride || await resolveVersionFromPackageJson(resolvedPath);
288
1575
  return {
289
1576
  resolvedPath,
290
- pagesRoot: path$1.resolve(resolvedPath, pagesBase),
291
- buildRoot: path$1.join(resolvedPath, "build"),
1577
+ pagesRoot: path__default.resolve(resolvedPath, pagesBase),
1578
+ buildRoot: path__default.join(resolvedPath, "build"),
292
1579
  version,
293
- tsConfigFilePath: path$1.join(resolvedPath, "tsconfig.json"),
1580
+ tsConfigFilePath: path__default.join(resolvedPath, "tsconfig.json"),
294
1581
  siteBaseUrl
295
1582
  };
296
1583
  }
297
1584
  async function resolveVersionFromPackageJson(projectRoot) {
298
1585
  try {
299
1586
  const pkgJson = JSON.parse(
300
- await fs$1.readFile(path$1.join(projectRoot, "package.json"), "utf-8")
1587
+ await fs$2.readFile(path__default.join(projectRoot, "package.json"), "utf-8")
301
1588
  );
302
1589
  if (pkgJson.version) {
303
1590
  return pkgJson.version;
@@ -313,7 +1600,7 @@ function initLogger(verbose) {
313
1600
  async function runBuild(projectPath, options) {
314
1601
  initLogger(options.verbose);
315
1602
  const ctx = await resolveProductionContext(projectPath, options.version);
316
- const { buildVersion } = await import("@jay-framework/production-server");
1603
+ const { buildVersion } = await import("./index-CatrpDqC.js");
317
1604
  await buildVersion({
318
1605
  version: ctx.version,
319
1606
  projectRoot: ctx.resolvedPath,
@@ -1158,7 +2445,7 @@ function isRelativeHandlerRef(value) {
1158
2445
  function resolveModulePath$1(basePath) {
1159
2446
  for (const ext of ["", ".ts", ".js", "/index.ts", "/index.js"]) {
1160
2447
  const candidate = basePath + ext;
1161
- if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
2448
+ if (fs$1.existsSync(candidate) && fs$1.statSync(candidate).isFile()) {
1162
2449
  return candidate;
1163
2450
  }
1164
2451
  }
@@ -1166,10 +2453,10 @@ function resolveModulePath$1(basePath) {
1166
2453
  }
1167
2454
  function collectTypeScriptFiles(dir, depth = 0) {
1168
2455
  if (depth > 4) return [];
1169
- const entries = fs.readdirSync(dir, { withFileTypes: true });
2456
+ const entries = fs$1.readdirSync(dir, { withFileTypes: true });
1170
2457
  const files = [];
1171
2458
  for (const entry of entries) {
1172
- const fullPath = path.join(dir, entry.name);
2459
+ const fullPath = path$1.join(dir, entry.name);
1173
2460
  if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "test") {
1174
2461
  files.push(...collectTypeScriptFiles(fullPath, depth + 1));
1175
2462
  } else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js"))) {
@@ -1180,13 +2467,13 @@ function collectTypeScriptFiles(dir, depth = 0) {
1180
2467
  }
1181
2468
  function resolveHandlerSourceFile(pluginPath, handlerRef, isNpmPackage) {
1182
2469
  if (isRelativeHandlerRef(handlerRef)) {
1183
- return resolveModulePath$1(path.join(pluginPath, handlerRef)) ?? null;
2470
+ return resolveModulePath$1(path$1.join(pluginPath, handlerRef)) ?? null;
1184
2471
  }
1185
- const searchRoots = isNpmPackage ? [path.join(pluginPath, "lib"), path.join(pluginPath, "dist")] : [pluginPath];
2472
+ const searchRoots = isNpmPackage ? [path$1.join(pluginPath, "lib"), path$1.join(pluginPath, "dist")] : [pluginPath];
1186
2473
  for (const root of searchRoots) {
1187
- if (!fs.existsSync(root)) continue;
2474
+ if (!fs$1.existsSync(root)) continue;
1188
2475
  for (const file of collectTypeScriptFiles(root)) {
1189
- const content = fs.readFileSync(file, "utf-8");
2476
+ const content = fs$1.readFileSync(file, "utf-8");
1190
2477
  const definesHandler = new RegExp(
1191
2478
  `export\\s+(?:async\\s+)?function\\s+${handlerRef}\\b`
1192
2479
  ).test(content);
@@ -1203,7 +2490,7 @@ function resolveHandlerSourceFile(pluginPath, handlerRef, isNpmPackage) {
1203
2490
  );
1204
2491
  if (reExportMatch) {
1205
2492
  const importSpec = reExportMatch[1].replace(/\.js$/, "");
1206
- const resolved = resolveModulePath$1(path.resolve(path.dirname(file), importSpec));
2493
+ const resolved = resolveModulePath$1(path$1.resolve(path$1.dirname(file), importSpec));
1207
2494
  if (resolved) return resolved;
1208
2495
  }
1209
2496
  }
@@ -1279,7 +2566,7 @@ function handlerBodyWritesAddMenuCatalog(body) {
1279
2566
  function resolveSetupHandlerFunctionBody(pluginPath, handlerRef, isNpmPackage) {
1280
2567
  const sourceFile = resolveHandlerSourceFile(pluginPath, handlerRef, isNpmPackage);
1281
2568
  if (!sourceFile) return null;
1282
- const source = fs.readFileSync(sourceFile, "utf-8");
2569
+ const source = fs$1.readFileSync(sourceFile, "utf-8");
1283
2570
  if (isRelativeHandlerRef(handlerRef)) {
1284
2571
  return extractDefaultExportFunctionBody(source) ?? extractFunctionBody(source, "setup") ?? extractFunctionBody(source, handlerRef);
1285
2572
  }
@@ -1312,7 +2599,7 @@ function mapLintFinding(finding, catalogPath, severity) {
1312
2599
  }
1313
2600
  function pluginShipsAddMenuCatalog(context) {
1314
2601
  return ADD_MENU_CATALOG_REL_PATHS.some(
1315
- (relPath) => fs.existsSync(path.join(context.pluginPath, relPath))
2602
+ (relPath) => fs$1.existsSync(path$1.join(context.pluginPath, relPath))
1316
2603
  );
1317
2604
  }
1318
2605
  function validateAddMenuAgentKitHandler(context, result) {
@@ -1346,7 +2633,7 @@ function validateAddMenuAgentKitHandler(context, result) {
1346
2633
  async function validateAddMenuCatalogFileAtPath(catalogPath, relPath, result) {
1347
2634
  let parsed;
1348
2635
  try {
1349
- const content = await fs.promises.readFile(catalogPath, "utf-8");
2636
+ const content = await fs$1.promises.readFile(catalogPath, "utf-8");
1350
2637
  parsed = YAML.parse(content);
1351
2638
  } catch (error) {
1352
2639
  const message = error instanceof Error ? error.message : String(error);
@@ -1375,8 +2662,8 @@ async function validateAddMenuCatalogFileAtPath(catalogPath, relPath, result) {
1375
2662
  async function validateAddMenuCatalog(context, result) {
1376
2663
  validateAddMenuAgentKitHandler(context, result);
1377
2664
  for (const relPath of ADD_MENU_CATALOG_REL_PATHS) {
1378
- const catalogPath = path.join(context.pluginPath, relPath);
1379
- if (!fs.existsSync(catalogPath)) continue;
2665
+ const catalogPath = path$1.join(context.pluginPath, relPath);
2666
+ if (!fs$1.existsSync(catalogPath)) continue;
1380
2667
  await validateAddMenuCatalogFileAtPath(catalogPath, relPath, result);
1381
2668
  }
1382
2669
  }
@@ -1493,7 +2780,7 @@ function mapSchemaError(error, relPath) {
1493
2780
  function validateSettingsTemplateAtPath(catalogPath, relPath, result, manifest) {
1494
2781
  let parsed;
1495
2782
  try {
1496
- parsed = YAML.parse(fs.readFileSync(catalogPath, "utf-8"));
2783
+ parsed = YAML.parse(fs$1.readFileSync(catalogPath, "utf-8"));
1497
2784
  } catch (err) {
1498
2785
  result.errors.push({
1499
2786
  type: "schema",
@@ -1527,8 +2814,8 @@ function validateSettingsTemplateAtPath(catalogPath, relPath, result, manifest)
1527
2814
  }
1528
2815
  }
1529
2816
  async function validateAiditorSettings(context, result) {
1530
- const templatePath = path.join(context.pluginPath, AIDITOR_SETTINGS_TEMPLATE_REL_PATH);
1531
- if (!fs.existsSync(templatePath)) {
2817
+ const templatePath = path$1.join(context.pluginPath, AIDITOR_SETTINGS_TEMPLATE_REL_PATH);
2818
+ if (!fs$1.existsSync(templatePath)) {
1532
2819
  return;
1533
2820
  }
1534
2821
  validateSettingsTemplateAtPath(
@@ -1563,10 +2850,10 @@ async function validatePluginPackage(pluginPath, options) {
1563
2850
  contractsChecked: 0,
1564
2851
  componentsChecked: 0
1565
2852
  };
1566
- const pluginYamlPath = path.join(pluginPath, "plugin.yaml");
1567
- const pluginManifest = loadPluginManifest(pluginPath);
2853
+ const pluginYamlPath = path$1.join(pluginPath, "plugin.yaml");
2854
+ const pluginManifest = loadPluginManifest$1(pluginPath);
1568
2855
  if (!pluginManifest) {
1569
- if (!fs.existsSync(pluginYamlPath)) {
2856
+ if (!fs$1.existsSync(pluginYamlPath)) {
1570
2857
  result.errors.push({
1571
2858
  type: "file-missing",
1572
2859
  message: "plugin.yaml not found",
@@ -1587,7 +2874,7 @@ async function validatePluginPackage(pluginPath, options) {
1587
2874
  const context = {
1588
2875
  manifest: pluginManifest,
1589
2876
  pluginPath,
1590
- isNpmPackage: fs.existsSync(path.join(pluginPath, "package.json"))
2877
+ isNpmPackage: fs$1.existsSync(path$1.join(pluginPath, "package.json"))
1591
2878
  };
1592
2879
  await validateSchema(context, result);
1593
2880
  if (pluginManifest.contracts) {
@@ -1619,8 +2906,8 @@ async function validatePluginPackage(pluginPath, options) {
1619
2906
  return result;
1620
2907
  }
1621
2908
  async function validateLocalPlugins(projectPath, options) {
1622
- const pluginsPath = path.join(projectPath, "src/plugins");
1623
- if (!fs.existsSync(pluginsPath)) {
2909
+ const pluginsPath = path$1.join(projectPath, "src/plugins");
2910
+ if (!fs$1.existsSync(pluginsPath)) {
1624
2911
  return {
1625
2912
  valid: false,
1626
2913
  errors: [
@@ -1634,10 +2921,10 @@ async function validateLocalPlugins(projectPath, options) {
1634
2921
  warnings: []
1635
2922
  };
1636
2923
  }
1637
- const pluginDirs = fs.readdirSync(pluginsPath, { withFileTypes: true }).filter((d) => d.isDirectory());
2924
+ const pluginDirs = fs$1.readdirSync(pluginsPath, { withFileTypes: true }).filter((d) => d.isDirectory());
1638
2925
  const allResults = [];
1639
2926
  for (const pluginDir of pluginDirs) {
1640
- const pluginPath = path.join(pluginsPath, pluginDir.name);
2927
+ const pluginPath = path$1.join(pluginsPath, pluginDir.name);
1641
2928
  const result = await validatePluginPackage(pluginPath, options);
1642
2929
  allResults.push(result);
1643
2930
  }
@@ -1651,8 +2938,8 @@ async function validateLocalPlugins(projectPath, options) {
1651
2938
  };
1652
2939
  }
1653
2940
  function validateDocFile(docPath, label, context, result) {
1654
- const resolvedPath = path.join(context.pluginPath, docPath);
1655
- if (!fs.existsSync(resolvedPath)) {
2941
+ const resolvedPath = path$1.join(context.pluginPath, docPath);
2942
+ if (!fs$1.existsSync(resolvedPath)) {
1656
2943
  result.errors.push({
1657
2944
  type: "file-missing",
1658
2945
  message: `Doc file for ${label} not found: ${docPath}`,
@@ -1662,9 +2949,9 @@ function validateDocFile(docPath, label, context, result) {
1662
2949
  return;
1663
2950
  }
1664
2951
  if (context.isNpmPackage) {
1665
- const packageJsonPath = path.join(context.pluginPath, "package.json");
2952
+ const packageJsonPath = path$1.join(context.pluginPath, "package.json");
1666
2953
  try {
1667
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
2954
+ const packageJson = JSON.parse(fs$1.readFileSync(packageJsonPath, "utf-8"));
1668
2955
  if (packageJson.exports) {
1669
2956
  const exportKey = "./" + docPath.replace(/^\.\//, "");
1670
2957
  if (!packageJson.exports[exportKey]) {
@@ -1999,25 +3286,25 @@ async function validateSchema(context, result) {
1999
3286
  }
2000
3287
  }
2001
3288
  function checkExportExists(exportName, context) {
2002
- const packageJsonPath = path.join(context.pluginPath, "package.json");
2003
- if (!fs.existsSync(packageJsonPath)) return true;
3289
+ const packageJsonPath = path$1.join(context.pluginPath, "package.json");
3290
+ if (!fs$1.existsSync(packageJsonPath)) return true;
2004
3291
  let mainPath;
2005
3292
  try {
2006
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
3293
+ const packageJson = JSON.parse(fs$1.readFileSync(packageJsonPath, "utf-8"));
2007
3294
  if (packageJson.exports?.["."]) {
2008
3295
  const entry = packageJson.exports["."];
2009
3296
  const entryPath = typeof entry === "string" ? entry : entry.default || entry.import;
2010
- if (entryPath) mainPath = path.join(context.pluginPath, entryPath);
3297
+ if (entryPath) mainPath = path$1.join(context.pluginPath, entryPath);
2011
3298
  }
2012
3299
  if (!mainPath && packageJson.main) {
2013
- mainPath = path.join(context.pluginPath, packageJson.main);
3300
+ mainPath = path$1.join(context.pluginPath, packageJson.main);
2014
3301
  }
2015
3302
  } catch {
2016
3303
  return true;
2017
3304
  }
2018
- if (!mainPath || !fs.existsSync(mainPath)) return true;
3305
+ if (!mainPath || !fs$1.existsSync(mainPath)) return true;
2019
3306
  try {
2020
- const content = fs.readFileSync(mainPath, "utf-8");
3307
+ const content = fs$1.readFileSync(mainPath, "utf-8");
2021
3308
  const patterns = [
2022
3309
  new RegExp(`export\\s*\\{[^}]*\\b${exportName}\\b[^}]*\\}`, "m"),
2023
3310
  new RegExp(`export\\s+(?:async\\s+)?function\\s+${exportName}\\b`),
@@ -2049,9 +3336,9 @@ function validateHandlerRef(value, label, location, context, result) {
2049
3336
  });
2050
3337
  }
2051
3338
  } else if (isRelativePath(value)) {
2052
- const handlerPath = path.join(context.pluginPath, value);
3339
+ const handlerPath = path$1.join(context.pluginPath, value);
2053
3340
  const extensions = ["", ".ts", ".js", "/index.ts", "/index.js"];
2054
- const found = extensions.some((ext) => fs.existsSync(handlerPath + ext));
3341
+ const found = extensions.some((ext) => fs$1.existsSync(handlerPath + ext));
2055
3342
  if (!found) {
2056
3343
  result.errors.push({
2057
3344
  type: "file-missing",
@@ -2064,18 +3351,18 @@ function validateHandlerRef(value, label, location, context, result) {
2064
3351
  }
2065
3352
  function resolveContractFile(contractSpec, context) {
2066
3353
  if (context.isNpmPackage) {
2067
- const packageJsonPath = path.join(context.pluginPath, "package.json");
2068
- if (fs.existsSync(packageJsonPath)) {
3354
+ const packageJsonPath = path$1.join(context.pluginPath, "package.json");
3355
+ if (fs$1.existsSync(packageJsonPath)) {
2069
3356
  try {
2070
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
3357
+ const packageJson = JSON.parse(fs$1.readFileSync(packageJsonPath, "utf-8"));
2071
3358
  if (packageJson.exports) {
2072
3359
  const exportKey = "./" + contractSpec;
2073
3360
  const exportValue = packageJson.exports[exportKey];
2074
3361
  if (exportValue) {
2075
3362
  const resolvedPath = typeof exportValue === "string" ? exportValue : exportValue.default || exportValue.import || exportValue.require;
2076
3363
  if (resolvedPath) {
2077
- const fullPath = path.join(context.pluginPath, resolvedPath);
2078
- if (fs.existsSync(fullPath)) return fullPath;
3364
+ const fullPath = path$1.join(context.pluginPath, resolvedPath);
3365
+ if (fs$1.existsSync(fullPath)) return fullPath;
2079
3366
  }
2080
3367
  }
2081
3368
  }
@@ -2083,13 +3370,13 @@ function resolveContractFile(contractSpec, context) {
2083
3370
  }
2084
3371
  }
2085
3372
  for (const dir of ["dist", "lib", ""]) {
2086
- const candidate = path.join(context.pluginPath, dir, contractSpec);
2087
- if (fs.existsSync(candidate)) return candidate;
3373
+ const candidate = path$1.join(context.pluginPath, dir, contractSpec);
3374
+ if (fs$1.existsSync(candidate)) return candidate;
2088
3375
  }
2089
3376
  return void 0;
2090
3377
  } else {
2091
- const candidate = path.join(context.pluginPath, contractSpec);
2092
- return fs.existsSync(candidate) ? candidate : void 0;
3378
+ const candidate = path$1.join(context.pluginPath, contractSpec);
3379
+ return fs$1.existsSync(candidate) ? candidate : void 0;
2093
3380
  }
2094
3381
  }
2095
3382
  async function validateContract(contract, index, context, generateTypes, result) {
@@ -2100,12 +3387,12 @@ async function validateContract(contract, index, context, generateTypes, result)
2100
3387
  type: "file-missing",
2101
3388
  message: `Contract file not found: ${contract.contract}`,
2102
3389
  location: `plugin.yaml contracts[${index}]`,
2103
- suggestion: context.isNpmPackage ? `Ensure the contract is exported in package.json and the file exists` : `Create the contract file at ${path.join(context.pluginPath, contract.contract)}`
3390
+ suggestion: context.isNpmPackage ? `Ensure the contract is exported in package.json and the file exists` : `Create the contract file at ${path$1.join(context.pluginPath, contract.contract)}`
2104
3391
  });
2105
3392
  return;
2106
3393
  }
2107
3394
  try {
2108
- const contractContent = await fs.promises.readFile(contractPath, "utf-8");
3395
+ const contractContent = await fs$1.promises.readFile(contractPath, "utf-8");
2109
3396
  const parsedContract = YAML.parse(contractContent);
2110
3397
  if (!parsedContract.name) {
2111
3398
  result.errors.push({
@@ -2172,21 +3459,21 @@ function hasExportModifier(node) {
2172
3459
  function resolveModulePath(basePath) {
2173
3460
  for (const ext of ["", ".ts", ".js", "/index.ts", "/index.js"]) {
2174
3461
  const candidate = basePath + ext;
2175
- if (fs.existsSync(candidate)) return candidate;
3462
+ if (fs$1.existsSync(candidate)) return candidate;
2176
3463
  }
2177
3464
  return void 0;
2178
3465
  }
2179
3466
  function resolveComponentSourcePath(componentName, context) {
2180
3467
  const modulePath = context.manifest.module || "index";
2181
- const entryBase = path.join(context.pluginPath, modulePath);
3468
+ const entryBase = path$1.join(context.pluginPath, modulePath);
2182
3469
  const entryFile = resolveModulePath(entryBase);
2183
- const libEntryFile = !entryFile ? resolveModulePath(path.join(context.pluginPath, "lib", modulePath)) : void 0;
3470
+ const libEntryFile = !entryFile ? resolveModulePath(path$1.join(context.pluginPath, "lib", modulePath)) : void 0;
2184
3471
  const sourceEntry = entryFile || libEntryFile;
2185
3472
  if (!sourceEntry) return void 0;
2186
3473
  if (!sourceEntry.endsWith(".ts")) return void 0;
2187
3474
  let sourceCode;
2188
3475
  try {
2189
- sourceCode = fs.readFileSync(sourceEntry, "utf-8");
3476
+ sourceCode = fs$1.readFileSync(sourceEntry, "utf-8");
2190
3477
  } catch {
2191
3478
  return void 0;
2192
3479
  }
@@ -2212,7 +3499,7 @@ function resolveComponentSourcePath(componentName, context) {
2212
3499
  for (const element of exportClause.elements) {
2213
3500
  const exportedName = element.name.text;
2214
3501
  if (exportedName === componentName) {
2215
- const resolvedBase = path.resolve(path.dirname(sourceEntry), moduleSpec);
3502
+ const resolvedBase = path$1.resolve(path$1.dirname(sourceEntry), moduleSpec);
2216
3503
  return resolveModulePath(resolvedBase);
2217
3504
  }
2218
3505
  }
@@ -2220,11 +3507,11 @@ function resolveComponentSourcePath(componentName, context) {
2220
3507
  }
2221
3508
  for (const moduleSpec of starReexportModules) {
2222
3509
  if (!moduleSpec.startsWith(".")) continue;
2223
- const resolvedBase = path.resolve(path.dirname(sourceEntry), moduleSpec);
3510
+ const resolvedBase = path$1.resolve(path$1.dirname(sourceEntry), moduleSpec);
2224
3511
  const resolvedPath = resolveModulePath(resolvedBase);
2225
3512
  if (!resolvedPath || !resolvedPath.endsWith(".ts")) continue;
2226
3513
  try {
2227
- const modSource = fs.readFileSync(resolvedPath, "utf-8");
3514
+ const modSource = fs$1.readFileSync(resolvedPath, "utf-8");
2228
3515
  const modFile = u.createSourceFile(
2229
3516
  resolvedPath,
2230
3517
  modSource,
@@ -2263,15 +3550,15 @@ async function checkComponentContractConsistency(contract, context, result) {
2263
3550
  if (!contractPath) return;
2264
3551
  let contractContent;
2265
3552
  try {
2266
- contractContent = await fs.promises.readFile(contractPath, "utf-8");
3553
+ contractContent = await fs$1.promises.readFile(contractPath, "utf-8");
2267
3554
  } catch {
2268
3555
  return;
2269
3556
  }
2270
- const parsed = parseContract(contractContent, path.basename(contractPath));
3557
+ const parsed = parseContract(contractContent, path$1.basename(contractPath));
2271
3558
  if (parsed.validations.length > 0) return;
2272
3559
  let sourceCode;
2273
3560
  try {
2274
- sourceCode = await fs.promises.readFile(sourcePath, "utf-8");
3561
+ sourceCode = await fs$1.promises.readFile(sourcePath, "utf-8");
2275
3562
  } catch {
2276
3563
  return;
2277
3564
  }
@@ -2290,8 +3577,8 @@ async function checkComponentContractConsistency(contract, context, result) {
2290
3577
  result.warnings.push(...checkResult.warnings);
2291
3578
  }
2292
3579
  async function validatePackageJson(context, result) {
2293
- const packageJsonPath = path.join(context.pluginPath, "package.json");
2294
- if (!fs.existsSync(packageJsonPath)) {
3580
+ const packageJsonPath = path$1.join(context.pluginPath, "package.json");
3581
+ if (!fs$1.existsSync(packageJsonPath)) {
2295
3582
  result.warnings.push({
2296
3583
  type: "file-missing",
2297
3584
  message: "package.json not found",
@@ -2301,7 +3588,7 @@ async function validatePackageJson(context, result) {
2301
3588
  return;
2302
3589
  }
2303
3590
  try {
2304
- const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, "utf-8"));
3591
+ const packageJson = JSON.parse(await fs$1.promises.readFile(packageJsonPath, "utf-8"));
2305
3592
  if (!packageJson.exports) {
2306
3593
  result.warnings.push({
2307
3594
  type: "export-mismatch",
@@ -2365,8 +3652,8 @@ async function validatePackageJson(context, result) {
2365
3652
  suggestion: 'Add "./plugin.yaml": "./plugin.yaml" to exports field'
2366
3653
  });
2367
3654
  }
2368
- const agentKitDir = path.join(context.pluginPath, "agent-kit");
2369
- if (fs.existsSync(agentKitDir) && fs.statSync(agentKitDir).isDirectory()) {
3655
+ const agentKitDir = path$1.join(context.pluginPath, "agent-kit");
3656
+ if (fs$1.existsSync(agentKitDir) && fs$1.statSync(agentKitDir).isDirectory()) {
2370
3657
  const filesArray = packageJson.files;
2371
3658
  if (!filesArray || !filesArray.includes("agent-kit")) {
2372
3659
  result.warnings.push({
@@ -2390,7 +3677,7 @@ function isBareFunctionExport(exportName, context) {
2390
3677
  if (!sourcePath) return false;
2391
3678
  let sourceCode;
2392
3679
  try {
2393
- sourceCode = fs.readFileSync(sourcePath, "utf-8");
3680
+ sourceCode = fs$1.readFileSync(sourcePath, "utf-8");
2394
3681
  } catch {
2395
3682
  return false;
2396
3683
  }
@@ -2418,8 +3705,8 @@ function resolveModulePathWithJsToTs(basePath) {
2418
3705
  }
2419
3706
  function resolveExportSourceFile(exportName, context) {
2420
3707
  const modulePath = context.manifest.module || "index";
2421
- const entryBase = path.join(context.pluginPath, modulePath);
2422
- const libEntryBase = path.join(context.pluginPath, "lib", modulePath);
3708
+ const entryBase = path$1.join(context.pluginPath, modulePath);
3709
+ const libEntryBase = path$1.join(context.pluginPath, "lib", modulePath);
2423
3710
  const sourceEntry = resolveModulePath(entryBase) || resolveModulePath(libEntryBase);
2424
3711
  if (!sourceEntry || !sourceEntry.endsWith(".ts")) return void 0;
2425
3712
  return followExportChain(exportName, sourceEntry);
@@ -2427,7 +3714,7 @@ function resolveExportSourceFile(exportName, context) {
2427
3714
  function followExportChain(exportName, filePath) {
2428
3715
  let sourceCode;
2429
3716
  try {
2430
- sourceCode = fs.readFileSync(filePath, "utf-8");
3717
+ sourceCode = fs$1.readFileSync(filePath, "utf-8");
2431
3718
  } catch {
2432
3719
  return void 0;
2433
3720
  }
@@ -2450,7 +3737,7 @@ function followExportChain(exportName, filePath) {
2450
3737
  if (u.isNamedExports(statement.exportClause)) {
2451
3738
  for (const element of statement.exportClause.elements) {
2452
3739
  if (element.name.text === exportName) {
2453
- const resolvedBase = path.resolve(path.dirname(filePath), moduleSpec);
3740
+ const resolvedBase = path$1.resolve(path$1.dirname(filePath), moduleSpec);
2454
3741
  return resolveModulePathWithJsToTs(resolvedBase);
2455
3742
  }
2456
3743
  }
@@ -2467,7 +3754,7 @@ function followExportChain(exportName, filePath) {
2467
3754
  }
2468
3755
  for (const moduleSpec of starReexportModules) {
2469
3756
  if (!moduleSpec.startsWith(".")) continue;
2470
- const resolvedBase = path.resolve(path.dirname(filePath), moduleSpec);
3757
+ const resolvedBase = path$1.resolve(path$1.dirname(filePath), moduleSpec);
2471
3758
  const resolved = resolveModulePathWithJsToTs(resolvedBase);
2472
3759
  if (!resolved) continue;
2473
3760
  const found = followExportChain(exportName, resolved);
@@ -2484,11 +3771,11 @@ async function validateDynamicContracts(context, result) {
2484
3771
  if (config.generator) {
2485
3772
  const isFilePath = config.generator.startsWith("./") || config.generator.startsWith("/") || config.generator.includes(".ts") || config.generator.includes(".js");
2486
3773
  if (isFilePath) {
2487
- const generatorPath = path.join(context.pluginPath, config.generator);
3774
+ const generatorPath = path$1.join(context.pluginPath, config.generator);
2488
3775
  const possibleExtensions = ["", ".ts", ".js", "/index.ts", "/index.js"];
2489
3776
  let found = false;
2490
3777
  for (const ext of possibleExtensions) {
2491
- if (fs.existsSync(generatorPath + ext)) {
3778
+ if (fs$1.existsSync(generatorPath + ext)) {
2492
3779
  found = true;
2493
3780
  break;
2494
3781
  }
@@ -2513,11 +3800,11 @@ async function validateDynamicContracts(context, result) {
2513
3800
  if (config.component) {
2514
3801
  const isFilePath = config.component.startsWith("./") || config.component.startsWith("/") || config.component.includes(".ts") || config.component.includes(".js");
2515
3802
  if (isFilePath) {
2516
- const componentPath = path.join(context.pluginPath, config.component);
3803
+ const componentPath = path$1.join(context.pluginPath, config.component);
2517
3804
  const possibleExtensions = ["", ".ts", ".js", "/index.ts", "/index.js"];
2518
3805
  let found = false;
2519
3806
  for (const ext of possibleExtensions) {
2520
- if (fs.existsSync(componentPath + ext)) {
3807
+ if (fs$1.existsSync(componentPath + ext)) {
2521
3808
  found = true;
2522
3809
  break;
2523
3810
  }
@@ -2838,12 +4125,12 @@ function checkRefElementTypes(jayHtml, file) {
2838
4125
  return warnings;
2839
4126
  }
2840
4127
  function checkPageComponentExport(jayHtmlPath) {
2841
- const dirname = path.dirname(jayHtmlPath);
2842
- const compPath = path.join(dirname, "page.ts");
2843
- if (!fs.existsSync(compPath)) return null;
4128
+ const dirname = path$1.dirname(jayHtmlPath);
4129
+ const compPath = path$1.join(dirname, "page.ts");
4130
+ if (!fs$1.existsSync(compPath)) return null;
2844
4131
  let content;
2845
4132
  try {
2846
- content = fs.readFileSync(compPath, "utf-8");
4133
+ content = fs$1.readFileSync(compPath, "utf-8");
2847
4134
  } catch {
2848
4135
  return null;
2849
4136
  }
@@ -2854,7 +4141,7 @@ function checkPageComponentExport(jayHtmlPath) {
2854
4141
  new RegExp(`export\\s+(?:const|let|var)\\s+${exportName}\\b`)
2855
4142
  ];
2856
4143
  if (patterns.some((p) => p.test(content))) return null;
2857
- return `${path.relative(dirname, compPath)} exists but does not export "${exportName}". Remove the file or add the export.`;
4144
+ return `${path$1.relative(dirname, compPath)} exists but does not export "${exportName}". Remove the file or add the export.`;
2858
4145
  }
2859
4146
  const DOCUMENT_ACCESS_PATTERNS = [
2860
4147
  /document\.getElementById\b/,
@@ -2867,15 +4154,15 @@ const DOCUMENT_ACCESS_PATTERNS = [
2867
4154
  ];
2868
4155
  const DOM_SUPPRESS_COMMENT = "jay-dom: allow";
2869
4156
  function checkDirectDocumentAccess(jayHtmlPath) {
2870
- const dirname = path.dirname(jayHtmlPath);
2871
- const basename = path.basename(jayHtmlPath, JAY_EXTENSION);
2872
- const candidates = [path.join(dirname, `${basename}.ts`), path.join(dirname, "page.ts")];
2873
- const compPath = candidates.find((p) => fs.existsSync(p));
4157
+ const dirname = path$1.dirname(jayHtmlPath);
4158
+ const basename = path$1.basename(jayHtmlPath, JAY_EXTENSION);
4159
+ const candidates = [path$1.join(dirname, `${basename}.ts`), path$1.join(dirname, "page.ts")];
4160
+ const compPath = candidates.find((p) => fs$1.existsSync(p));
2874
4161
  if (!compPath) return [];
2875
- const compName = path.basename(compPath);
4162
+ const compName = path$1.basename(compPath);
2876
4163
  let content;
2877
4164
  try {
2878
- content = fs.readFileSync(compPath, "utf-8");
4165
+ content = fs$1.readFileSync(compPath, "utf-8");
2879
4166
  } catch {
2880
4167
  return [];
2881
4168
  }
@@ -2898,8 +4185,8 @@ function checkDirectDocumentAccess(jayHtmlPath) {
2898
4185
  }
2899
4186
  const PARSE_PARAM = /^\[(\[)?(\.\.\.)?([^\]]+)\]?\]$/;
2900
4187
  function extractRouteParams(filePath, pagesBase) {
2901
- const relative = path.relative(pagesBase, filePath);
2902
- const segments = relative.split(path.sep);
4188
+ const relative = path$1.relative(pagesBase, filePath);
4189
+ const segments = relative.split(path$1.sep);
2903
4190
  const params = /* @__PURE__ */ new Set();
2904
4191
  for (const segment of segments) {
2905
4192
  const match = PARSE_PARAM.exec(segment);
@@ -3109,7 +4396,7 @@ function resolveLinkedTags(tags, contractDir) {
3109
4396
  }
3110
4397
  function resolveContractLinks(contract, contractPath) {
3111
4398
  if (!contractPath) return contract;
3112
- const contractDir = path.dirname(contractPath);
4399
+ const contractDir = path$1.dirname(contractPath);
3113
4400
  return { ...contract, tags: resolveLinkedTags(contract.tags, contractDir) };
3114
4401
  }
3115
4402
  async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
@@ -3123,7 +4410,7 @@ async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
3123
4410
  try {
3124
4411
  let handlerModule;
3125
4412
  if (plugin.isLocal) {
3126
- const handlerPath = path.resolve(plugin.pluginPath, validatorDef.handler);
4413
+ const handlerPath = path$1.resolve(plugin.pluginPath, validatorDef.handler);
3127
4414
  handlerModule = await import(handlerPath);
3128
4415
  } else {
3129
4416
  handlerModule = await import(plugin.packageName);
@@ -3151,8 +4438,8 @@ async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
3151
4438
  }
3152
4439
  loadedValidators.push(source);
3153
4440
  for (const { relativePath, parsed } of parsedFiles) {
3154
- const pageContractPath = parsed.contractRef ? path.resolve(
3155
- path.dirname(path.resolve(projectRoot, relativePath)),
4441
+ const pageContractPath = parsed.contractRef ? path$1.resolve(
4442
+ path$1.dirname(path$1.resolve(projectRoot, relativePath)),
3156
4443
  parsed.contractRef
3157
4444
  ) : void 0;
3158
4445
  const resolvedPageContract = parsed.contract ? resolveContractLinks(parsed.contract, pageContractPath) : void 0;
@@ -3196,7 +4483,8 @@ async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
3196
4483
  providedHeadTags
3197
4484
  };
3198
4485
  }),
3199
- projectRoot
4486
+ projectRoot,
4487
+ validationOverrides: parsed.validationOverrides
3200
4488
  };
3201
4489
  try {
3202
4490
  const findings = await validatorFn(ctx);
@@ -3232,11 +4520,11 @@ async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
3232
4520
  return loadedValidators;
3233
4521
  }
3234
4522
  async function validateJayFiles(options = {}) {
3235
- const config = loadConfig();
3236
- const resolvedConfig = getConfigWithDefaults(config);
3237
4523
  const projectRoot = options.projectRoot ?? process.cwd();
3238
- const scanDir = options.path ? path.resolve(options.path) : path.resolve(resolvedConfig.devServer.pagesBase);
3239
- const componentsDir = path.resolve(resolvedConfig.devServer.componentsBase);
4524
+ const config = loadConfig(projectRoot);
4525
+ const resolvedConfig = getConfigWithDefaults(config);
4526
+ const scanDir = options.path ? path$1.resolve(options.path) : path$1.resolve(resolvedConfig.devServer.pagesBase);
4527
+ const componentsDir = path$1.resolve(resolvedConfig.devServer.componentsBase);
3240
4528
  const errors = [];
3241
4529
  const warnings = [];
3242
4530
  const coverage = [];
@@ -3255,10 +4543,10 @@ async function validateJayFiles(options = {}) {
3255
4543
  `));
3256
4544
  }
3257
4545
  for (const contractFile of contractFiles) {
3258
- const relativePath = path.relative(projectRoot, contractFile);
4546
+ const relativePath = path$1.relative(projectRoot, contractFile);
3259
4547
  try {
3260
4548
  const content = await promises.readFile(contractFile, "utf-8");
3261
- const result = parseContract(content, path.basename(contractFile));
4549
+ const result = parseContract(content, path$1.basename(contractFile));
3262
4550
  if (result.validations.length > 0) {
3263
4551
  for (const validation of result.validations) {
3264
4552
  errors.push({
@@ -3285,9 +4573,9 @@ async function validateJayFiles(options = {}) {
3285
4573
  }
3286
4574
  }
3287
4575
  for (const jayFile of jayHtmlFiles) {
3288
- const relativePath = path.relative(projectRoot, jayFile);
3289
- const filename = path.basename(jayFile.replace(JAY_EXTENSION, ""));
3290
- const dirname = path.dirname(jayFile);
4576
+ const relativePath = path$1.relative(projectRoot, jayFile);
4577
+ const filename = path$1.basename(jayFile.replace(JAY_EXTENSION, ""));
4578
+ const dirname = path$1.dirname(jayFile);
3291
4579
  try {
3292
4580
  const content = await promises.readFile(jayFile, "utf-8");
3293
4581
  const parsedFile = await parseJayFile(
@@ -3346,17 +4634,34 @@ async function validateJayFiles(options = {}) {
3346
4634
  for (const msg of refTypeErrors) {
3347
4635
  errors.push({ file: relativePath, message: msg, stage: "generate" });
3348
4636
  }
3349
- const headlessPropWarnings = checkHeadlessInstanceProps(parsedFile.val, relativePath);
3350
- for (const msg of headlessPropWarnings) {
3351
- warnings.push({ file: relativePath, message: msg });
4637
+ const headlessPropResults = checkHeadlessInstanceProps(parsedFile.val, relativePath);
4638
+ for (const msg of headlessPropResults) {
4639
+ if (msg.includes("is missing required prop") || msg.includes("source phase must be")) {
4640
+ errors.push({ file: relativePath, message: msg, stage: "generate" });
4641
+ } else {
4642
+ warnings.push({ file: relativePath, message: msg });
4643
+ }
3352
4644
  }
3353
4645
  const fileCoverage = analyzeTagCoverage(parsedFile.val, relativePath);
3354
4646
  if (fileCoverage) {
3355
4647
  coverage.push(fileCoverage);
4648
+ const allowedUnused = parsedFile.val.validationOverrides?.["jay-stack"]?.["allow-unused-tags"];
4649
+ const allowedSet = new Set(Array.isArray(allowedUnused) ? allowedUnused : []);
4650
+ for (const contract of fileCoverage.contracts) {
4651
+ for (const tag of contract.requiredUnusedTags) {
4652
+ const qualifiedTag = contract.key ? `${contract.key}.${tag}` : tag;
4653
+ if (allowedSet.has(qualifiedTag) || allowedSet.has(tag)) continue;
4654
+ const label = contract.key ? `${contract.key} (${contract.contractName})` : contract.contractName;
4655
+ warnings.push({
4656
+ file: relativePath,
4657
+ message: `Required tag "${tag}" from contract "${label}" is not used in the template. Suppress with jay-stack: { allow-unused-tags: ["${qualifiedTag}"] } in <script type="application/jay-validations">. See agent-kit/designer/validation-guide.md`
4658
+ });
4659
+ }
4660
+ }
3356
4661
  }
3357
4662
  const generatedFile = generateElementFile(
3358
4663
  parsedFile.val,
3359
- RuntimeMode.MainTrusted,
4664
+ RuntimeMode$1.MainTrusted,
3360
4665
  GenerateTarget.jay
3361
4666
  );
3362
4667
  if (generatedFile.validations.length > 0) {
@@ -3394,8 +4699,8 @@ async function validateJayFiles(options = {}) {
3394
4699
  }
3395
4700
  }
3396
4701
  }
3397
- const robotsTxtPath = path.resolve(projectRoot, "public/robots.txt");
3398
- if (!fs.existsSync(robotsTxtPath)) {
4702
+ const robotsTxtPath = path$1.resolve(projectRoot, "public/robots.txt");
4703
+ if (!fs$1.existsSync(robotsTxtPath)) {
3399
4704
  warnings.push({
3400
4705
  file: "public/robots.txt",
3401
4706
  message: "public/robots.txt not found — search engines may crawl pages you don't intend to expose.",
@@ -3406,7 +4711,7 @@ async function validateJayFiles(options = {}) {
3406
4711
  warnings.push({
3407
4712
  file: ".jay",
3408
4713
  message: "site.baseUrl not configured — sitemap.xml will not be generated in production.",
3409
- suggestion: "Add to .jay config: site:\n baseUrl: https://your-domain.com"
4714
+ suggestion: "Add to .jay config:\n site:\n baseUrl: https://your-domain.com"
3410
4715
  });
3411
4716
  }
3412
4717
  const pluginValidators = await runPluginValidators(projectRoot, parsedFiles, errors, warnings);
@@ -3491,7 +4796,7 @@ function printJayValidationResult(result, options) {
3491
4796
  }
3492
4797
  }
3493
4798
  }
3494
- if (result.coverage.length > 0) {
4799
+ if (options.verbose && result.coverage.length > 0) {
3495
4800
  logger.important("");
3496
4801
  logger.important(chalk.bold("šŸ“¦ Tag Coverage"));
3497
4802
  for (const fileCov of result.coverage) {
@@ -3506,23 +4811,26 @@ function printJayValidationResult(result, options) {
3506
4811
  chalk.gray(` Unused: ${contract.unusedTags.join(", ")}`)
3507
4812
  );
3508
4813
  }
3509
- if (contract.requiredUnusedTags.length > 0) {
3510
- logger.important(
3511
- chalk.yellow(
3512
- ` ⚠ Required unused: ${contract.requiredUnusedTags.join(", ")}`
3513
- )
3514
- );
3515
- }
3516
4814
  }
3517
4815
  }
3518
4816
  }
3519
4817
  logger.important("");
3520
- if (result.valid) {
4818
+ if (result.valid && result.warnings.length === 0) {
3521
4819
  logger.important(chalk.green("Validation passed."));
4820
+ } else if (result.valid) {
4821
+ logger.important(
4822
+ chalk.yellow(
4823
+ `Validation passed with ${result.warnings.length} warning(s). Warnings must be fixed or explicitly suppressed — do not ignore them.`
4824
+ )
4825
+ );
3522
4826
  } else {
3523
- logger.important(chalk.red(`Validation failed — ${result.errors.length} error(s).`));
4827
+ logger.important(
4828
+ chalk.red(
4829
+ `Validation failed — ${result.errors.length} error(s)` + (result.warnings.length > 0 ? `, ${result.warnings.length} warning(s). Errors must be fixed. Warnings must be fixed or explicitly suppressed.` : ".")
4830
+ )
4831
+ );
3524
4832
  }
3525
- const totalIssues = result.errors.length + result.warnings.length + result.coverage.length;
4833
+ const totalIssues = result.errors.length + result.warnings.length;
3526
4834
  if (totalIssues > 0) {
3527
4835
  logger.important(
3528
4836
  chalk.gray(
@@ -3626,7 +4934,7 @@ async function runAgentKit(options) {
3626
4934
  }
3627
4935
  }
3628
4936
  async function runMaterialize(projectRoot, options, defaultOutputRelative, keepViteAlive = false) {
3629
- const outputDir = options.output ?? path$1.join(projectRoot, defaultOutputRelative);
4937
+ const outputDir = options.output ?? path__default.join(projectRoot, defaultOutputRelative);
3630
4938
  let viteServer;
3631
4939
  let initErrors = /* @__PURE__ */ new Map();
3632
4940
  try {
@@ -3692,81 +5000,81 @@ Materialized ${totalContracts} contracts`));
3692
5000
  return { initErrors };
3693
5001
  }
3694
5002
  async function ensureAgentKitDocs(projectRoot, _force, mode) {
3695
- const agentKitDir = path$1.join(projectRoot, "agent-kit");
3696
- const thisDir = path$1.dirname(fileURLToPath(import.meta.url));
3697
- const templateDir = path$1.resolve(thisDir, "..", "agent-kit-template");
5003
+ const agentKitDir = path__default.join(projectRoot, "agent-kit");
5004
+ const thisDir = path__default.dirname(fileURLToPath(import.meta.url));
5005
+ const templateDir = path__default.resolve(thisDir, "..", "agent-kit-template");
3698
5006
  const roles = mode && ALL_ROLES.includes(mode) ? [mode] : ALL_ROLES;
3699
5007
  for (const role of roles) {
3700
- const roleTemplateDir = path$1.join(templateDir, role);
3701
- const roleOutputDir = path$1.join(agentKitDir, role);
5008
+ const roleTemplateDir = path__default.join(templateDir, role);
5009
+ const roleOutputDir = path__default.join(agentKitDir, role);
3702
5010
  let files;
3703
5011
  try {
3704
- files = (await fs$1.readdir(roleTemplateDir)).filter((f) => f.endsWith(".md"));
5012
+ files = (await fs$2.readdir(roleTemplateDir)).filter((f) => f.endsWith(".md"));
3705
5013
  } catch {
3706
5014
  continue;
3707
5015
  }
3708
- await fs$1.mkdir(roleOutputDir, { recursive: true });
5016
+ await fs$2.mkdir(roleOutputDir, { recursive: true });
3709
5017
  for (const filename of files) {
3710
- await fs$1.copyFile(
3711
- path$1.join(roleTemplateDir, filename),
3712
- path$1.join(roleOutputDir, filename)
5018
+ await fs$2.copyFile(
5019
+ path__default.join(roleTemplateDir, filename),
5020
+ path__default.join(roleOutputDir, filename)
3713
5021
  );
3714
5022
  getLogger().info(chalk.gray(` Created agent-kit/${role}/${filename}`));
3715
5023
  }
3716
5024
  }
3717
- const topLevelFiles = (await fs$1.readdir(templateDir)).filter((f) => f.endsWith(".md"));
5025
+ const topLevelFiles = (await fs$2.readdir(templateDir)).filter((f) => f.endsWith(".md"));
3718
5026
  for (const filename of topLevelFiles) {
3719
- await fs$1.copyFile(path$1.join(templateDir, filename), path$1.join(agentKitDir, filename));
5027
+ await fs$2.copyFile(path__default.join(templateDir, filename), path__default.join(agentKitDir, filename));
3720
5028
  getLogger().info(chalk.gray(` Created agent-kit/${filename}`));
3721
5029
  }
3722
5030
  const sharedDirs = ["contracts"];
3723
5031
  for (const dir of sharedDirs) {
3724
- const srcDir = path$1.join(templateDir, dir);
3725
- if (!fsSync.existsSync(srcDir)) continue;
3726
- await copyDirRecursive(srcDir, path$1.join(agentKitDir, dir));
5032
+ const srcDir = path__default.join(templateDir, dir);
5033
+ if (!fs__default.existsSync(srcDir)) continue;
5034
+ await copyDirRecursive(srcDir, path__default.join(agentKitDir, dir));
3727
5035
  getLogger().info(chalk.gray(` Created agent-kit/${dir}/`));
3728
5036
  }
3729
5037
  }
3730
5038
  async function copyDirRecursive(src, dest) {
3731
- await fs$1.mkdir(dest, { recursive: true });
3732
- const entries = await fs$1.readdir(src, { withFileTypes: true });
5039
+ await fs$2.mkdir(dest, { recursive: true });
5040
+ const entries = await fs$2.readdir(src, { withFileTypes: true });
3733
5041
  for (const entry of entries) {
3734
- const srcPath = path$1.join(src, entry.name);
3735
- const destPath = path$1.join(dest, entry.name);
5042
+ const srcPath = path__default.join(src, entry.name);
5043
+ const destPath = path__default.join(dest, entry.name);
3736
5044
  if (entry.isDirectory()) {
3737
5045
  await copyDirRecursive(srcPath, destPath);
3738
5046
  } else if (entry.name.endsWith(".md")) {
3739
- await fs$1.copyFile(srcPath, destPath);
5047
+ await fs$2.copyFile(srcPath, destPath);
3740
5048
  }
3741
5049
  }
3742
5050
  }
3743
5051
  async function mergePluginAgentKitGuides(projectRoot, mode) {
3744
5052
  const plugins = await scanPlugins({ projectRoot, includeDevDeps: true });
3745
- const agentKitDir = path$1.join(projectRoot, "agent-kit");
5053
+ const agentKitDir = path__default.join(projectRoot, "agent-kit");
3746
5054
  const roles = mode && ALL_ROLES.includes(mode) ? [mode] : ALL_ROLES;
3747
5055
  const copiedPerRole = /* @__PURE__ */ new Map();
3748
5056
  for (const [, plugin] of plugins) {
3749
- const pluginAgentKitDir = path$1.join(plugin.pluginPath, "agent-kit");
3750
- if (!fsSync.existsSync(pluginAgentKitDir)) continue;
5057
+ const pluginAgentKitDir = path__default.join(plugin.pluginPath, "agent-kit");
5058
+ if (!fs__default.existsSync(pluginAgentKitDir)) continue;
3751
5059
  for (const role of roles) {
3752
- const roleSourceDir = path$1.join(pluginAgentKitDir, role);
5060
+ const roleSourceDir = path__default.join(pluginAgentKitDir, role);
3753
5061
  let files;
3754
5062
  try {
3755
- files = (await fs$1.readdir(roleSourceDir)).filter(
5063
+ files = (await fs$2.readdir(roleSourceDir)).filter(
3756
5064
  (f) => f.endsWith(".md") && f !== "INSTRUCTIONS.md"
3757
5065
  );
3758
5066
  } catch {
3759
5067
  continue;
3760
5068
  }
3761
5069
  if (files.length === 0) continue;
3762
- const roleOutputDir = path$1.join(agentKitDir, role);
3763
- await fs$1.mkdir(roleOutputDir, { recursive: true });
5070
+ const roleOutputDir = path__default.join(agentKitDir, role);
5071
+ await fs$2.mkdir(roleOutputDir, { recursive: true });
3764
5072
  for (const filename of files) {
3765
- const sourcePath = path$1.join(roleSourceDir, filename);
3766
- await fs$1.copyFile(sourcePath, path$1.join(roleOutputDir, filename));
5073
+ const sourcePath = path__default.join(roleSourceDir, filename);
5074
+ await fs$2.copyFile(sourcePath, path__default.join(roleOutputDir, filename));
3767
5075
  let description = "";
3768
5076
  try {
3769
- const content = await fs$1.readFile(sourcePath, "utf-8");
5077
+ const content = await fs$2.readFile(sourcePath, "utf-8");
3770
5078
  const lines = content.split("\n");
3771
5079
  let pastHeading = false;
3772
5080
  for (const line of lines) {
@@ -3792,8 +5100,8 @@ async function mergePluginAgentKitGuides(projectRoot, mode) {
3792
5100
  }
3793
5101
  }
3794
5102
  for (const [role, entries] of copiedPerRole) {
3795
- const instructionsPath = path$1.join(agentKitDir, role, "INSTRUCTIONS.md");
3796
- if (!fsSync.existsSync(instructionsPath)) continue;
5103
+ const instructionsPath = path__default.join(agentKitDir, role, "INSTRUCTIONS.md");
5104
+ if (!fs__default.existsSync(instructionsPath)) continue;
3797
5105
  const lines = [
3798
5106
  "",
3799
5107
  "## Plugin-Contributed Guides",
@@ -3805,11 +5113,10 @@ async function mergePluginAgentKitGuides(projectRoot, mode) {
3805
5113
  lines.push(`| [${filename}](${filename}) | ${pluginName} | ${description} |`);
3806
5114
  }
3807
5115
  lines.push("");
3808
- await fs$1.appendFile(instructionsPath, lines.join("\n"));
5116
+ await fs$2.appendFile(instructionsPath, lines.join("\n"));
3809
5117
  }
3810
5118
  }
3811
5119
  async function generatePluginAgentKit(projectRoot, options, initErrors, viteServer) {
3812
- const { discoverPluginsWithAgentKit, executePluginAgentKit } = await import("@jay-framework/stack-server-runtime");
3813
5120
  const plugins = await discoverPluginsWithAgentKit({
3814
5121
  projectRoot,
3815
5122
  verbose: options.verbose,
@@ -3882,7 +5189,6 @@ async function runAction(actionRef, options, projectRoot, initializeServices) {
3882
5189
  }
3883
5190
  viteServer = await createViteForCli({ projectRoot });
3884
5191
  await initializeServices(projectRoot, viteServer);
3885
- const { discoverAndRegisterActions, discoverAllPluginActions, ActionRegistry } = await import("@jay-framework/stack-server-runtime");
3886
5192
  const registry = new ActionRegistry();
3887
5193
  await discoverAndRegisterActions({
3888
5194
  projectRoot,
@@ -3994,8 +5300,8 @@ async function runParams(contractRef, options, projectRoot, initializeServices)
3994
5300
  );
3995
5301
  process.exit(1);
3996
5302
  }
3997
- const { resolveServices } = await import("@jay-framework/stack-server-runtime");
3998
- const resolvedServices = resolveServices(component.services || []);
5303
+ const { resolveServices: resolveServices2 } = await import("@jay-framework/stack-server-runtime");
5304
+ const resolvedServices = resolveServices2(component.services || []);
3999
5305
  const paramsGenerator = component.loadParams(resolvedServices);
4000
5306
  let total = 0;
4001
5307
  for await (const batch of paramsGenerator) {
@@ -4089,7 +5395,7 @@ async function runSetup(pluginFilter, options, projectRoot) {
4089
5395
  try {
4090
5396
  const logger = getLogger();
4091
5397
  const jayConfig = loadConfig();
4092
- const configDir = path$1.resolve(projectRoot, jayConfig.devServer?.configBase || "./config");
5398
+ const configDir = path__default.resolve(projectRoot, jayConfig.devServer?.configBase || "./config");
4093
5399
  logger.important(chalk.bold("\nšŸ”§ Setting up plugins...\n"));
4094
5400
  if (options.verbose) {
4095
5401
  logger.info("Starting Vite for TypeScript support...");
@@ -4121,7 +5427,7 @@ async function runSetup(pluginFilter, options, projectRoot) {
4121
5427
  const interactive = options.interactive === true;
4122
5428
  let answersMap;
4123
5429
  if (options.answers) {
4124
- answersMap = YAML.parse(fsSync.readFileSync(options.answers, "utf-8")) || {};
5430
+ answersMap = YAML.parse(fs__default.readFileSync(options.answers, "utf-8")) || {};
4125
5431
  }
4126
5432
  let configured = 0;
4127
5433
  let needsConfig = 0;
@@ -4248,12 +5554,12 @@ async function initPlugin(pluginName, allPluginsWithInit, viteServer, logger) {
4248
5554
  }
4249
5555
  async function runProjectInit(projectRoot, viteServer) {
4250
5556
  try {
4251
- const initPathTs = path$1.join(projectRoot, "src", "init.ts");
4252
- const initPathJs = path$1.join(projectRoot, "src", "init.js");
5557
+ const initPathTs = path__default.join(projectRoot, "src", "init.ts");
5558
+ const initPathJs = path__default.join(projectRoot, "src", "init.js");
4253
5559
  let initModule;
4254
- if (fsSync.existsSync(initPathTs) && viteServer) {
5560
+ if (fs__default.existsSync(initPathTs) && viteServer) {
4255
5561
  initModule = await viteServer.ssrLoadModule(initPathTs);
4256
- } else if (fsSync.existsSync(initPathJs)) {
5562
+ } else if (fs__default.existsSync(initPathJs)) {
4257
5563
  initModule = await import(initPathJs);
4258
5564
  }
4259
5565
  if (initModule?.init?._serverInit) {
@@ -4266,12 +5572,6 @@ async function runProjectInit(projectRoot, viteServer) {
4266
5572
  async function runCommand(commandRef, rawArgs, options, projectRoot, initializeServices) {
4267
5573
  let viteServer;
4268
5574
  try {
4269
- const {
4270
- discoverPluginCommands,
4271
- commandSchemaToFlags,
4272
- parseInputFromFlags,
4273
- executePluginCommand
4274
- } = await import("@jay-framework/stack-server-runtime");
4275
5575
  const commands = await discoverPluginCommands({
4276
5576
  projectRoot,
4277
5577
  verbose: options.verbose
@@ -4327,21 +5627,19 @@ async function runCommand(commandRef, rawArgs, options, projectRoot, initializeS
4327
5627
  }
4328
5628
  viteServer = await createViteForCli({ projectRoot });
4329
5629
  await initializeServices(projectRoot, viteServer);
4330
- const { registerService } = await import("@jay-framework/stack-server-runtime");
4331
- const { CONSOLE_CONTEXT } = await import("@jay-framework/fullstack-component");
4332
5630
  const jayConfig = loadConfig();
4333
- const publicFolder = path$1.resolve(
5631
+ const publicFolder = path__default.resolve(
4334
5632
  projectRoot,
4335
5633
  jayConfig.devServer?.publicFolder || "public"
4336
5634
  );
4337
5635
  const version = await resolveVersionFromPackageJson(projectRoot);
4338
- const buildRoot = path$1.resolve(projectRoot, `build/v${version}`);
5636
+ const buildRoot = path__default.resolve(projectRoot, `build/v${version}`);
4339
5637
  registerService(CONSOLE_CONTEXT, {
4340
5638
  projectRoot,
4341
5639
  publicFolder,
4342
5640
  build: {
4343
- frontend: path$1.join(buildRoot, "frontend"),
4344
- backend: path$1.join(buildRoot, "backend")
5641
+ frontend: path__default.join(buildRoot, "frontend"),
5642
+ backend: path__default.join(buildRoot, "backend")
4345
5643
  },
4346
5644
  verbose: options.verbose ?? false,
4347
5645
  log: (msg) => getLogger().important(msg),
@@ -4515,9 +5813,9 @@ if (!process.argv.slice(2).length) {
4515
5813
  }
4516
5814
  export {
4517
5815
  getConfigWithDefaults,
4518
- listContracts2 as listContracts,
5816
+ listContracts,
4519
5817
  loadConfig,
4520
- materializeContracts2 as materializeContracts,
5818
+ materializeContracts,
4521
5819
  startDevServer,
4522
5820
  updateConfig
4523
5821
  };