@jay-framework/jay-stack-cli 0.17.3 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-kit-template/designer/jay-html-components.md +2 -0
- package/agent-kit-template/designer/jay-html-syntax.md +1 -1
- package/agent-kit-template/designer/project-structure.md +5 -0
- package/agent-kit-template/developer/cli-commands.md +5 -1
- package/agent-kit-template/developer/component-refs.md +7 -3
- package/agent-kit-template/developer/project-structure.md +5 -0
- package/agent-kit-template/developer/render-results.md +37 -0
- package/agent-kit-template/developer/routing.md +25 -0
- package/agent-kit-template/devops/INSTRUCTIONS.md +24 -0
- package/agent-kit-template/devops/fetch-handler.md +185 -0
- package/agent-kit-template/devops/invalidation.md +77 -0
- package/agent-kit-template/devops/production-build.md +80 -0
- package/agent-kit-template/devops/serving-modes.md +118 -0
- package/agent-kit-template/plugin/INSTRUCTIONS.md +2 -0
- package/agent-kit-template/plugin/actions-guide.md +2 -10
- package/agent-kit-template/plugin/commands-guide.md +121 -0
- package/agent-kit-template/plugin/component-refs.md +7 -3
- package/agent-kit-template/plugin/component-structure.md +26 -2
- package/agent-kit-template/plugin/plugin-structure.md +27 -0
- package/agent-kit-template/plugin/render-results.md +37 -0
- package/agent-kit-template/plugin/webhooks-guide.md +124 -0
- package/dist/index.js +732 -456
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -7,18 +7,18 @@ import getPort from "get-port";
|
|
|
7
7
|
import path from "path";
|
|
8
8
|
import fs, { promises } from "fs";
|
|
9
9
|
import YAML from "yaml";
|
|
10
|
-
import { getLogger,
|
|
10
|
+
import { getLogger, setDevLogger, createDevLogger } from "@jay-framework/logger";
|
|
11
11
|
import { parseJayFile, JAY_IMPORT_RESOLVER, generateElementDefinitionFile, ContractTagType, parseContract, generateElementFile, generateServerElementFile, htmlElementTagNameMap } from "@jay-framework/compiler-jay-html";
|
|
12
12
|
import { JAY_CONTRACT_EXTENSION, JAY_EXTENSION, resolvePluginManifest, LOCAL_PLUGIN_PATH, JayAtomicType, JayEnumType, loadPluginManifest, RuntimeMode, GenerateTarget } from "@jay-framework/compiler-shared";
|
|
13
|
-
import { scanPlugins as scanPlugins$1
|
|
13
|
+
import { listContracts, materializeContracts, scanPlugins as scanPlugins$1 } from "@jay-framework/stack-server-runtime";
|
|
14
14
|
import { listContracts as listContracts2, materializeContracts as materializeContracts2 } from "@jay-framework/stack-server-runtime";
|
|
15
15
|
import { Command } from "commander";
|
|
16
16
|
import chalk from "chalk";
|
|
17
|
+
import path$1 from "node:path";
|
|
18
|
+
import fs$1 from "node:fs/promises";
|
|
17
19
|
import { createRequire } from "module";
|
|
18
20
|
import { glob } from "glob";
|
|
19
21
|
import { parse } from "node-html-parser";
|
|
20
|
-
import path$1 from "node:path";
|
|
21
|
-
import fs$1 from "node:fs/promises";
|
|
22
22
|
import fsSync from "node:fs";
|
|
23
23
|
import { fileURLToPath } from "node:url";
|
|
24
24
|
const DEFAULT_CONFIG = {
|
|
@@ -2530,6 +2530,11 @@ async function startDevServer(options = {}) {
|
|
|
2530
2530
|
routes.forEach((route) => {
|
|
2531
2531
|
app.get(route.path, route.handler);
|
|
2532
2532
|
});
|
|
2533
|
+
service.attachRouteRegistrar((added) => {
|
|
2534
|
+
added.forEach((route) => {
|
|
2535
|
+
app.get(route.path, route.handler);
|
|
2536
|
+
});
|
|
2537
|
+
});
|
|
2533
2538
|
generatePageDefinitionFiles(routes, jayOptions.tsConfigFilePath, process.cwd());
|
|
2534
2539
|
httpServer.listen(devServerPort, () => {
|
|
2535
2540
|
log.important(`🚀 Jay Stack dev server started successfully!`);
|
|
@@ -2583,6 +2588,175 @@ async function startDevServer(options = {}) {
|
|
|
2583
2588
|
process.on("SIGTERM", shutdown);
|
|
2584
2589
|
process.on("SIGINT", shutdown);
|
|
2585
2590
|
}
|
|
2591
|
+
async function initializeServicesForCli(projectRoot, viteServer) {
|
|
2592
|
+
const path2 = await import("node:path");
|
|
2593
|
+
const fs2 = await import("node:fs");
|
|
2594
|
+
const {
|
|
2595
|
+
runInitCallbacks,
|
|
2596
|
+
getServiceRegistry,
|
|
2597
|
+
discoverPluginsWithInit,
|
|
2598
|
+
sortPluginsByDependencies,
|
|
2599
|
+
executePluginServerInits
|
|
2600
|
+
} = await import("@jay-framework/stack-server-runtime");
|
|
2601
|
+
let initErrors = /* @__PURE__ */ new Map();
|
|
2602
|
+
try {
|
|
2603
|
+
const discoveredPlugins = await discoverPluginsWithInit({
|
|
2604
|
+
projectRoot,
|
|
2605
|
+
verbose: false
|
|
2606
|
+
});
|
|
2607
|
+
const pluginsWithInit = sortPluginsByDependencies(discoveredPlugins);
|
|
2608
|
+
try {
|
|
2609
|
+
initErrors = await executePluginServerInits(pluginsWithInit, viteServer, false);
|
|
2610
|
+
} catch (error) {
|
|
2611
|
+
getLogger().warn(chalk.yellow(`⚠️ Plugin initialization skipped: ${error.message}`));
|
|
2612
|
+
}
|
|
2613
|
+
const initPathTs = path2.join(projectRoot, "src", "init.ts");
|
|
2614
|
+
const initPathJs = path2.join(projectRoot, "src", "init.js");
|
|
2615
|
+
let initModule;
|
|
2616
|
+
if (fs2.existsSync(initPathTs) && viteServer) {
|
|
2617
|
+
initModule = await viteServer.ssrLoadModule(initPathTs);
|
|
2618
|
+
} else if (fs2.existsSync(initPathJs)) {
|
|
2619
|
+
initModule = await import(initPathJs);
|
|
2620
|
+
}
|
|
2621
|
+
if (initModule?.init?._serverInit) {
|
|
2622
|
+
await initModule.init._serverInit();
|
|
2623
|
+
}
|
|
2624
|
+
await runInitCallbacks();
|
|
2625
|
+
} catch (error) {
|
|
2626
|
+
getLogger().warn(chalk.yellow(`⚠️ Service initialization failed: ${error.message}`));
|
|
2627
|
+
getLogger().warn(chalk.gray(" Static contracts will still be listed."));
|
|
2628
|
+
}
|
|
2629
|
+
return { services: getServiceRegistry(), initErrors };
|
|
2630
|
+
}
|
|
2631
|
+
async function runDev(projectPath, options) {
|
|
2632
|
+
const logLevel = options.quiet ? "silent" : options.verbose ? "verbose" : "info";
|
|
2633
|
+
setDevLogger(createDevLogger(logLevel));
|
|
2634
|
+
const testMode = options.testMode || options.timeout !== void 0;
|
|
2635
|
+
await startDevServer({
|
|
2636
|
+
projectPath: projectPath || process.cwd(),
|
|
2637
|
+
testMode,
|
|
2638
|
+
timeout: options.timeout,
|
|
2639
|
+
logLevel
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
async function resolveProductionContext(projectPath, versionOverride) {
|
|
2643
|
+
const resolvedPath = path$1.resolve(projectPath || process.cwd());
|
|
2644
|
+
const jayConfigPath = path$1.join(resolvedPath, ".jay");
|
|
2645
|
+
let pagesBase = "./src/pages";
|
|
2646
|
+
try {
|
|
2647
|
+
const jayConfig = YAML.parse(await fs$1.readFile(jayConfigPath, "utf-8"));
|
|
2648
|
+
pagesBase = jayConfig?.devServer?.pagesBase || pagesBase;
|
|
2649
|
+
} catch {
|
|
2650
|
+
}
|
|
2651
|
+
const version = versionOverride || await resolveVersionFromPackageJson(resolvedPath);
|
|
2652
|
+
return {
|
|
2653
|
+
resolvedPath,
|
|
2654
|
+
pagesRoot: path$1.resolve(resolvedPath, pagesBase),
|
|
2655
|
+
buildRoot: path$1.join(resolvedPath, "build"),
|
|
2656
|
+
version,
|
|
2657
|
+
tsConfigFilePath: path$1.join(resolvedPath, "tsconfig.json")
|
|
2658
|
+
};
|
|
2659
|
+
}
|
|
2660
|
+
async function resolveVersionFromPackageJson(projectRoot) {
|
|
2661
|
+
try {
|
|
2662
|
+
const pkgJson = JSON.parse(
|
|
2663
|
+
await fs$1.readFile(path$1.join(projectRoot, "package.json"), "utf-8")
|
|
2664
|
+
);
|
|
2665
|
+
if (pkgJson.version) {
|
|
2666
|
+
return pkgJson.version;
|
|
2667
|
+
}
|
|
2668
|
+
} catch {
|
|
2669
|
+
}
|
|
2670
|
+
return "1";
|
|
2671
|
+
}
|
|
2672
|
+
function initLogger(verbose) {
|
|
2673
|
+
const logLevel = verbose ? "verbose" : "info";
|
|
2674
|
+
setDevLogger(createDevLogger(logLevel));
|
|
2675
|
+
}
|
|
2676
|
+
async function runBuild(projectPath, options) {
|
|
2677
|
+
initLogger(options.verbose);
|
|
2678
|
+
const ctx = await resolveProductionContext(projectPath, options.version);
|
|
2679
|
+
const { buildVersion } = await import("@jay-framework/production-server");
|
|
2680
|
+
await buildVersion({
|
|
2681
|
+
version: ctx.version,
|
|
2682
|
+
projectRoot: ctx.resolvedPath,
|
|
2683
|
+
pagesRoot: ctx.pagesRoot,
|
|
2684
|
+
buildRoot: ctx.buildRoot,
|
|
2685
|
+
concurrency: 4,
|
|
2686
|
+
tsConfigFilePath: ctx.tsConfigFilePath,
|
|
2687
|
+
minify: options.minify
|
|
2688
|
+
});
|
|
2689
|
+
}
|
|
2690
|
+
async function runServe(projectPath, options) {
|
|
2691
|
+
initLogger(options.verbose);
|
|
2692
|
+
const ctx = await resolveProductionContext(projectPath, options.version);
|
|
2693
|
+
if (options.role === "renderer") {
|
|
2694
|
+
const { startRendererServer } = await import("@jay-framework/production-server");
|
|
2695
|
+
await startRendererServer({
|
|
2696
|
+
buildRoot: ctx.buildRoot,
|
|
2697
|
+
version: ctx.version,
|
|
2698
|
+
port: parseInt(options.port, 10),
|
|
2699
|
+
projectRoot: ctx.resolvedPath,
|
|
2700
|
+
pagesRoot: ctx.pagesRoot,
|
|
2701
|
+
tsConfigFilePath: ctx.tsConfigFilePath
|
|
2702
|
+
});
|
|
2703
|
+
} else {
|
|
2704
|
+
const { startMainServer } = await import("@jay-framework/production-server");
|
|
2705
|
+
await startMainServer({
|
|
2706
|
+
buildRoot: ctx.buildRoot,
|
|
2707
|
+
version: ctx.version,
|
|
2708
|
+
port: parseInt(options.port, 10),
|
|
2709
|
+
testMode: options.testMode,
|
|
2710
|
+
publicBasePath: options.staticBaseUrl,
|
|
2711
|
+
serveStatic: options.serveStatic
|
|
2712
|
+
});
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
async function runRebuild(projectPath, options) {
|
|
2716
|
+
initLogger(options.verbose);
|
|
2717
|
+
const ctx = await resolveProductionContext(projectPath, options.version);
|
|
2718
|
+
let params;
|
|
2719
|
+
if (options.params) {
|
|
2720
|
+
params = JSON.parse(options.params);
|
|
2721
|
+
}
|
|
2722
|
+
const { rebuild } = await import("@jay-framework/production-server");
|
|
2723
|
+
let target;
|
|
2724
|
+
if (options.contract) {
|
|
2725
|
+
target = { mode: "contract", contractName: options.contract, params };
|
|
2726
|
+
} else if (options.route) {
|
|
2727
|
+
target = { mode: "route", routePattern: options.route, params };
|
|
2728
|
+
} else if (options.url) {
|
|
2729
|
+
target = { mode: "url", url: options.url };
|
|
2730
|
+
} else {
|
|
2731
|
+
getLogger().error(chalk.red("One of --contract, --route, or --url is required"));
|
|
2732
|
+
process.exit(1);
|
|
2733
|
+
}
|
|
2734
|
+
const result = await rebuild({
|
|
2735
|
+
projectRoot: ctx.resolvedPath,
|
|
2736
|
+
pagesRoot: ctx.pagesRoot,
|
|
2737
|
+
buildRoot: ctx.buildRoot,
|
|
2738
|
+
version: ctx.version,
|
|
2739
|
+
target,
|
|
2740
|
+
tsConfigFilePath: ctx.tsConfigFilePath
|
|
2741
|
+
});
|
|
2742
|
+
if (result.errors.length > 0) {
|
|
2743
|
+
for (const err of result.errors) {
|
|
2744
|
+
getLogger().error(
|
|
2745
|
+
chalk.red(` Error: ${err.route} ${JSON.stringify(err.params)}: ${err.error}`)
|
|
2746
|
+
);
|
|
2747
|
+
}
|
|
2748
|
+
process.exit(1);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
const runProduction = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2752
|
+
__proto__: null,
|
|
2753
|
+
initLogger,
|
|
2754
|
+
resolveProductionContext,
|
|
2755
|
+
resolveVersionFromPackageJson,
|
|
2756
|
+
runBuild,
|
|
2757
|
+
runRebuild,
|
|
2758
|
+
runServe
|
|
2759
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2586
2760
|
const s = createRequire(import.meta.url), e = s("typescript"), u = e;
|
|
2587
2761
|
new Proxy(e, {
|
|
2588
2762
|
get(t, r) {
|
|
@@ -3605,9 +3779,6 @@ const SKIP_ATTRS = /* @__PURE__ */ new Set([
|
|
|
3605
3779
|
"if",
|
|
3606
3780
|
"ref",
|
|
3607
3781
|
"trackBy",
|
|
3608
|
-
"slowForEach",
|
|
3609
|
-
"jayIndex",
|
|
3610
|
-
"jayTrackBy",
|
|
3611
3782
|
"when-resolved",
|
|
3612
3783
|
"when-loading",
|
|
3613
3784
|
"when-rejected",
|
|
@@ -4260,95 +4431,369 @@ function printJayValidationResult(result, options) {
|
|
|
4260
4431
|
}
|
|
4261
4432
|
}
|
|
4262
4433
|
}
|
|
4263
|
-
async function
|
|
4264
|
-
const
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
}
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4434
|
+
async function runValidate(scanPath, options) {
|
|
4435
|
+
const result = await validateJayFiles({
|
|
4436
|
+
path: scanPath,
|
|
4437
|
+
verbose: options.verbose,
|
|
4438
|
+
json: options.json
|
|
4439
|
+
});
|
|
4440
|
+
printJayValidationResult(result, options);
|
|
4441
|
+
if (!result.valid) {
|
|
4442
|
+
process.exit(1);
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
async function runValidatePlugin(pluginPath, options) {
|
|
4446
|
+
const result = await validatePlugin({
|
|
4447
|
+
pluginPath: pluginPath || process.cwd(),
|
|
4448
|
+
local: options.local,
|
|
4449
|
+
verbose: options.verbose,
|
|
4450
|
+
strict: options.strict,
|
|
4451
|
+
generateTypes: options.generateTypes
|
|
4452
|
+
});
|
|
4453
|
+
printValidationResult(result, options.verbose ?? false);
|
|
4454
|
+
if (!result.valid || options.strict && result.warnings.length > 0) {
|
|
4455
|
+
process.exit(1);
|
|
4456
|
+
}
|
|
4457
|
+
}
|
|
4458
|
+
function printValidationResult(result, verbose) {
|
|
4459
|
+
const logger = getLogger();
|
|
4460
|
+
if (result.valid && result.warnings.length === 0) {
|
|
4461
|
+
logger.important(chalk.green("Plugin validation successful!\n"));
|
|
4462
|
+
if (verbose) {
|
|
4463
|
+
logger.important("Plugin: " + result.pluginName);
|
|
4464
|
+
logger.important(" plugin.yaml valid");
|
|
4465
|
+
logger.important(` ${result.contractsChecked} contracts validated`);
|
|
4466
|
+
if (result.typesGenerated) {
|
|
4467
|
+
logger.important(` ${result.typesGenerated} type definitions generated`);
|
|
4468
|
+
}
|
|
4469
|
+
logger.important(` ${result.componentsChecked} components validated`);
|
|
4470
|
+
if (result.packageJsonChecked) {
|
|
4471
|
+
logger.important(" package.json valid");
|
|
4472
|
+
}
|
|
4473
|
+
logger.important("\nNo errors found.");
|
|
4284
4474
|
}
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4475
|
+
} else if (result.valid && result.warnings.length > 0) {
|
|
4476
|
+
logger.important(chalk.yellow("Plugin validation passed with warnings\n"));
|
|
4477
|
+
logger.important("Warnings:");
|
|
4478
|
+
result.warnings.forEach((warning) => {
|
|
4479
|
+
logger.important(chalk.yellow(` ${warning.message}`));
|
|
4480
|
+
if (warning.location) {
|
|
4481
|
+
logger.important(chalk.gray(` Location: ${warning.location}`));
|
|
4482
|
+
}
|
|
4483
|
+
if (warning.suggestion) {
|
|
4484
|
+
logger.important(chalk.gray(` ${warning.suggestion}`));
|
|
4485
|
+
}
|
|
4486
|
+
logger.important("");
|
|
4487
|
+
});
|
|
4488
|
+
logger.important(chalk.gray("Use --strict to treat warnings as errors."));
|
|
4489
|
+
} else {
|
|
4490
|
+
logger.important(chalk.red("Plugin validation failed\n"));
|
|
4491
|
+
logger.important("Errors:");
|
|
4492
|
+
result.errors.forEach((error) => {
|
|
4493
|
+
logger.important(chalk.red(` ${error.message}`));
|
|
4494
|
+
if (error.location) {
|
|
4495
|
+
logger.important(chalk.gray(` Location: ${error.location}`));
|
|
4496
|
+
}
|
|
4497
|
+
if (error.suggestion) {
|
|
4498
|
+
logger.important(chalk.gray(` ${error.suggestion}`));
|
|
4499
|
+
}
|
|
4500
|
+
logger.important("");
|
|
4501
|
+
});
|
|
4502
|
+
logger.important(chalk.red(`${result.errors.length} errors found.`));
|
|
4503
|
+
}
|
|
4504
|
+
}
|
|
4505
|
+
const ALL_ROLES = ["designer", "developer", "plugin", "devops"];
|
|
4506
|
+
async function runAgentKit(options) {
|
|
4507
|
+
const projectRoot = process.cwd();
|
|
4508
|
+
const { initErrors, viteServer } = await runMaterialize(
|
|
4509
|
+
projectRoot,
|
|
4510
|
+
options,
|
|
4511
|
+
"agent-kit/materialized-contracts",
|
|
4512
|
+
true
|
|
4513
|
+
);
|
|
4514
|
+
try {
|
|
4515
|
+
if (!options.list) {
|
|
4516
|
+
await ensureAgentKitDocs(projectRoot, options.force, options.mode);
|
|
4517
|
+
await mergePluginAgentKitGuides(projectRoot, options.mode);
|
|
4518
|
+
if (options.references !== false) {
|
|
4519
|
+
await generatePluginReferences(projectRoot, options, initErrors, viteServer);
|
|
4520
|
+
}
|
|
4292
4521
|
}
|
|
4293
|
-
|
|
4294
|
-
|
|
4522
|
+
} finally {
|
|
4523
|
+
if (viteServer) {
|
|
4524
|
+
await viteServer.close();
|
|
4295
4525
|
}
|
|
4296
|
-
await runInitCallbacks();
|
|
4297
|
-
} catch (error) {
|
|
4298
|
-
getLogger().warn(chalk.yellow(`⚠️ Service initialization failed: ${error.message}`));
|
|
4299
|
-
getLogger().warn(chalk.gray(" Static contracts will still be listed."));
|
|
4300
4526
|
}
|
|
4301
|
-
return { services: getServiceRegistry(), initErrors };
|
|
4302
4527
|
}
|
|
4303
|
-
async function
|
|
4528
|
+
async function runMaterialize(projectRoot, options, defaultOutputRelative, keepViteAlive = false) {
|
|
4529
|
+
const outputDir = options.output ?? path$1.join(projectRoot, defaultOutputRelative);
|
|
4304
4530
|
let viteServer;
|
|
4531
|
+
let initErrors = /* @__PURE__ */ new Map();
|
|
4305
4532
|
try {
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4533
|
+
if (options.list) {
|
|
4534
|
+
const index = await listContracts({
|
|
4535
|
+
projectRoot,
|
|
4536
|
+
dynamicOnly: options.dynamicOnly,
|
|
4537
|
+
pluginFilter: options.plugin
|
|
4538
|
+
});
|
|
4539
|
+
if (options.yaml) {
|
|
4540
|
+
getLogger().important(YAML.stringify(index));
|
|
4541
|
+
} else {
|
|
4542
|
+
printContractList(index);
|
|
4543
|
+
}
|
|
4544
|
+
return { initErrors };
|
|
4312
4545
|
}
|
|
4313
|
-
const actionExport = actionRef.substring(slashIndex + 1);
|
|
4314
|
-
const input = options.input ? JSON.parse(options.input) : {};
|
|
4315
4546
|
if (options.verbose) {
|
|
4316
4547
|
getLogger().info("Starting Vite for TypeScript support...");
|
|
4317
4548
|
}
|
|
4318
4549
|
viteServer = await createViteForCli({ projectRoot });
|
|
4319
|
-
await
|
|
4320
|
-
const { discoverAndRegisterActions, discoverAllPluginActions, ActionRegistry } = await import("@jay-framework/stack-server-runtime");
|
|
4321
|
-
const registry = new ActionRegistry();
|
|
4322
|
-
await discoverAndRegisterActions({
|
|
4323
|
-
projectRoot,
|
|
4324
|
-
registry,
|
|
4325
|
-
verbose: options.verbose,
|
|
4326
|
-
viteServer
|
|
4327
|
-
});
|
|
4328
|
-
await discoverAllPluginActions({
|
|
4550
|
+
const { services, initErrors: errors } = await initializeServicesForCli(
|
|
4329
4551
|
projectRoot,
|
|
4330
|
-
registry,
|
|
4331
|
-
verbose: options.verbose,
|
|
4332
4552
|
viteServer
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
const
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4553
|
+
);
|
|
4554
|
+
initErrors = errors;
|
|
4555
|
+
const result = await materializeContracts(
|
|
4556
|
+
{
|
|
4557
|
+
projectRoot,
|
|
4558
|
+
outputDir,
|
|
4559
|
+
force: options.force,
|
|
4560
|
+
dynamicOnly: options.dynamicOnly,
|
|
4561
|
+
pluginFilter: options.plugin,
|
|
4562
|
+
verbose: options.verbose,
|
|
4563
|
+
viteServer
|
|
4564
|
+
},
|
|
4565
|
+
services
|
|
4566
|
+
);
|
|
4567
|
+
if (options.yaml) {
|
|
4568
|
+
getLogger().important(YAML.stringify(result.pluginsIndex));
|
|
4569
|
+
} else {
|
|
4570
|
+
const totalContracts = result.pluginsIndex.plugins.reduce(
|
|
4571
|
+
(sum, p) => sum + p.contracts.length,
|
|
4572
|
+
0
|
|
4573
|
+
);
|
|
4574
|
+
getLogger().important(chalk.green(`
|
|
4575
|
+
Materialized ${totalContracts} contracts`));
|
|
4576
|
+
getLogger().important(` Static: ${result.staticCount}`);
|
|
4577
|
+
getLogger().important(` Dynamic: ${result.dynamicCount}`);
|
|
4578
|
+
getLogger().important(` Output: ${result.outputDir}`);
|
|
4344
4579
|
}
|
|
4580
|
+
return { initErrors, viteServer: keepViteAlive ? viteServer : void 0 };
|
|
4581
|
+
} catch (error) {
|
|
4582
|
+
getLogger().error(chalk.red("Failed to materialize contracts:") + " " + error.message);
|
|
4345
4583
|
if (options.verbose) {
|
|
4346
|
-
getLogger().
|
|
4347
|
-
getLogger().info(`Input: ${JSON.stringify(input)}`);
|
|
4584
|
+
getLogger().error(error.stack);
|
|
4348
4585
|
}
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4586
|
+
process.exit(1);
|
|
4587
|
+
} finally {
|
|
4588
|
+
if (viteServer && !keepViteAlive) {
|
|
4589
|
+
await viteServer.close();
|
|
4590
|
+
}
|
|
4591
|
+
}
|
|
4592
|
+
return { initErrors };
|
|
4593
|
+
}
|
|
4594
|
+
async function ensureAgentKitDocs(projectRoot, _force, mode) {
|
|
4595
|
+
const agentKitDir = path$1.join(projectRoot, "agent-kit");
|
|
4596
|
+
const thisDir = path$1.dirname(fileURLToPath(import.meta.url));
|
|
4597
|
+
const templateDir = path$1.resolve(thisDir, "..", "agent-kit-template");
|
|
4598
|
+
const roles = mode && ALL_ROLES.includes(mode) ? [mode] : ALL_ROLES;
|
|
4599
|
+
for (const role of roles) {
|
|
4600
|
+
const roleTemplateDir = path$1.join(templateDir, role);
|
|
4601
|
+
const roleOutputDir = path$1.join(agentKitDir, role);
|
|
4602
|
+
let files;
|
|
4603
|
+
try {
|
|
4604
|
+
files = (await fs$1.readdir(roleTemplateDir)).filter((f) => f.endsWith(".md"));
|
|
4605
|
+
} catch {
|
|
4606
|
+
continue;
|
|
4607
|
+
}
|
|
4608
|
+
await fs$1.mkdir(roleOutputDir, { recursive: true });
|
|
4609
|
+
for (const filename of files) {
|
|
4610
|
+
await fs$1.copyFile(
|
|
4611
|
+
path$1.join(roleTemplateDir, filename),
|
|
4612
|
+
path$1.join(roleOutputDir, filename)
|
|
4613
|
+
);
|
|
4614
|
+
getLogger().info(chalk.gray(` Created agent-kit/${role}/${filename}`));
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4618
|
+
async function mergePluginAgentKitGuides(projectRoot, mode) {
|
|
4619
|
+
const plugins = await scanPlugins$1({ projectRoot });
|
|
4620
|
+
const agentKitDir = path$1.join(projectRoot, "agent-kit");
|
|
4621
|
+
const roles = mode && ALL_ROLES.includes(mode) ? [mode] : ALL_ROLES;
|
|
4622
|
+
const copiedPerRole = /* @__PURE__ */ new Map();
|
|
4623
|
+
for (const [, plugin] of plugins) {
|
|
4624
|
+
const pluginAgentKitDir = path$1.join(plugin.pluginPath, "agent-kit");
|
|
4625
|
+
if (!fsSync.existsSync(pluginAgentKitDir))
|
|
4626
|
+
continue;
|
|
4627
|
+
for (const role of roles) {
|
|
4628
|
+
const roleSourceDir = path$1.join(pluginAgentKitDir, role);
|
|
4629
|
+
let files;
|
|
4630
|
+
try {
|
|
4631
|
+
files = (await fs$1.readdir(roleSourceDir)).filter(
|
|
4632
|
+
(f) => f.endsWith(".md") && f !== "INSTRUCTIONS.md"
|
|
4633
|
+
);
|
|
4634
|
+
} catch {
|
|
4635
|
+
continue;
|
|
4636
|
+
}
|
|
4637
|
+
if (files.length === 0)
|
|
4638
|
+
continue;
|
|
4639
|
+
const roleOutputDir = path$1.join(agentKitDir, role);
|
|
4640
|
+
await fs$1.mkdir(roleOutputDir, { recursive: true });
|
|
4641
|
+
for (const filename of files) {
|
|
4642
|
+
const sourcePath = path$1.join(roleSourceDir, filename);
|
|
4643
|
+
await fs$1.copyFile(sourcePath, path$1.join(roleOutputDir, filename));
|
|
4644
|
+
let description = "";
|
|
4645
|
+
try {
|
|
4646
|
+
const content = await fs$1.readFile(sourcePath, "utf-8");
|
|
4647
|
+
const lines = content.split("\n");
|
|
4648
|
+
let pastHeading = false;
|
|
4649
|
+
for (const line of lines) {
|
|
4650
|
+
if (line.startsWith("# ")) {
|
|
4651
|
+
pastHeading = true;
|
|
4652
|
+
continue;
|
|
4653
|
+
}
|
|
4654
|
+
if (pastHeading && line.trim()) {
|
|
4655
|
+
description = line.trim();
|
|
4656
|
+
break;
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
} catch {
|
|
4660
|
+
}
|
|
4661
|
+
if (!copiedPerRole.has(role))
|
|
4662
|
+
copiedPerRole.set(role, []);
|
|
4663
|
+
copiedPerRole.get(role).push({ filename, pluginName: plugin.name, description });
|
|
4664
|
+
getLogger().info(
|
|
4665
|
+
chalk.gray(
|
|
4666
|
+
` Copied agent-kit/${role}/${filename} from plugin "${plugin.name}"`
|
|
4667
|
+
)
|
|
4668
|
+
);
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
for (const [role, entries] of copiedPerRole) {
|
|
4673
|
+
const instructionsPath = path$1.join(agentKitDir, role, "INSTRUCTIONS.md");
|
|
4674
|
+
if (!fsSync.existsSync(instructionsPath))
|
|
4675
|
+
continue;
|
|
4676
|
+
const lines = [
|
|
4677
|
+
"",
|
|
4678
|
+
"## Plugin-Contributed Guides",
|
|
4679
|
+
"",
|
|
4680
|
+
"| File | Plugin | Description |",
|
|
4681
|
+
"| --- | --- | --- |"
|
|
4682
|
+
];
|
|
4683
|
+
for (const { filename, pluginName, description } of entries) {
|
|
4684
|
+
lines.push(`| [${filename}](${filename}) | ${pluginName} | ${description} |`);
|
|
4685
|
+
}
|
|
4686
|
+
lines.push("");
|
|
4687
|
+
await fs$1.appendFile(instructionsPath, lines.join("\n"));
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
async function generatePluginReferences(projectRoot, options, initErrors, viteServer) {
|
|
4691
|
+
const { discoverPluginsWithReferences, executePluginReferences } = await import("@jay-framework/stack-server-runtime");
|
|
4692
|
+
const plugins = await discoverPluginsWithReferences({
|
|
4693
|
+
projectRoot,
|
|
4694
|
+
verbose: options.verbose,
|
|
4695
|
+
pluginFilter: options.plugin
|
|
4696
|
+
});
|
|
4697
|
+
if (plugins.length === 0)
|
|
4698
|
+
return;
|
|
4699
|
+
const logger = getLogger();
|
|
4700
|
+
logger.important("");
|
|
4701
|
+
logger.important(chalk.bold("Generating plugin references..."));
|
|
4702
|
+
for (const plugin of plugins) {
|
|
4703
|
+
const pluginInitError = initErrors.get(plugin.name);
|
|
4704
|
+
if (pluginInitError) {
|
|
4705
|
+
logger.warn(
|
|
4706
|
+
chalk.yellow(
|
|
4707
|
+
` ${plugin.name}: references skipped — init failed: ${pluginInitError.message}`
|
|
4708
|
+
)
|
|
4709
|
+
);
|
|
4710
|
+
continue;
|
|
4711
|
+
}
|
|
4712
|
+
try {
|
|
4713
|
+
const result = await executePluginReferences(plugin, {
|
|
4714
|
+
projectRoot,
|
|
4715
|
+
force: options.force ?? false,
|
|
4716
|
+
viteServer,
|
|
4717
|
+
verbose: options.verbose
|
|
4718
|
+
});
|
|
4719
|
+
if (result.referencesCreated.length > 0) {
|
|
4720
|
+
logger.important(chalk.green(` ${plugin.name}:`));
|
|
4721
|
+
for (const ref of result.referencesCreated) {
|
|
4722
|
+
logger.important(chalk.gray(` ${ref}`));
|
|
4723
|
+
}
|
|
4724
|
+
if (result.message) {
|
|
4725
|
+
logger.important(chalk.gray(` ${result.message}`));
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
} catch (error) {
|
|
4729
|
+
logger.warn(chalk.yellow(` ${plugin.name}: references skipped — ${error.message}`));
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
}
|
|
4733
|
+
function printContractList(index) {
|
|
4734
|
+
const logger = getLogger();
|
|
4735
|
+
logger.important("\nAvailable Contracts:\n");
|
|
4736
|
+
for (const plugin of index.plugins) {
|
|
4737
|
+
logger.important(chalk.bold(plugin.name));
|
|
4738
|
+
for (const contract of plugin.contracts) {
|
|
4739
|
+
const typeIcon = contract.type === "static" ? "static" : "dynamic";
|
|
4740
|
+
logger.important(` [${typeIcon}] ${contract.name}`);
|
|
4741
|
+
}
|
|
4742
|
+
logger.important("");
|
|
4743
|
+
}
|
|
4744
|
+
if (index.plugins.length === 0) {
|
|
4745
|
+
logger.important(chalk.gray("No contracts found."));
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
async function runAction(actionRef, options, projectRoot, initializeServices) {
|
|
4749
|
+
let viteServer;
|
|
4750
|
+
try {
|
|
4751
|
+
const slashIndex = actionRef.indexOf("/");
|
|
4752
|
+
if (slashIndex === -1) {
|
|
4753
|
+
getLogger().error(
|
|
4754
|
+
chalk.red("❌ Invalid action reference. Use format: <plugin>/<action>")
|
|
4755
|
+
);
|
|
4756
|
+
process.exit(1);
|
|
4757
|
+
}
|
|
4758
|
+
const actionExport = actionRef.substring(slashIndex + 1);
|
|
4759
|
+
const input = options.input ? JSON.parse(options.input) : {};
|
|
4760
|
+
if (options.verbose) {
|
|
4761
|
+
getLogger().info("Starting Vite for TypeScript support...");
|
|
4762
|
+
}
|
|
4763
|
+
viteServer = await createViteForCli({ projectRoot });
|
|
4764
|
+
await initializeServices(projectRoot, viteServer);
|
|
4765
|
+
const { discoverAndRegisterActions, discoverAllPluginActions, ActionRegistry } = await import("@jay-framework/stack-server-runtime");
|
|
4766
|
+
const registry = new ActionRegistry();
|
|
4767
|
+
await discoverAndRegisterActions({
|
|
4768
|
+
projectRoot,
|
|
4769
|
+
registry,
|
|
4770
|
+
verbose: options.verbose,
|
|
4771
|
+
viteServer
|
|
4772
|
+
});
|
|
4773
|
+
await discoverAllPluginActions({
|
|
4774
|
+
projectRoot,
|
|
4775
|
+
registry,
|
|
4776
|
+
verbose: options.verbose,
|
|
4777
|
+
viteServer
|
|
4778
|
+
});
|
|
4779
|
+
const allNames = registry.getNames();
|
|
4780
|
+
const matchedName = allNames.find((name) => name === actionExport) || allNames.find((name) => name.endsWith("." + actionExport)) || allNames.find((name) => name === actionRef);
|
|
4781
|
+
if (!matchedName) {
|
|
4782
|
+
getLogger().error(chalk.red(`❌ Action "${actionExport}" not found.`));
|
|
4783
|
+
if (allNames.length > 0) {
|
|
4784
|
+
getLogger().error(` Available actions: ${allNames.join(", ")}`);
|
|
4785
|
+
} else {
|
|
4786
|
+
getLogger().error(" No actions registered. Does the plugin have actions?");
|
|
4787
|
+
}
|
|
4788
|
+
process.exit(1);
|
|
4789
|
+
}
|
|
4790
|
+
if (options.verbose) {
|
|
4791
|
+
getLogger().info(`Executing action: ${matchedName}`);
|
|
4792
|
+
getLogger().info(`Input: ${JSON.stringify(input)}`);
|
|
4793
|
+
}
|
|
4794
|
+
const result = await registry.execute(matchedName, input);
|
|
4795
|
+
if (result.success) {
|
|
4796
|
+
if (options.yaml) {
|
|
4352
4797
|
getLogger().important(YAML.stringify(result.data));
|
|
4353
4798
|
} else {
|
|
4354
4799
|
getLogger().important(JSON.stringify(result.data, null, 2));
|
|
@@ -4584,65 +5029,184 @@ async function runSetup(pluginFilter, options, projectRoot, initializeServices)
|
|
|
4584
5029
|
}
|
|
4585
5030
|
}
|
|
4586
5031
|
}
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
program.command("dev [path]").description("Start the Jay Stack development server").option("-v, --verbose", "Enable verbose logging output").option("-q, --quiet", "Suppress all non-error output").option("--test-mode", "Enable test endpoints (/_jay/health, /_jay/shutdown)").option("--timeout <seconds>", "Auto-shutdown after N seconds (implies --test-mode)", parseInt).action(async (path2, options) => {
|
|
5032
|
+
async function runCommand(commandRef, rawArgs, options, projectRoot, initializeServices) {
|
|
5033
|
+
let viteServer;
|
|
4590
5034
|
try {
|
|
4591
|
-
const
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
5035
|
+
const {
|
|
5036
|
+
discoverPluginCommands,
|
|
5037
|
+
commandSchemaToFlags,
|
|
5038
|
+
parseInputFromFlags,
|
|
5039
|
+
executePluginCommand
|
|
5040
|
+
} = await import("@jay-framework/stack-server-runtime");
|
|
5041
|
+
const commands = await discoverPluginCommands({
|
|
5042
|
+
projectRoot,
|
|
5043
|
+
verbose: options.verbose
|
|
4599
5044
|
});
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
5045
|
+
if (options.list || !commandRef) {
|
|
5046
|
+
printCommandList(commands);
|
|
5047
|
+
return;
|
|
5048
|
+
}
|
|
5049
|
+
const slashIndex = commandRef.indexOf("/");
|
|
5050
|
+
if (slashIndex === -1) {
|
|
5051
|
+
getLogger().error(
|
|
5052
|
+
chalk.red("Invalid command reference. Use format: <plugin>/<command>")
|
|
5053
|
+
);
|
|
5054
|
+
getLogger().error(chalk.gray("Example: jay-stack run media/upload-public"));
|
|
5055
|
+
process.exit(1);
|
|
5056
|
+
}
|
|
5057
|
+
const pluginName = commandRef.substring(0, slashIndex);
|
|
5058
|
+
const commandName = commandRef.substring(slashIndex + 1);
|
|
5059
|
+
const command = commands.find(
|
|
5060
|
+
(c) => (c.pluginName === pluginName || c.packageName === pluginName) && c.commandName === commandName
|
|
5061
|
+
);
|
|
5062
|
+
if (!command) {
|
|
5063
|
+
getLogger().error(chalk.red(`Command "${commandRef}" not found.`));
|
|
5064
|
+
const pluginCommands = commands.filter(
|
|
5065
|
+
(c) => c.pluginName === pluginName || c.packageName === pluginName
|
|
5066
|
+
);
|
|
5067
|
+
if (pluginCommands.length > 0) {
|
|
5068
|
+
getLogger().error(`Available commands for ${pluginName}:`);
|
|
5069
|
+
for (const c of pluginCommands) {
|
|
5070
|
+
getLogger().error(
|
|
5071
|
+
` ${c.commandName}${c.metadata?.description ? " " + c.metadata.description : ""}`
|
|
5072
|
+
);
|
|
5073
|
+
}
|
|
5074
|
+
} else if (commands.length > 0) {
|
|
5075
|
+
getLogger().error("Available plugins with commands:");
|
|
5076
|
+
const plugins = [...new Set(commands.map((c) => c.pluginName))];
|
|
5077
|
+
for (const p of plugins) {
|
|
5078
|
+
getLogger().error(` ${p}`);
|
|
5079
|
+
}
|
|
5080
|
+
} else {
|
|
5081
|
+
getLogger().error("No plugins with CLI commands found.");
|
|
5082
|
+
}
|
|
5083
|
+
process.exit(1);
|
|
5084
|
+
}
|
|
5085
|
+
let input = {};
|
|
5086
|
+
if (command.metadata?.inputSchema) {
|
|
5087
|
+
const flagDefs = commandSchemaToFlags(command.metadata.inputSchema);
|
|
5088
|
+
const rawOptions = parseRawFlags(rawArgs, flagDefs);
|
|
5089
|
+
input = parseInputFromFlags(rawOptions, command.metadata.inputSchema);
|
|
4616
5090
|
}
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
5091
|
+
if (options.verbose) {
|
|
5092
|
+
getLogger().info("Starting Vite for TypeScript support...");
|
|
5093
|
+
}
|
|
5094
|
+
viteServer = await createViteForCli({ projectRoot });
|
|
5095
|
+
await initializeServices(projectRoot, viteServer);
|
|
5096
|
+
const { registerService } = await import("@jay-framework/stack-server-runtime");
|
|
5097
|
+
const { CONSOLE_CONTEXT } = await import("@jay-framework/fullstack-component");
|
|
5098
|
+
const jayConfig = loadConfig();
|
|
5099
|
+
const publicFolder = path$1.resolve(
|
|
5100
|
+
projectRoot,
|
|
5101
|
+
jayConfig.devServer?.publicFolder || "public"
|
|
5102
|
+
);
|
|
5103
|
+
const version = await resolveVersionFromPackageJson(projectRoot);
|
|
5104
|
+
const buildRoot = path$1.resolve(projectRoot, `build/v${version}`);
|
|
5105
|
+
registerService(CONSOLE_CONTEXT, {
|
|
5106
|
+
projectRoot,
|
|
5107
|
+
publicFolder,
|
|
5108
|
+
build: {
|
|
5109
|
+
frontend: path$1.join(buildRoot, "frontend"),
|
|
5110
|
+
backend: path$1.join(buildRoot, "backend")
|
|
5111
|
+
},
|
|
5112
|
+
verbose: options.verbose ?? false,
|
|
5113
|
+
log: (msg) => getLogger().important(msg),
|
|
5114
|
+
warn: (msg) => getLogger().warn(chalk.yellow(msg)),
|
|
5115
|
+
error: (msg) => getLogger().error(chalk.red(msg))
|
|
4627
5116
|
});
|
|
5117
|
+
if (options.verbose) {
|
|
5118
|
+
getLogger().info(`Executing ${command.pluginName}/${command.commandName}...`);
|
|
5119
|
+
}
|
|
5120
|
+
const result = await executePluginCommand(command, input, viteServer);
|
|
5121
|
+
if (!result.success) {
|
|
5122
|
+
process.exit(1);
|
|
5123
|
+
}
|
|
4628
5124
|
} catch (error) {
|
|
4629
|
-
getLogger().error(chalk.red("
|
|
4630
|
-
if (
|
|
5125
|
+
getLogger().error(chalk.red("Command failed:") + " " + error.message);
|
|
5126
|
+
if (options.verbose) {
|
|
4631
5127
|
getLogger().error(error.stack);
|
|
5128
|
+
}
|
|
4632
5129
|
process.exit(1);
|
|
5130
|
+
} finally {
|
|
5131
|
+
if (viteServer) {
|
|
5132
|
+
await viteServer.close();
|
|
5133
|
+
}
|
|
4633
5134
|
}
|
|
4634
|
-
}
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
5135
|
+
}
|
|
5136
|
+
function printCommandList(commands) {
|
|
5137
|
+
const logger = getLogger();
|
|
5138
|
+
if (commands.length === 0) {
|
|
5139
|
+
logger.important(chalk.gray("No plugins with CLI commands found."));
|
|
5140
|
+
return;
|
|
5141
|
+
}
|
|
5142
|
+
logger.important("\nAvailable plugin commands:\n");
|
|
5143
|
+
const byPlugin = /* @__PURE__ */ new Map();
|
|
5144
|
+
for (const cmd of commands) {
|
|
5145
|
+
if (!byPlugin.has(cmd.pluginName))
|
|
5146
|
+
byPlugin.set(cmd.pluginName, []);
|
|
5147
|
+
byPlugin.get(cmd.pluginName).push(cmd);
|
|
5148
|
+
}
|
|
5149
|
+
for (const [pluginName, cmds] of byPlugin) {
|
|
5150
|
+
logger.important(chalk.bold(` ${pluginName}`));
|
|
5151
|
+
for (const cmd of cmds) {
|
|
5152
|
+
const desc = cmd.metadata?.description ? ` ${cmd.metadata.description}` : "";
|
|
5153
|
+
logger.important(` ${cmd.commandName}${desc}`);
|
|
5154
|
+
}
|
|
5155
|
+
logger.important("");
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
function parseRawFlags(args, flagDefs) {
|
|
5159
|
+
const result = {};
|
|
5160
|
+
const booleanFlags = new Set(
|
|
5161
|
+
flagDefs.filter((f) => f.type === "boolean").map((f) => {
|
|
5162
|
+
const match = f.flag.match(/^--(\S+)/);
|
|
5163
|
+
return match ? match[1] : "";
|
|
5164
|
+
})
|
|
5165
|
+
);
|
|
5166
|
+
let i = 0;
|
|
5167
|
+
while (i < args.length) {
|
|
5168
|
+
const arg = args[i];
|
|
5169
|
+
if (arg.startsWith("--")) {
|
|
5170
|
+
const name = arg.slice(2);
|
|
5171
|
+
if (booleanFlags.has(name)) {
|
|
5172
|
+
result[name] = true;
|
|
5173
|
+
i++;
|
|
5174
|
+
} else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
|
|
5175
|
+
result[name] = args[i + 1];
|
|
5176
|
+
i += 2;
|
|
5177
|
+
} else {
|
|
5178
|
+
result[name] = true;
|
|
5179
|
+
i++;
|
|
5180
|
+
}
|
|
5181
|
+
} else {
|
|
5182
|
+
i++;
|
|
5183
|
+
}
|
|
5184
|
+
}
|
|
5185
|
+
return result;
|
|
5186
|
+
}
|
|
5187
|
+
const program = new Command();
|
|
5188
|
+
program.name("jay-stack").description("Jay Stack CLI - Development server and plugin validation").version("0.9.0");
|
|
5189
|
+
program.command("dev").description("Start the Jay Stack development server").option("-p, --path <path>", "Project root (default: cwd)").option("-v, --verbose", "Enable verbose logging output").option("-q, --quiet", "Suppress all non-error output").option("--test-mode", "Enable test endpoints (/_jay/health, /_jay/shutdown)").option("--timeout <seconds>", "Auto-shutdown after N seconds (implies --test-mode)", parseInt).action(async (options) => {
|
|
5190
|
+
try {
|
|
5191
|
+
await runDev(options.path, options);
|
|
5192
|
+
} catch (error) {
|
|
5193
|
+
getLogger().error(chalk.red("Error starting dev server:") + " " + error.message);
|
|
5194
|
+
process.exit(1);
|
|
5195
|
+
}
|
|
5196
|
+
});
|
|
5197
|
+
program.command("build").description("Build production artifacts").option("-p, --path <path>", "Project root (default: cwd)").option("--version <n>", "Build version number (default: from package.json)").option("--no-minify", "Disable minification (useful for debugging)").option("-v, --verbose", "Enable verbose logging output").action(async (options) => {
|
|
5198
|
+
try {
|
|
5199
|
+
await runBuild(options.path, options);
|
|
5200
|
+
} catch (error) {
|
|
5201
|
+
getLogger().error(chalk.red("Build failed:") + " " + error.message);
|
|
5202
|
+
if (error.stack)
|
|
5203
|
+
getLogger().error(error.stack);
|
|
5204
|
+
process.exit(1);
|
|
5205
|
+
}
|
|
5206
|
+
});
|
|
5207
|
+
program.command("serve").description("Start production server").option("-p, --path <path>", "Project root (default: cwd)").option("--version <n>", "Build version to serve (default: from package.json)").option("--port <n>", "Port number", "3000").option("--role <role>", "Server role: main (default) or renderer", "main").option("--static-base-url <url>", "Base URL for browser-facing assets (default: /)").option("--no-serve-static", "Disable serving static files from frontend/").option("--test-mode", "Enable test endpoints (/_jay/health, /_jay/shutdown)").option("-v, --verbose", "Enable verbose logging output").action(async (options) => {
|
|
5208
|
+
try {
|
|
5209
|
+
await runServe(options.path, options);
|
|
4646
5210
|
} catch (error) {
|
|
4647
5211
|
getLogger().error(chalk.red("Server failed:") + " " + error.message);
|
|
4648
5212
|
if (error.stack)
|
|
@@ -4650,17 +5214,31 @@ program.command("serve [path]").description("Start production server").option("-
|
|
|
4650
5214
|
process.exit(1);
|
|
4651
5215
|
}
|
|
4652
5216
|
});
|
|
4653
|
-
program.command("
|
|
5217
|
+
program.command("rebuild").description("Rebuild instances by contract, route, or URL").option("--contract <name>", "Rebuild by contract name (e.g., product-page)").option("--route <pattern>", "Rebuild by route pattern (e.g., /products/[slug])").option("--url <url>", "Rebuild by URL (e.g., /products/blue-widget)").option("--params <json>", `JSON params to rebuild specific instance (e.g., '{"slug":"x"}')`).option("--version <n>", "Build version (default: from package.json)").option("-p, --path <path>", "Project root (default: cwd)").option("-v, --verbose", "Enable verbose logging output").action(async (options) => {
|
|
4654
5218
|
try {
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
5219
|
+
await runRebuild(options.path, options);
|
|
5220
|
+
} catch (error) {
|
|
5221
|
+
getLogger().error(chalk.red("Rebuild failed:") + " " + error.message);
|
|
5222
|
+
if (error.stack)
|
|
5223
|
+
getLogger().error(error.stack);
|
|
5224
|
+
process.exit(1);
|
|
5225
|
+
}
|
|
5226
|
+
});
|
|
5227
|
+
program.command("cleanup").description("Delete orphaned files from previous rebuilds").option("--version <n>", "Build version (default: from package.json)").option("-p, --path <path>", "Project root (default: cwd)").action(async (options) => {
|
|
5228
|
+
try {
|
|
5229
|
+
const { initLogger: initLogger2, resolveProductionContext: resolveProductionContext2 } = await Promise.resolve().then(() => runProduction);
|
|
5230
|
+
initLogger2();
|
|
5231
|
+
const ctx = await resolveProductionContext2(options.path, options.version);
|
|
5232
|
+
const { cleanupOrphanedFiles } = await import("@jay-framework/production-server");
|
|
5233
|
+
await cleanupOrphanedFiles(ctx.buildRoot, ctx.version);
|
|
5234
|
+
} catch (error) {
|
|
5235
|
+
getLogger().error(chalk.red("Cleanup failed:") + " " + error.message);
|
|
5236
|
+
process.exit(1);
|
|
5237
|
+
}
|
|
5238
|
+
});
|
|
5239
|
+
program.command("validate").description("Validate all .jay-html and .jay-contract files").option("-p, --path <path>", "Scan root (default: cwd)").option("-v, --verbose", "Show per-file validation status").option("--json", "Output results as JSON").action(async (options) => {
|
|
5240
|
+
try {
|
|
5241
|
+
await runValidate(options.path, options);
|
|
4664
5242
|
} catch (error) {
|
|
4665
5243
|
if (options.json) {
|
|
4666
5244
|
getLogger().important(
|
|
@@ -4672,342 +5250,40 @@ program.command("validate [path]").description("Validate all .jay-html and .jay-
|
|
|
4672
5250
|
process.exit(1);
|
|
4673
5251
|
}
|
|
4674
5252
|
});
|
|
4675
|
-
program.command("validate-plugin
|
|
5253
|
+
program.command("validate-plugin").description("Validate a Jay Stack plugin package").option("-p, --path <path>", "Plugin root (default: cwd)").option("--local", "Validate local plugins in src/plugins/").option("-v, --verbose", "Show detailed validation output").option("--strict", "Treat warnings as errors (for CI)").option("--generate-types", "Generate .d.ts files for contracts").action(async (options) => {
|
|
4676
5254
|
try {
|
|
4677
|
-
|
|
4678
|
-
pluginPath: pluginPath || process.cwd(),
|
|
4679
|
-
local: options.local,
|
|
4680
|
-
verbose: options.verbose,
|
|
4681
|
-
strict: options.strict,
|
|
4682
|
-
generateTypes: options.generateTypes
|
|
4683
|
-
});
|
|
4684
|
-
printValidationResult(result, options.verbose);
|
|
4685
|
-
if (!result.valid || options.strict && result.warnings.length > 0) {
|
|
4686
|
-
process.exit(1);
|
|
4687
|
-
}
|
|
5255
|
+
await runValidatePlugin(options.path, options);
|
|
4688
5256
|
} catch (error) {
|
|
4689
5257
|
getLogger().error(chalk.red("Validation error:") + " " + error.message);
|
|
4690
5258
|
process.exit(1);
|
|
4691
5259
|
}
|
|
4692
5260
|
});
|
|
4693
|
-
|
|
4694
|
-
async function ensureAgentKitDocs(projectRoot, _force, mode) {
|
|
4695
|
-
const agentKitDir = path$1.join(projectRoot, "agent-kit");
|
|
4696
|
-
const thisDir = path$1.dirname(fileURLToPath(import.meta.url));
|
|
4697
|
-
const templateDir = path$1.resolve(thisDir, "..", "agent-kit-template");
|
|
4698
|
-
const roles = mode && ALL_ROLES.includes(mode) ? [mode] : ALL_ROLES;
|
|
4699
|
-
for (const role of roles) {
|
|
4700
|
-
const roleTemplateDir = path$1.join(templateDir, role);
|
|
4701
|
-
const roleOutputDir = path$1.join(agentKitDir, role);
|
|
4702
|
-
let files;
|
|
4703
|
-
try {
|
|
4704
|
-
files = (await fs$1.readdir(roleTemplateDir)).filter((f) => f.endsWith(".md"));
|
|
4705
|
-
} catch {
|
|
4706
|
-
continue;
|
|
4707
|
-
}
|
|
4708
|
-
await fs$1.mkdir(roleOutputDir, { recursive: true });
|
|
4709
|
-
for (const filename of files) {
|
|
4710
|
-
await fs$1.copyFile(
|
|
4711
|
-
path$1.join(roleTemplateDir, filename),
|
|
4712
|
-
path$1.join(roleOutputDir, filename)
|
|
4713
|
-
);
|
|
4714
|
-
getLogger().info(chalk.gray(` Created agent-kit/${role}/${filename}`));
|
|
4715
|
-
}
|
|
4716
|
-
}
|
|
4717
|
-
}
|
|
4718
|
-
async function mergePluginAgentKitGuides(projectRoot, mode) {
|
|
4719
|
-
const plugins = await scanPlugins$1({ projectRoot });
|
|
4720
|
-
const agentKitDir = path$1.join(projectRoot, "agent-kit");
|
|
4721
|
-
const roles = mode && ALL_ROLES.includes(mode) ? [mode] : ALL_ROLES;
|
|
4722
|
-
const copiedPerRole = /* @__PURE__ */ new Map();
|
|
4723
|
-
for (const [, plugin] of plugins) {
|
|
4724
|
-
const pluginAgentKitDir = path$1.join(plugin.pluginPath, "agent-kit");
|
|
4725
|
-
if (!fsSync.existsSync(pluginAgentKitDir))
|
|
4726
|
-
continue;
|
|
4727
|
-
for (const role of roles) {
|
|
4728
|
-
const roleSourceDir = path$1.join(pluginAgentKitDir, role);
|
|
4729
|
-
let files;
|
|
4730
|
-
try {
|
|
4731
|
-
files = (await fs$1.readdir(roleSourceDir)).filter(
|
|
4732
|
-
(f) => f.endsWith(".md") && f !== "INSTRUCTIONS.md"
|
|
4733
|
-
);
|
|
4734
|
-
} catch {
|
|
4735
|
-
continue;
|
|
4736
|
-
}
|
|
4737
|
-
if (files.length === 0)
|
|
4738
|
-
continue;
|
|
4739
|
-
const roleOutputDir = path$1.join(agentKitDir, role);
|
|
4740
|
-
await fs$1.mkdir(roleOutputDir, { recursive: true });
|
|
4741
|
-
for (const filename of files) {
|
|
4742
|
-
const sourcePath = path$1.join(roleSourceDir, filename);
|
|
4743
|
-
await fs$1.copyFile(sourcePath, path$1.join(roleOutputDir, filename));
|
|
4744
|
-
let description = "";
|
|
4745
|
-
try {
|
|
4746
|
-
const content = await fs$1.readFile(sourcePath, "utf-8");
|
|
4747
|
-
const lines = content.split("\n");
|
|
4748
|
-
let pastHeading = false;
|
|
4749
|
-
for (const line of lines) {
|
|
4750
|
-
if (line.startsWith("# ")) {
|
|
4751
|
-
pastHeading = true;
|
|
4752
|
-
continue;
|
|
4753
|
-
}
|
|
4754
|
-
if (pastHeading && line.trim()) {
|
|
4755
|
-
description = line.trim();
|
|
4756
|
-
break;
|
|
4757
|
-
}
|
|
4758
|
-
}
|
|
4759
|
-
} catch {
|
|
4760
|
-
}
|
|
4761
|
-
if (!copiedPerRole.has(role))
|
|
4762
|
-
copiedPerRole.set(role, []);
|
|
4763
|
-
copiedPerRole.get(role).push({ filename, pluginName: plugin.name, description });
|
|
4764
|
-
getLogger().info(
|
|
4765
|
-
chalk.gray(
|
|
4766
|
-
` Copied agent-kit/${role}/${filename} from plugin "${plugin.name}"`
|
|
4767
|
-
)
|
|
4768
|
-
);
|
|
4769
|
-
}
|
|
4770
|
-
}
|
|
4771
|
-
}
|
|
4772
|
-
for (const [role, entries] of copiedPerRole) {
|
|
4773
|
-
const instructionsPath = path$1.join(agentKitDir, role, "INSTRUCTIONS.md");
|
|
4774
|
-
if (!fsSync.existsSync(instructionsPath))
|
|
4775
|
-
continue;
|
|
4776
|
-
const lines = [
|
|
4777
|
-
"",
|
|
4778
|
-
"## Plugin-Contributed Guides",
|
|
4779
|
-
"",
|
|
4780
|
-
"| File | Plugin | Description |",
|
|
4781
|
-
"| --- | --- | --- |"
|
|
4782
|
-
];
|
|
4783
|
-
for (const { filename, pluginName, description } of entries) {
|
|
4784
|
-
lines.push(`| [${filename}](${filename}) | ${pluginName} | ${description} |`);
|
|
4785
|
-
}
|
|
4786
|
-
lines.push("");
|
|
4787
|
-
await fs$1.appendFile(instructionsPath, lines.join("\n"));
|
|
4788
|
-
}
|
|
4789
|
-
}
|
|
4790
|
-
async function generatePluginReferences(projectRoot, options, initErrors, viteServer) {
|
|
4791
|
-
const { discoverPluginsWithReferences, executePluginReferences } = await import("@jay-framework/stack-server-runtime");
|
|
4792
|
-
const plugins = await discoverPluginsWithReferences({
|
|
4793
|
-
projectRoot,
|
|
4794
|
-
verbose: options.verbose,
|
|
4795
|
-
pluginFilter: options.plugin
|
|
4796
|
-
});
|
|
4797
|
-
if (plugins.length === 0)
|
|
4798
|
-
return;
|
|
4799
|
-
const logger = getLogger();
|
|
4800
|
-
logger.important("");
|
|
4801
|
-
logger.important(chalk.bold("📚 Generating plugin references..."));
|
|
4802
|
-
for (const plugin of plugins) {
|
|
4803
|
-
const pluginInitError = initErrors.get(plugin.name);
|
|
4804
|
-
if (pluginInitError) {
|
|
4805
|
-
logger.warn(
|
|
4806
|
-
chalk.yellow(
|
|
4807
|
-
` ⚠️ ${plugin.name}: references skipped — init failed: ${pluginInitError.message}`
|
|
4808
|
-
)
|
|
4809
|
-
);
|
|
4810
|
-
continue;
|
|
4811
|
-
}
|
|
4812
|
-
try {
|
|
4813
|
-
const result = await executePluginReferences(plugin, {
|
|
4814
|
-
projectRoot,
|
|
4815
|
-
force: options.force ?? false,
|
|
4816
|
-
viteServer,
|
|
4817
|
-
verbose: options.verbose
|
|
4818
|
-
});
|
|
4819
|
-
if (result.referencesCreated.length > 0) {
|
|
4820
|
-
logger.important(chalk.green(` ✅ ${plugin.name}:`));
|
|
4821
|
-
for (const ref of result.referencesCreated) {
|
|
4822
|
-
logger.important(chalk.gray(` ${ref}`));
|
|
4823
|
-
}
|
|
4824
|
-
if (result.message) {
|
|
4825
|
-
logger.important(chalk.gray(` ${result.message}`));
|
|
4826
|
-
}
|
|
4827
|
-
}
|
|
4828
|
-
} catch (error) {
|
|
4829
|
-
logger.warn(
|
|
4830
|
-
chalk.yellow(` ⚠️ ${plugin.name}: references skipped — ${error.message}`)
|
|
4831
|
-
);
|
|
4832
|
-
}
|
|
4833
|
-
}
|
|
4834
|
-
}
|
|
4835
|
-
async function runMaterialize(projectRoot, options, defaultOutputRelative, keepViteAlive = false) {
|
|
4836
|
-
const path2 = await import("node:path");
|
|
4837
|
-
const outputDir = options.output ?? path2.join(projectRoot, defaultOutputRelative);
|
|
4838
|
-
let viteServer;
|
|
4839
|
-
let initErrors = /* @__PURE__ */ new Map();
|
|
4840
|
-
try {
|
|
4841
|
-
if (options.list) {
|
|
4842
|
-
const index = await listContracts({
|
|
4843
|
-
projectRoot,
|
|
4844
|
-
dynamicOnly: options.dynamicOnly,
|
|
4845
|
-
pluginFilter: options.plugin
|
|
4846
|
-
});
|
|
4847
|
-
if (options.yaml) {
|
|
4848
|
-
getLogger().important(YAML.stringify(index));
|
|
4849
|
-
} else {
|
|
4850
|
-
printContractList(index);
|
|
4851
|
-
}
|
|
4852
|
-
return { initErrors };
|
|
4853
|
-
}
|
|
4854
|
-
if (options.verbose) {
|
|
4855
|
-
getLogger().info("Starting Vite for TypeScript support...");
|
|
4856
|
-
}
|
|
4857
|
-
viteServer = await createViteForCli({ projectRoot });
|
|
4858
|
-
const { services, initErrors: errors } = await initializeServicesForCli(
|
|
4859
|
-
projectRoot,
|
|
4860
|
-
viteServer
|
|
4861
|
-
);
|
|
4862
|
-
initErrors = errors;
|
|
4863
|
-
const result = await materializeContracts(
|
|
4864
|
-
{
|
|
4865
|
-
projectRoot,
|
|
4866
|
-
outputDir,
|
|
4867
|
-
force: options.force,
|
|
4868
|
-
dynamicOnly: options.dynamicOnly,
|
|
4869
|
-
pluginFilter: options.plugin,
|
|
4870
|
-
verbose: options.verbose,
|
|
4871
|
-
viteServer
|
|
4872
|
-
},
|
|
4873
|
-
services
|
|
4874
|
-
);
|
|
4875
|
-
if (options.yaml) {
|
|
4876
|
-
getLogger().important(YAML.stringify(result.pluginsIndex));
|
|
4877
|
-
} else {
|
|
4878
|
-
const totalContracts = result.pluginsIndex.plugins.reduce(
|
|
4879
|
-
(sum, p) => sum + p.contracts.length,
|
|
4880
|
-
0
|
|
4881
|
-
);
|
|
4882
|
-
getLogger().important(chalk.green(`
|
|
4883
|
-
✅ Materialized ${totalContracts} contracts`));
|
|
4884
|
-
getLogger().important(` Static: ${result.staticCount}`);
|
|
4885
|
-
getLogger().important(` Dynamic: ${result.dynamicCount}`);
|
|
4886
|
-
getLogger().important(` Output: ${result.outputDir}`);
|
|
4887
|
-
}
|
|
4888
|
-
return { initErrors, viteServer: keepViteAlive ? viteServer : void 0 };
|
|
4889
|
-
} catch (error) {
|
|
4890
|
-
getLogger().error(chalk.red("❌ Failed to materialize contracts:") + " " + error.message);
|
|
4891
|
-
if (options.verbose) {
|
|
4892
|
-
getLogger().error(error.stack);
|
|
4893
|
-
}
|
|
4894
|
-
process.exit(1);
|
|
4895
|
-
} finally {
|
|
4896
|
-
if (viteServer && !keepViteAlive) {
|
|
4897
|
-
await viteServer.close();
|
|
4898
|
-
}
|
|
4899
|
-
}
|
|
4900
|
-
return { initErrors };
|
|
4901
|
-
}
|
|
4902
|
-
program.command("setup [plugin]").description(
|
|
4903
|
-
"Run plugin setup: create config templates, validate credentials, generate reference data"
|
|
4904
|
-
).option("--force", "Force re-run (overwrite config templates and regenerate references)").option("-v, --verbose", "Show detailed output").action(async (plugin, options) => {
|
|
5261
|
+
program.command("setup [plugin]").description("Run plugin setup: config templates, credential validation, reference data").option("--force", "Force re-run (overwrite config templates and regenerate references)").option("-v, --verbose", "Show detailed output").action(async (plugin, options) => {
|
|
4905
5262
|
await runSetup(plugin, options, process.cwd(), initializeServicesForCli);
|
|
4906
5263
|
});
|
|
4907
|
-
program.command("agent-kit").description(
|
|
4908
|
-
"Prepare the agent kit: materialize contracts, generate references, and write docs to agent-kit/"
|
|
4909
|
-
).option("-o, --output <dir>", "Output directory (default: agent-kit/materialized-contracts)").option("--yaml", "Output contract index as YAML to stdout").option("--list", "List contracts without writing files").option("--plugin <name>", "Filter to specific plugin").option("--dynamic-only", "Only process dynamic contracts").option("--force", "Force re-materialization").option("--no-references", "Skip reference data generation").option(
|
|
5264
|
+
program.command("agent-kit").description("Prepare agent kit: materialize contracts, generate references, write docs").option("-o, --output <dir>", "Output directory (default: agent-kit/materialized-contracts)").option("--yaml", "Output contract index as YAML to stdout").option("--list", "List contracts without writing files").option("--plugin <name>", "Filter to specific plugin").option("--dynamic-only", "Only process dynamic contracts").option("--force", "Force re-materialization").option("--no-references", "Skip reference data generation").option(
|
|
4910
5265
|
"-m, --mode <role>",
|
|
4911
5266
|
"Generate guides for a specific role: designer, developer, or plugin (default: all)"
|
|
4912
5267
|
).option("-v, --verbose", "Show detailed output").action(async (options) => {
|
|
4913
|
-
|
|
4914
|
-
const { initErrors, viteServer } = await runMaterialize(
|
|
4915
|
-
projectRoot,
|
|
4916
|
-
options,
|
|
4917
|
-
"agent-kit/materialized-contracts",
|
|
4918
|
-
/* keepViteAlive */
|
|
4919
|
-
true
|
|
4920
|
-
);
|
|
4921
|
-
try {
|
|
4922
|
-
if (!options.list) {
|
|
4923
|
-
await ensureAgentKitDocs(projectRoot, options.force, options.mode);
|
|
4924
|
-
await mergePluginAgentKitGuides(projectRoot, options.mode);
|
|
4925
|
-
if (options.references !== false) {
|
|
4926
|
-
await generatePluginReferences(projectRoot, options, initErrors, viteServer);
|
|
4927
|
-
}
|
|
4928
|
-
}
|
|
4929
|
-
} finally {
|
|
4930
|
-
if (viteServer) {
|
|
4931
|
-
await viteServer.close();
|
|
4932
|
-
}
|
|
4933
|
-
}
|
|
5268
|
+
await runAgentKit(options);
|
|
4934
5269
|
});
|
|
4935
|
-
program.command("action <plugin/action>").description(
|
|
4936
|
-
`Run a plugin action (e.g., jay-stack action wix-stores/searchProducts --input '{"query":""}')`
|
|
4937
|
-
).option("--input <json>", "JSON input for the action (default: {})").option("--yaml", "Output result as YAML instead of JSON").option("-v, --verbose", "Show detailed output").action(async (actionRef, options) => {
|
|
5270
|
+
program.command("action <plugin/action>").description("Run a plugin action (e.g., jay-stack action wix-stores/searchProducts)").option("--input <json>", "JSON input for the action (default: {})").option("--yaml", "Output result as YAML instead of JSON").option("-v, --verbose", "Show detailed output").action(async (actionRef, options) => {
|
|
4938
5271
|
await runAction(actionRef, options, process.cwd(), initializeServicesForCli);
|
|
4939
5272
|
});
|
|
4940
|
-
program.command("
|
|
4941
|
-
|
|
4942
|
-
|
|
5273
|
+
program.command("run [plugin/command]").description("Run a plugin CLI command (e.g., jay-stack run media/upload-public)").option("--list", "List all available plugin commands").option("-v, --verbose", "Show detailed output").allowUnknownOption().allowExcessArguments().action(async (commandRef, options, command) => {
|
|
5274
|
+
const rawArgs = command.parent?.rawArgs.slice(3) ?? [];
|
|
5275
|
+
const extraArgs = rawArgs.filter(
|
|
5276
|
+
(a) => a !== commandRef && a !== "-v" && a !== "--verbose" && a !== "--list"
|
|
5277
|
+
);
|
|
5278
|
+
await runCommand(commandRef, extraArgs, options, process.cwd(), initializeServicesForCli);
|
|
5279
|
+
});
|
|
5280
|
+
program.command("params <plugin/contract>").description("Discover load param values for a contract (NDJSON or YAML)").option("--yaml", "Output as YAML instead of NDJSON").option("-v, --verbose", "Show detailed output").action(async (contractRef, options) => {
|
|
4943
5281
|
await runParams(contractRef, options, process.cwd(), initializeServicesForCli);
|
|
4944
5282
|
});
|
|
4945
5283
|
program.parse(process.argv);
|
|
4946
5284
|
if (!process.argv.slice(2).length) {
|
|
4947
5285
|
program.outputHelp();
|
|
4948
5286
|
}
|
|
4949
|
-
function printValidationResult(result, verbose) {
|
|
4950
|
-
const logger = getLogger();
|
|
4951
|
-
if (result.valid && result.warnings.length === 0) {
|
|
4952
|
-
logger.important(chalk.green("✅ Plugin validation successful!\n"));
|
|
4953
|
-
if (verbose) {
|
|
4954
|
-
logger.important("Plugin: " + result.pluginName);
|
|
4955
|
-
logger.important(" ✅ plugin.yaml valid");
|
|
4956
|
-
logger.important(` ✅ ${result.contractsChecked} contracts validated`);
|
|
4957
|
-
if (result.typesGenerated) {
|
|
4958
|
-
logger.important(` ✅ ${result.typesGenerated} type definitions generated`);
|
|
4959
|
-
}
|
|
4960
|
-
logger.important(` ✅ ${result.componentsChecked} components validated`);
|
|
4961
|
-
if (result.packageJsonChecked) {
|
|
4962
|
-
logger.important(" ✅ package.json valid");
|
|
4963
|
-
}
|
|
4964
|
-
logger.important("\nNo errors found.");
|
|
4965
|
-
}
|
|
4966
|
-
} else if (result.valid && result.warnings.length > 0) {
|
|
4967
|
-
logger.important(chalk.yellow("⚠️ Plugin validation passed with warnings\n"));
|
|
4968
|
-
logger.important("Warnings:");
|
|
4969
|
-
result.warnings.forEach((warning) => {
|
|
4970
|
-
logger.important(chalk.yellow(` ⚠️ ${warning.message}`));
|
|
4971
|
-
if (warning.location) {
|
|
4972
|
-
logger.important(chalk.gray(` Location: ${warning.location}`));
|
|
4973
|
-
}
|
|
4974
|
-
if (warning.suggestion) {
|
|
4975
|
-
logger.important(chalk.gray(` → ${warning.suggestion}`));
|
|
4976
|
-
}
|
|
4977
|
-
logger.important("");
|
|
4978
|
-
});
|
|
4979
|
-
logger.important(chalk.gray("Use --strict to treat warnings as errors."));
|
|
4980
|
-
} else {
|
|
4981
|
-
logger.important(chalk.red("❌ Plugin validation failed\n"));
|
|
4982
|
-
logger.important("Errors:");
|
|
4983
|
-
result.errors.forEach((error) => {
|
|
4984
|
-
logger.important(chalk.red(` ❌ ${error.message}`));
|
|
4985
|
-
if (error.location) {
|
|
4986
|
-
logger.important(chalk.gray(` Location: ${error.location}`));
|
|
4987
|
-
}
|
|
4988
|
-
if (error.suggestion) {
|
|
4989
|
-
logger.important(chalk.gray(` → ${error.suggestion}`));
|
|
4990
|
-
}
|
|
4991
|
-
logger.important("");
|
|
4992
|
-
});
|
|
4993
|
-
logger.important(chalk.red(`${result.errors.length} errors found.`));
|
|
4994
|
-
}
|
|
4995
|
-
}
|
|
4996
|
-
function printContractList(index) {
|
|
4997
|
-
const logger = getLogger();
|
|
4998
|
-
logger.important("\nAvailable Contracts:\n");
|
|
4999
|
-
for (const plugin of index.plugins) {
|
|
5000
|
-
logger.important(chalk.bold(`📦 ${plugin.name}`));
|
|
5001
|
-
for (const contract of plugin.contracts) {
|
|
5002
|
-
const typeIcon = contract.type === "static" ? "📄" : "⚡";
|
|
5003
|
-
logger.important(` ${typeIcon} ${contract.name}`);
|
|
5004
|
-
}
|
|
5005
|
-
logger.important("");
|
|
5006
|
-
}
|
|
5007
|
-
if (index.plugins.length === 0) {
|
|
5008
|
-
logger.important(chalk.gray("No contracts found."));
|
|
5009
|
-
}
|
|
5010
|
-
}
|
|
5011
5287
|
export {
|
|
5012
5288
|
createEditorHandlers,
|
|
5013
5289
|
getConfigWithDefaults,
|