@lunora/cli 1.0.0-alpha.48 → 1.0.0-alpha.480
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/LICENSE.md +33 -0
- package/README.md +3 -1
- package/dist/bin.mjs +3 -10
- package/dist/cli.d.mts +31 -0
- package/dist/cli.d.ts +31 -0
- package/dist/cli.mjs +1 -0
- package/dist/index.d.mts +1168 -416
- package/dist/index.d.ts +1168 -416
- package/dist/index.mjs +1 -19
- package/dist/packem_chunks/cli.mjs +2 -0
- package/dist/packem_chunks/dispatch.mjs +1 -0
- package/dist/packem_chunks/handler.mjs +61 -157
- package/dist/packem_chunks/handler10.mjs +2 -16
- package/dist/packem_chunks/handler11.mjs +1 -22
- package/dist/packem_chunks/handler12.mjs +1 -192
- package/dist/packem_chunks/handler13.mjs +1 -131
- package/dist/packem_chunks/handler14.mjs +3 -65
- package/dist/packem_chunks/handler15.mjs +1 -58
- package/dist/packem_chunks/handler16.mjs +1 -80
- package/dist/packem_chunks/handler17.mjs +1 -43
- package/dist/packem_chunks/handler18.mjs +1 -105
- package/dist/packem_chunks/handler19.mjs +1 -170
- package/dist/packem_chunks/handler2.mjs +1 -114
- package/dist/packem_chunks/handler20.mjs +1 -94
- package/dist/packem_chunks/handler21.mjs +7 -94
- package/dist/packem_chunks/handler22.mjs +1 -0
- package/dist/packem_chunks/handler23.mjs +3 -0
- package/dist/packem_chunks/handler24.mjs +3 -0
- package/dist/packem_chunks/handler25.mjs +2 -0
- package/dist/packem_chunks/handler26.mjs +1 -0
- package/dist/packem_chunks/handler27.mjs +2 -0
- package/dist/packem_chunks/handler28.mjs +99 -0
- package/dist/packem_chunks/handler29.mjs +3 -0
- package/dist/packem_chunks/handler3.mjs +1 -204
- package/dist/packem_chunks/handler30.mjs +15 -0
- package/dist/packem_chunks/handler31.mjs +1 -0
- package/dist/packem_chunks/handler32.mjs +1 -0
- package/dist/packem_chunks/handler4.mjs +1 -33
- package/dist/packem_chunks/handler5.mjs +1 -49
- package/dist/packem_chunks/handler6.mjs +3 -91
- package/dist/packem_chunks/handler7.mjs +1 -42
- package/dist/packem_chunks/handler8.mjs +1 -174
- package/dist/packem_chunks/handler9.mjs +1 -315
- package/dist/packem_chunks/runCodegenCommand.mjs +4 -52
- package/dist/packem_chunks/runDevCommand.mjs +8 -0
- package/dist/packem_chunks/runInitCommand.mjs +423 -1447
- package/dist/packem_chunks/runResetCommand.mjs +1 -41
- package/dist/packem_chunks/runRpcCommand.mjs +1 -68
- package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck9tABfr.mjs +1 -0
- package/dist/packem_shared/EXIT_CODE-DQVhSE-1.mjs +1 -0
- package/dist/packem_shared/admin-token-VdUnvnKW.mjs +1 -0
- package/dist/packem_shared/admin-url-DJB8P6Jh.mjs +1 -0
- package/dist/packem_shared/api-spec-lYyq4vL6.mjs +1 -0
- package/dist/packem_shared/binding-manifest-file-CQ1eQYy1.mjs +2 -0
- package/dist/packem_shared/buildRegistryIndex-Dc8D8AR6.mjs +1 -0
- package/dist/packem_shared/cap-error-body-YBKO32BF.mjs +1 -0
- package/dist/packem_shared/catalog-CahzmDLV.mjs +1 -0
- package/dist/packem_shared/cli-manifest-DoQ_3bzs.mjs +1 -0
- package/dist/packem_shared/cloudflare-credentials-BVmZnDZk.mjs +1 -0
- package/dist/packem_shared/codegen-error-AmH54ofi.mjs +3 -0
- package/dist/packem_shared/command-BpMv2n0o.mjs +1 -0
- package/dist/packem_shared/commands-CkuCMUP_.mjs +13 -0
- package/dist/packem_shared/createLogger-4TujevyB.mjs +2 -0
- package/dist/packem_shared/createRecordingSpawner-DchLi0gR.mjs +1 -0
- package/dist/packem_shared/deploy-target-resolve-BTCW1Iv4.mjs +1 -0
- package/dist/packem_shared/diffSnapshots-Y1G8am6C.mjs +7 -0
- package/dist/packem_shared/docker-DpVxvYpL.mjs +1 -0
- package/dist/packem_shared/export-rows-EzdNDYpa.mjs +3 -0
- package/dist/packem_shared/free-port-DjbFhaaT.mjs +1 -0
- package/dist/packem_shared/health-probe-BLnoq_oC.mjs +13 -0
- package/dist/packem_shared/import-3Y59Ry9F.mjs +13 -0
- package/dist/packem_shared/index-oHZBGBwB.mjs +1 -0
- package/dist/packem_shared/insertSchemaExtension-CbTH3lCQ.mjs +10 -0
- package/dist/packem_shared/js-literal-FWLi94Lh.mjs +1 -0
- package/dist/packem_shared/lint-ignore-report-DKZagpqk.mjs +2 -0
- package/dist/packem_shared/mcp-config-file-GR1Y_CVw.mjs +2 -0
- package/dist/packem_shared/open-url-EnKy--w-.mjs +1 -0
- package/dist/packem_shared/output-format-DWe_tkTR.mjs +2 -0
- package/dist/packem_shared/parseManifest-CwPTKdtS.mjs +1 -0
- package/dist/packem_shared/path-containment-CgxYZggb.mjs +1 -0
- package/dist/packem_shared/plan-pog5AvMk.mjs +5 -0
- package/dist/packem_shared/planDevCommand-Bl6OrwXm.mjs +1 -0
- package/dist/packem_shared/platform-diagnostics-Cn2g6Jh-.mjs +4 -0
- package/dist/packem_shared/prompt-cancelled-BvsNxg_Q.mjs +1 -0
- package/dist/packem_shared/render-lunora-error-JsLelWwR.mjs +2 -0
- package/dist/packem_shared/resolve-Bdc9KEUv.mjs +5 -0
- package/dist/packem_shared/resolve-target-BRvw8Pf7.mjs +1 -0
- package/dist/packem_shared/runAddCommand-gThKW-ZB.mjs +1 -0
- package/dist/packem_shared/runDeployCommand-ByBuze9W.mjs +1 -0
- package/dist/packem_shared/runExportCommand-_PtkJJDT.mjs +5 -0
- package/dist/packem_shared/runMigrateGenerateCommand-CguLEIZp.mjs +11 -0
- package/dist/packem_shared/schemaIrToSnapshot-Ck7DSPdf.mjs +1 -0
- package/dist/packem_shared/shared-CV7ESvuj.mjs +2 -0
- package/dist/packem_shared/storage-3GOIFVZm.mjs +1 -0
- package/dist/packem_shared/tui-prompts-B3YwUhGw.mjs +4 -0
- package/dist/packem_shared/variables-CPYyJtsL.mjs +1 -0
- package/dist/packem_shared/vectorize-metadata-DK61NmVx.mjs +2 -0
- package/dist/packem_shared/wrangler-name-Dsk5K1f-.mjs +1 -0
- package/dist/packem_shared/wrangler-secrets-C9siMBwN.mjs +1 -0
- package/package.json +45 -19
- package/skills/README.md +36 -17
- package/skills/lunora/SKILL.md +158 -65
- package/skills/lunora-cloudflare-audit/SKILL.md +164 -0
- package/skills/lunora-create-package/SKILL.md +98 -84
- package/skills/lunora-deploy/SKILL.md +212 -102
- package/skills/lunora-functions/SKILL.md +367 -60
- package/skills/lunora-migration-helper/SKILL.md +194 -149
- package/skills/lunora-performance-audit/SKILL.md +137 -95
- package/skills/lunora-quickstart/SKILL.md +136 -136
- package/skills/lunora-realtime/SKILL.md +219 -97
- package/skills/lunora-setup-auth/SKILL.md +203 -101
- package/skills/lunora-setup-hyperdrive/SKILL.md +153 -110
- package/skills/lunora-setup-hyperdrive-global/SKILL.md +152 -94
- package/skills/lunora-setup-mail/SKILL.md +87 -113
- package/skills/lunora-setup-scheduler/SKILL.md +133 -97
- package/skills/lunora-setup-storage/SKILL.md +189 -95
- package/dist/packem_chunks/planDevCommand.mjs +0 -541
- package/dist/packem_chunks/runDeployCommand.mjs +0 -594
- package/dist/packem_chunks/runMigrateGenerateCommand.mjs +0 -397
- package/dist/packem_shared/COMMANDS-B0ftFD_3.mjs +0 -948
- package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs +0 -244
- package/dist/packem_shared/admin-url-4UzT-CI4.mjs +0 -19
- package/dist/packem_shared/api-spec-CtA6ilu4.mjs +0 -13
- package/dist/packem_shared/buildRegistryIndex-BcYe607_.mjs +0 -38
- package/dist/packem_shared/codegen-error-DJG-ghs_.mjs +0 -31
- package/dist/packem_shared/command-D3lB_4Az.mjs +0 -19
- package/dist/packem_shared/commands-B-gR09Z_.mjs +0 -845
- package/dist/packem_shared/createLogger-B40gPzQo.mjs +0 -78
- package/dist/packem_shared/createRecordingSpawner-DxI3mebw.mjs +0 -43
- package/dist/packem_shared/detect-package-manager-DYp7n3mJ.mjs +0 -61
- package/dist/packem_shared/diffSnapshots-BeDvvNiF.mjs +0 -161
- package/dist/packem_shared/docker-hMQ97KSQ.mjs +0 -21
- package/dist/packem_shared/insertSchemaExtension-DAqbfr9Z.mjs +0 -64
- package/dist/packem_shared/open-url-Dfq6fAyT.mjs +0 -41
- package/dist/packem_shared/output-format-wUvAN6AL.mjs +0 -17
- package/dist/packem_shared/parseArgs-YXFuKdEk.mjs +0 -56
- package/dist/packem_shared/parseManifest--vZf2FY1.mjs +0 -94
- package/dist/packem_shared/prompt-cancelled-APzX1Im-.mjs +0 -9
- package/dist/packem_shared/resolve-target-qbsJ_5sF.mjs +0 -16
- package/dist/packem_shared/runAddCommand-bnY6-HKb.mjs +0 -4
- package/dist/packem_shared/schema-drift-gate-BtBt0as0.mjs +0 -79
- package/dist/packem_shared/schemaIrToSnapshot-DdsljJT-.mjs +0 -43
- package/dist/packem_shared/storage-BIsph-Vk.mjs +0 -84
- package/dist/packem_shared/tui-prompts-BjEN8XgP.mjs +0 -658
- package/dist/packem_shared/wrangler-name-cy4yhm9j.mjs +0 -12
- package/dist/packem_shared/wrangler-secrets-P2_ZUR-k.mjs +0 -47
|
@@ -1,105 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import { AGENT_RULES_DIR, detectAgentRules, LUNORA_SKILL_NAMES } from '@lunora/config';
|
|
4
|
-
import { join, relative, dirname } from '@visulima/path';
|
|
5
|
-
import { d as defineHandler } from '../packem_shared/command-D3lB_4Az.mjs';
|
|
6
|
-
|
|
7
|
-
const resolveBundledSkillsDirectory = (startDirectory = dirname(fileURLToPath(import.meta.url))) => {
|
|
8
|
-
let directory = startDirectory;
|
|
9
|
-
for (let index = 0; index < 6; index += 1) {
|
|
10
|
-
const packageJson = join(directory, "package.json");
|
|
11
|
-
if (existsSync(packageJson)) {
|
|
12
|
-
try {
|
|
13
|
-
const parsed = JSON.parse(readFileSync(packageJson, "utf8"));
|
|
14
|
-
if (parsed.name === "@lunora/cli") {
|
|
15
|
-
const skills = join(directory, "skills");
|
|
16
|
-
return existsSync(skills) ? skills : void 0;
|
|
17
|
-
}
|
|
18
|
-
} catch {
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
const parent = dirname(directory);
|
|
22
|
-
if (parent === directory) {
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
directory = parent;
|
|
26
|
-
}
|
|
27
|
-
return void 0;
|
|
28
|
-
};
|
|
29
|
-
const listBundledSkills = (skillsDirectory) => readdirSync(skillsDirectory).filter((name) => {
|
|
30
|
-
const directory = join(skillsDirectory, name);
|
|
31
|
-
return statSync(directory).isDirectory() && existsSync(join(directory, "SKILL.md"));
|
|
32
|
-
});
|
|
33
|
-
const copySkill = (source, destination, overwrite) => {
|
|
34
|
-
mkdirSync(destination, { recursive: true });
|
|
35
|
-
let wrote = false;
|
|
36
|
-
for (const entry of readdirSync(source)) {
|
|
37
|
-
const from = join(source, entry);
|
|
38
|
-
const to = join(destination, entry);
|
|
39
|
-
if (statSync(from).isDirectory()) {
|
|
40
|
-
wrote = copySkill(from, to, overwrite) || wrote;
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (existsSync(to) && !overwrite) {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
writeFileSync(to, readFileSync(from));
|
|
47
|
-
wrote = true;
|
|
48
|
-
}
|
|
49
|
-
return wrote;
|
|
50
|
-
};
|
|
51
|
-
const runRulesInstall = (options) => {
|
|
52
|
-
const cwd = options.cwd ?? process.cwd();
|
|
53
|
-
const overwrite = options.overwrite === true;
|
|
54
|
-
const skillsDirectory = resolveBundledSkillsDirectory();
|
|
55
|
-
if (skillsDirectory === void 0) {
|
|
56
|
-
options.logger.error("rules: could not locate the bundled skills (is @lunora/cli installed correctly?).");
|
|
57
|
-
return { code: 1, installed: [], skipped: [] };
|
|
58
|
-
}
|
|
59
|
-
const installed = [];
|
|
60
|
-
const skipped = [];
|
|
61
|
-
for (const name of listBundledSkills(skillsDirectory)) {
|
|
62
|
-
const destination = join(cwd, AGENT_RULES_DIR, name);
|
|
63
|
-
const wrote = copySkill(join(skillsDirectory, name), destination, overwrite);
|
|
64
|
-
if (wrote) {
|
|
65
|
-
installed.push(name);
|
|
66
|
-
} else {
|
|
67
|
-
skipped.push(name);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const target = relative(cwd, join(cwd, AGENT_RULES_DIR)) || AGENT_RULES_DIR;
|
|
71
|
-
if (installed.length > 0) {
|
|
72
|
-
options.logger.success(`Installed ${String(installed.length)} Lunora skill(s) into ${target}/: ${installed.join(", ")}.`);
|
|
73
|
-
}
|
|
74
|
-
if (skipped.length > 0) {
|
|
75
|
-
options.logger.info(`Skipped ${String(skipped.length)} existing skill(s) (re-run with --overwrite to replace): ${skipped.join(", ")}.`);
|
|
76
|
-
}
|
|
77
|
-
options.logger.info("Your AI coding agent will pick these up automatically. Start with the `lunora` skill.");
|
|
78
|
-
return { code: 0, installed, skipped };
|
|
79
|
-
};
|
|
80
|
-
const runRulesCheck = (options) => {
|
|
81
|
-
const cwd = options.cwd ?? process.cwd();
|
|
82
|
-
const status = detectAgentRules(cwd);
|
|
83
|
-
if (status.installed) {
|
|
84
|
-
options.logger.success(`Lunora agent rules are installed (${String(status.present.length)}/${String(LUNORA_SKILL_NAMES.length)} skills).`);
|
|
85
|
-
if (status.missing.length > 0) {
|
|
86
|
-
options.logger.info(`Missing: ${status.missing.join(", ")}. Run \`lunora rules install\` to add them.`);
|
|
87
|
-
}
|
|
88
|
-
return { code: 0, installed: status.present, skipped: [] };
|
|
89
|
-
}
|
|
90
|
-
options.logger.warn("Lunora agent rules are not installed. Run `lunora rules install` so your AI agent knows how to use Lunora.");
|
|
91
|
-
return { code: options.strict === true ? 1 : 0, installed: status.present, skipped: [] };
|
|
92
|
-
};
|
|
93
|
-
const execute = defineHandler(({ argument, cwd, logger, options }) => {
|
|
94
|
-
const subcommand = argument[0] ?? "check";
|
|
95
|
-
if (subcommand === "install") {
|
|
96
|
-
return runRulesInstall({ cwd, logger, overwrite: options.overwrite === true });
|
|
97
|
-
}
|
|
98
|
-
if (subcommand === "check") {
|
|
99
|
-
return runRulesCheck({ cwd, logger, strict: options.strict === true });
|
|
100
|
-
}
|
|
101
|
-
logger.error("rules: unknown subcommand. Usage: lunora rules <install|check>");
|
|
102
|
-
return { code: 1 };
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
export { execute, resolveBundledSkillsDirectory, runRulesCheck, runRulesInstall };
|
|
1
|
+
import{existsSync as h}from"node:fs";import{join as p}from"node:path";import{runCodegen as g}from"@lunora/codegen";import{resolveLazyFunctions as u}from"@lunora/config";import{validateWranglerProject as v,wranglerCodegenInputs as y}from"@lunora/config/cloudflare";import{a as w,e as S,r as k}from"../packem_shared/platform-diagnostics-Cn2g6Jh-.mjs";import{p as j}from"../packem_shared/api-spec-lYyq4vL6.mjs";import{r as E}from"../packem_shared/codegen-error-AmH54ofi.mjs";import{d as A}from"../packem_shared/command-BpMv2n0o.mjs";import{r as D}from"../packem_shared/deploy-target-resolve-BTCW1Iv4.mjs";import{EXIT_CODE as R}from"../packem_shared/EXIT_CODE-DQVhSE-1.mjs";import{r as $,p as b}from"../packem_shared/health-probe-BLnoq_oC.mjs";import{defaultSpawner as F}from"../packem_shared/createRecordingSpawner-DchLi0gR.mjs";import{execArgsFor as U,detectPackageManager as x}from"@lunora/config/cli";const P=async(r,a,t)=>{if(!h(p(r,"tsconfig.json")))return{warning:"no tsconfig.json found — skipping TypeScript type-check"};const o=U(x(r),"tsc",["--noEmit","-p","tsconfig.json"]),e=await a({args:o.args,command:o.command,cwd:r,stdoutToStderr:t==="json"});return e.code===0?{}:{error:`type errors: tsc --noEmit exited ${String(e.code)}`}},T=async(r,a)=>{if(r.healthUrl===void 0||r.healthUrl==="")return;const t=await b({baseUrl:r.healthUrl,fetchImpl:r.healthFetch});if(t.error===void 0){a.success(`verify: health probe ok (${t.url})`);return}return t.error},z=(r,a)=>{const{errorAdvisories:t,names:o,shouldBlock:e}=S(r,k(a));if(e)return`${t.length.toString()} ERROR-level ${t.length===1?"advisory":"advisories"} (${o.join(", ")}). Pass --no-strict-advisories to downgrade this to a warning and continue.`},C=(r,a,t,o)=>{if(a.length===0&&t.length===0)return r.success("verify: project is valid"),{code:0,errors:[],warnings:[],wranglerPath:o};if(t.length>0){r.warn("verify: warnings:");for(const e of t)r.warn(` - ${e}`)}if(a.length>0){r.error("verify: errors:");for(const e of a){r.error(` - ${e}`);const s=E(e);s!==void 0&&r.error(s)}return{code:1,error:a[0],errors:a,warnings:t,wranglerPath:o}}return r.success("verify: project is valid (with warnings)"),{code:0,errors:[],warnings:t,wranglerPath:o}},H=async r=>{const a=r.cwd??process.cwd(),{logger:t}=r,o=v({environment:r.env,projectRoot:a}),e=[...o.report.errors],s=[...o.report.warnings];try{const n=D(a,r.target);if(n.target===void 0){const c=n.error??"unknown deploy target";return t.error(c),{code:R.USAGE,error:c,errors:[c],warnings:[],wranglerPath:void 0}}const i=g({apiSpec:r.apiSpec,lazyFunctions:u(r.lazyFunctions),dryRun:!0,projectRoot:a,target:n.target,...y(a)}),l=w(i.platformDiagnostics,t);e.push(...l.errors),s.push(...l.warnings);const f=z(i.advisories,r);f!==void 0&&e.push(f);const m=await $({allowDrift:r.allowSchemaDrift===!0,codegen:i,command:"verify",logger:t,readOnly:!0});m.blocked&&e.push(m.reason)}catch(n){const i=n instanceof Error?n.message:String(n);e.push(`codegen failed: ${i}`)}if(r.typecheck!==!1){const n=await P(a,r.spawner??F,r.format??"pretty");n.error!==void 0&&e.push(n.error),n.warning!==void 0&&s.push(n.warning)}const d=await T(r,t);return d!==void 0&&e.push(d),C(t,e,s,o.wranglerPath)},Q=A(async({cwd:r,format:a,logger:t,options:o})=>{const e=await H({allowSchemaDrift:o.allowSchemaDrift===!0,apiSpec:j(o.apiSpec),lazyFunctions:u(o.lazyFunctions),cwd:r,env:o.env,format:a,healthUrl:o.healthUrl,logger:t,strictAdvisories:o.strictAdvisories,target:o.target,typecheck:o.typecheck===!1?!1:void 0});return{code:e.code,data:{errors:e.errors,warnings:e.warnings,wranglerPath:e.wranglerPath},error:e.error}});export{Q as execute,H as runVerifyCommand};
|
|
@@ -1,170 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdtemp, writeFile, rm } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { discoverSchema, schemaFromIr } from '@lunora/codegen';
|
|
5
|
-
import { seedPlan } from '@lunora/seed';
|
|
6
|
-
import { join } from '@visulima/path';
|
|
7
|
-
import { Project } from 'ts-morph';
|
|
8
|
-
import { d as defineHandler } from '../packem_shared/command-D3lB_4Az.mjs';
|
|
9
|
-
import { a as resolveProductionWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
|
|
10
|
-
import { b as tuiConfirm } from '../packem_shared/tui-prompts-BjEN8XgP.mjs';
|
|
11
|
-
import { runImportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs';
|
|
12
|
-
import { runResetCommand } from './runResetCommand.mjs';
|
|
13
|
-
|
|
14
|
-
const isLocalUrl = (url) => {
|
|
15
|
-
if (url === void 0) {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
try {
|
|
19
|
-
const { hostname } = new URL(url);
|
|
20
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
|
|
21
|
-
} catch {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
const ndjsonReplacer = (_key, value) => {
|
|
26
|
-
if (typeof value === "bigint") {
|
|
27
|
-
return Number(value);
|
|
28
|
-
}
|
|
29
|
-
if (value instanceof ArrayBuffer) {
|
|
30
|
-
return [...new Uint8Array(value)];
|
|
31
|
-
}
|
|
32
|
-
return value;
|
|
33
|
-
};
|
|
34
|
-
const seedFailure = (code) => {
|
|
35
|
-
return { code, conflicts: 0, generated: 0, inserted: 0, ndjson: "" };
|
|
36
|
-
};
|
|
37
|
-
const guardSeedTargets = (options, schemaPath) => {
|
|
38
|
-
if (!existsSync(schemaPath)) {
|
|
39
|
-
options.logger.error(`schema not found: ${schemaPath} — run \`vis generate lunora-table --name=<name>\` to create one`);
|
|
40
|
-
return seedFailure(1);
|
|
41
|
-
}
|
|
42
|
-
if (options.reset === true && (options.prod === true || !isLocalUrl(options.url))) {
|
|
43
|
-
options.logger.error("--reset only clears local .wrangler/state and cannot be combined with --prod or a remote --url");
|
|
44
|
-
return seedFailure(1);
|
|
45
|
-
}
|
|
46
|
-
return void 0;
|
|
47
|
-
};
|
|
48
|
-
const insertSeedRows = async (ndjson, generated, cwd, options) => {
|
|
49
|
-
const scratchDirectory = await mkdtemp(join(tmpdir(), "lunora-seed-"));
|
|
50
|
-
const temporaryFile = join(scratchDirectory, "rows.ndjson");
|
|
51
|
-
await writeFile(temporaryFile, ndjson, "utf8");
|
|
52
|
-
try {
|
|
53
|
-
const result = await runImportCommand({
|
|
54
|
-
batchSize: options.batchSize,
|
|
55
|
-
fetchImpl: options.fetchImpl,
|
|
56
|
-
file: temporaryFile,
|
|
57
|
-
logger: options.logger,
|
|
58
|
-
prod: options.prod,
|
|
59
|
-
token: options.token,
|
|
60
|
-
url: options.url
|
|
61
|
-
});
|
|
62
|
-
const conflicts = result.body?.conflicts ?? 0;
|
|
63
|
-
if (conflicts > 0) {
|
|
64
|
-
options.logger.warn(
|
|
65
|
-
`${String(conflicts)} row(s) skipped — their _id already exists. Seeding is deterministic; re-run with --reset to wipe local state first, or a different --seed for fresh ids.`
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
return { code: result.code, conflicts, generated, inserted: result.inserted, ndjson };
|
|
69
|
-
} finally {
|
|
70
|
-
await rm(scratchDirectory, { force: true, recursive: true }).catch(() => {
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
const validateSeedTable = (options, ir) => {
|
|
75
|
-
if (options.table === void 0 || ir.tables.some((table) => table.name === options.table)) {
|
|
76
|
-
return void 0;
|
|
77
|
-
}
|
|
78
|
-
const available = ir.tables.map((table) => table.name).join(", ");
|
|
79
|
-
options.logger.error(`unknown table "${options.table}" — schema defines: ${available || "(no tables)"}`);
|
|
80
|
-
return seedFailure(1);
|
|
81
|
-
};
|
|
82
|
-
const confirmRemoteSeedTarget = async (options, generated) => {
|
|
83
|
-
const targetsRemote = options.prod === true || !isLocalUrl(options.url);
|
|
84
|
-
if (!targetsRemote || options.yes === true) {
|
|
85
|
-
return void 0;
|
|
86
|
-
}
|
|
87
|
-
if (!process.stdin.isTTY && options.confirm === void 0) {
|
|
88
|
-
options.logger.error("seed: refusing to insert into a non-local target without confirmation — re-run with --yes");
|
|
89
|
-
return seedFailure(1);
|
|
90
|
-
}
|
|
91
|
-
const confirmer = options.confirm ?? tuiConfirm;
|
|
92
|
-
const confirmed = await confirmer(`This will insert ${String(generated)} generated row(s) into ${options.url ?? "the production worker"}. Continue?`);
|
|
93
|
-
if (!confirmed) {
|
|
94
|
-
options.logger.info("seed: aborted");
|
|
95
|
-
return seedFailure(1);
|
|
96
|
-
}
|
|
97
|
-
return void 0;
|
|
98
|
-
};
|
|
99
|
-
const runSeedCommand = async (options) => {
|
|
100
|
-
const cwd = options.cwd ?? process.cwd();
|
|
101
|
-
const schemaPath = join(cwd, "lunora", "schema.ts");
|
|
102
|
-
const guard = guardSeedTargets(options, schemaPath);
|
|
103
|
-
if (guard !== void 0) {
|
|
104
|
-
return guard;
|
|
105
|
-
}
|
|
106
|
-
const project = new Project({ skipAddingFilesFromTsConfig: true });
|
|
107
|
-
const ir = discoverSchema(project, schemaPath);
|
|
108
|
-
const unknownTable = validateSeedTable(options, ir);
|
|
109
|
-
if (unknownTable !== void 0) {
|
|
110
|
-
return unknownTable;
|
|
111
|
-
}
|
|
112
|
-
const schema = schemaFromIr(ir);
|
|
113
|
-
const plan = seedPlan(schema, {
|
|
114
|
-
defaultCount: options.count ?? 10,
|
|
115
|
-
only: options.table === void 0 ? void 0 : [options.table],
|
|
116
|
-
seed: options.seed ?? 0
|
|
117
|
-
});
|
|
118
|
-
const lines = [];
|
|
119
|
-
for (const { rows, table } of plan) {
|
|
120
|
-
for (const row of rows) {
|
|
121
|
-
lines.push(JSON.stringify({ doc: row, table }, ndjsonReplacer));
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const ndjson = lines.length > 0 ? `${lines.join("\n")}
|
|
125
|
-
` : "";
|
|
126
|
-
const generated = lines.length;
|
|
127
|
-
if (options.dryRun === true) {
|
|
128
|
-
if (ndjson.length > 0) {
|
|
129
|
-
process.stdout.write(ndjson);
|
|
130
|
-
}
|
|
131
|
-
options.logger.info(`generated ${String(generated)} row(s) across ${String(plan.length)} table(s) — dry run, nothing inserted`);
|
|
132
|
-
return { code: 0, conflicts: 0, generated, inserted: 0, ndjson };
|
|
133
|
-
}
|
|
134
|
-
if (options.reset === true) {
|
|
135
|
-
const reset = await runResetCommand({ cwd, logger: options.logger, yes: true });
|
|
136
|
-
if (reset.code !== 0) {
|
|
137
|
-
return { code: reset.code, conflicts: 0, generated, inserted: 0, ndjson };
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (generated === 0) {
|
|
141
|
-
options.logger.warn("no rows generated — nothing to insert");
|
|
142
|
-
return { code: 0, conflicts: 0, generated: 0, inserted: 0, ndjson };
|
|
143
|
-
}
|
|
144
|
-
const aborted = await confirmRemoteSeedTarget(options, generated);
|
|
145
|
-
if (aborted !== void 0) {
|
|
146
|
-
return aborted;
|
|
147
|
-
}
|
|
148
|
-
return insertSeedRows(ndjson, generated, cwd, options);
|
|
149
|
-
};
|
|
150
|
-
const execute = defineHandler(async ({ cwd, logger, options }) => {
|
|
151
|
-
const result = await runSeedCommand({
|
|
152
|
-
batchSize: options.batchSize,
|
|
153
|
-
count: options.count,
|
|
154
|
-
cwd,
|
|
155
|
-
dryRun: options.dryRun === true,
|
|
156
|
-
logger,
|
|
157
|
-
prod: options.prod === true,
|
|
158
|
-
reset: options.reset === true,
|
|
159
|
-
seed: options.seed,
|
|
160
|
-
table: options.table,
|
|
161
|
-
token: options.token,
|
|
162
|
-
// Resolve the link here (only under --prod) so seed's own remote/confirm
|
|
163
|
-
// logic and the downstream import both see the same effective target.
|
|
164
|
-
url: resolveProductionWorkerUrl({ cwd, prod: options.prod === true, url: options.url }),
|
|
165
|
-
yes: options.yes === true
|
|
166
|
-
});
|
|
167
|
-
return { code: result.code };
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
export { execute, runSeedCommand };
|
|
1
|
+
import{readLiveDevServerState as c}from"@lunora/config";import{d as i}from"../packem_shared/command-BpMv2n0o.mjs";import{o as a}from"../packem_shared/open-url-EnKy--w-.mjs";const n="http://127.0.0.1:6173",d="/__lunora",u=/\/$/u,l=r=>{const e=c(r);return e===void 0?n:e.studioUrl!==void 0?e.studioUrl:e.mode==="vite"?`${e.url.replace(u,"")}${d}`:n},m=async r=>{const e=l(r.cwd??process.cwd()),{logger:t}=r;t.info(`opening ${e}`);try{await a(e,{opener:r.opener})}catch(o){const s=o instanceof Error?o.message:String(o);return t.error(`view: failed to open URL: ${s}`),{code:1,url:e}}return{code:0,url:e}},v=i(({cwd:r,logger:e})=>m({cwd:r,logger:e}));export{v as execute,m as runViewCommand};
|
|
@@ -1,114 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
3
|
-
import { join, relative } from 'node:path';
|
|
4
|
-
import { d as defineHandler } from '../packem_shared/command-D3lB_4Az.mjs';
|
|
5
|
-
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-DxI3mebw.mjs';
|
|
6
|
-
|
|
7
|
-
const walk = (root) => {
|
|
8
|
-
const entries = [];
|
|
9
|
-
const recurse = (directory) => {
|
|
10
|
-
for (const name of readdirSync(directory)) {
|
|
11
|
-
const full = join(directory, name);
|
|
12
|
-
const info = statSync(full);
|
|
13
|
-
if (info.isDirectory()) {
|
|
14
|
-
recurse(full);
|
|
15
|
-
} else if (info.isFile()) {
|
|
16
|
-
entries.push({ path: relative(root, full), sizeBytes: info.size });
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
recurse(root);
|
|
21
|
-
return entries;
|
|
22
|
-
};
|
|
23
|
-
const formatBytes = (bytes) => {
|
|
24
|
-
if (bytes < 1024) {
|
|
25
|
-
return `${String(bytes)} B`;
|
|
26
|
-
}
|
|
27
|
-
if (bytes < 1024 * 1024) {
|
|
28
|
-
return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
29
|
-
}
|
|
30
|
-
return `${(bytes / (1024 * 1024)).toFixed(2)} MiB`;
|
|
31
|
-
};
|
|
32
|
-
const buildReport = (outdir) => {
|
|
33
|
-
const all = walk(outdir);
|
|
34
|
-
const sorted = all.toSorted((a, b) => b.sizeBytes - a.sizeBytes);
|
|
35
|
-
const totalBytes = all.reduce((sum, entry) => sum + entry.sizeBytes, 0);
|
|
36
|
-
const generatedFiles = all.filter((entry) => entry.path.includes("_generated"));
|
|
37
|
-
return {
|
|
38
|
-
generatedFiles,
|
|
39
|
-
outdir,
|
|
40
|
-
topModules: sorted.slice(0, 10),
|
|
41
|
-
totalBytes,
|
|
42
|
-
totalFiles: all.length
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
const renderText = (report, logger) => {
|
|
46
|
-
logger.info(`outdir: ${report.outdir}`);
|
|
47
|
-
logger.info(`total: ${String(report.totalFiles)} files, ${formatBytes(report.totalBytes)}`);
|
|
48
|
-
if (report.topModules.length > 0) {
|
|
49
|
-
logger.info("");
|
|
50
|
-
logger.info("top modules by size:");
|
|
51
|
-
for (const entry of report.topModules) {
|
|
52
|
-
logger.info(` ${formatBytes(entry.sizeBytes).padStart(10, " ")} ${entry.path}`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (report.generatedFiles.length > 0) {
|
|
56
|
-
logger.info("");
|
|
57
|
-
logger.info(`_generated/ files: ${String(report.generatedFiles.length)}`);
|
|
58
|
-
for (const entry of report.generatedFiles) {
|
|
59
|
-
logger.info(` ${formatBytes(entry.sizeBytes).padStart(10, " ")} ${entry.path}`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const runAnalyzeCommand = async (options) => {
|
|
64
|
-
const cwd = options.cwd ?? process.cwd();
|
|
65
|
-
const { logger } = options;
|
|
66
|
-
let outdir;
|
|
67
|
-
let descriptor;
|
|
68
|
-
let temporary = false;
|
|
69
|
-
if (options.inspectOnly) {
|
|
70
|
-
outdir = options.inspectOnly;
|
|
71
|
-
} else {
|
|
72
|
-
outdir = mkdtempSync(join(tmpdir(), "lunora-analyze-"));
|
|
73
|
-
temporary = true;
|
|
74
|
-
descriptor = {
|
|
75
|
-
args: ["exec", "wrangler", "deploy", "--dry-run", "--outdir", outdir],
|
|
76
|
-
command: "pnpm",
|
|
77
|
-
cwd
|
|
78
|
-
};
|
|
79
|
-
logger.info(`analyze: building via ${descriptor.command} ${descriptor.args.join(" ")}`);
|
|
80
|
-
const spawner = options.spawner ?? defaultSpawner;
|
|
81
|
-
const spawned = await spawner(descriptor);
|
|
82
|
-
if (spawned.code !== 0) {
|
|
83
|
-
logger.error(`analyze: wrangler dry-run failed (exit ${String(spawned.code)})`);
|
|
84
|
-
rmSync(outdir, { force: true, recursive: true });
|
|
85
|
-
return { code: spawned.code, descriptor, report: void 0 };
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
try {
|
|
89
|
-
if (!existsSync(outdir)) {
|
|
90
|
-
logger.error(`analyze: outdir not found at ${outdir}`);
|
|
91
|
-
return { code: 1, descriptor, report: void 0 };
|
|
92
|
-
}
|
|
93
|
-
const report = buildReport(outdir);
|
|
94
|
-
if (options.json) {
|
|
95
|
-
process.stdout.write(`${JSON.stringify(report, void 0, 2)}
|
|
96
|
-
`);
|
|
97
|
-
} else {
|
|
98
|
-
renderText(report, logger);
|
|
99
|
-
}
|
|
100
|
-
return { code: 0, descriptor, report };
|
|
101
|
-
} finally {
|
|
102
|
-
if (temporary && existsSync(outdir)) {
|
|
103
|
-
try {
|
|
104
|
-
rmSync(outdir, { force: true, recursive: true });
|
|
105
|
-
} catch {
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
const execute = defineHandler(
|
|
111
|
-
({ cwd, logger, options }) => runAnalyzeCommand({ cwd, json: options.json === true, logger })
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
export { execute, runAnalyzeCommand };
|
|
1
|
+
import{existsSync as b}from"node:fs";import{readProjectDependencies as w,applyLintIgnores as A,detectLintTools as k}from"@lunora/config";import{findWranglerFile as I}from"@lunora/config/cloudflare";import{join as U,basename as h}from"@visulima/path";import{d as N}from"../packem_shared/command-BpMv2n0o.mjs";import{EXIT_CODE as o}from"../packem_shared/EXIT_CODE-DQVhSE-1.mjs";import{r as S}from"../packem_shared/lint-ignore-report-DKZagpqk.mjs";import{t as y,a as E}from"../packem_shared/tui-prompts-B3YwUhGw.mjs";import{i as _}from"../packem_shared/resolve-Bdc9KEUv.mjs";import{r as D}from"../packem_shared/commands-CkuCMUP_.mjs";import{n as L,i as M,A as P,E as R,s as O,d as f,p as $,r as v,M as j,a as C,b as g,c as F,D as m,e as x,f as H,g as d,h as z,j as B,w as G,k as W,l as V}from"../packem_shared/storage-3GOIFVZm.mjs";const p=e=>{const r=e.trim().toLowerCase();return B.find(a=>a.value===r||a.label.toLowerCase()===r||r==="auth0"&&a.value==="auth-auth0"||r==="clerk"&&a.value==="auth-clerk")?.value},q=async e=>{const r=e.cwd??process.cwd(),t=H(w(r));return t!==void 0?t:e.yes===!0?(e.logger.warn(`add: couldn't detect your framework — using "${d}". Pass a specific item (e.g. \`lunora add auth-ui-vue\`) to override.`),d):await(e.promptSelect??((c,n,i)=>y(c,n,i)))("Which framework is your app?",z,{default:d})??d},X=async e=>{if(e.provider!==void 0&&e.provider!==""){const t=p(e.provider);return t===void 0?(e.logger.warn(`add: unknown --provider "${e.provider}" — using "${m}" (email & password).`),m):t}if(e.yes===!0)return m;const r=e.promptSelect??((t,a,c)=>y(t,a,c));return x(r)},l=e=>e.promptText??((r,t)=>E(r,t)),J=async e=>{const r=h(e.cwd??process.cwd());if(e.bucket!==void 0&&e.bucket!==""){const t=O(e.bucket);if(t!==void 0)return t;const a=f(r);return e.logger.warn(`add: "${e.bucket}" isn't a valid R2 bucket name (lowercase alphanumeric + hyphens, 3–63 chars) — using "${a}".`),a}return e.yes===!0?f(r):$(l(e),r)},K=async e=>{const r=t=>{e.logger.warn(`add: ${t}`)};if(e.mailTo!==void 0&&e.mailTo!=="")return v(e.mailTo,r);if(e.yes!==!0)return v(await l(e)(j,{placeholder:"you@yourdomain.com"}),r)},Q=async e=>{const r=h(e.cwd??process.cwd());if(e.db!==void 0&&e.db!==""){const t=C(e.db);if(t!==void 0)return t;const a=g(r);return e.logger.warn(`add: "${e.db}" isn't a usable D1 database name — using "${a}".`),a}return e.yes===!0?g(r):F(l(e),r)},Y=async(e,r)=>e.kind==="auth"?[await X(r)]:e.kind==="auth-ui"?[await q(r)]:e.kind==="email"?[R]:[e.item],Z=(e,r)=>{S(A(e,k(e)),r)},ee=e=>!_(e)||e.yes===!0,re=async e=>{const r=e.cwd??process.cwd(),t=e.feature===void 0?void 0:L(e.feature);if(t===void 0)return e.logger.error("add requires a feature or registry item. Usage: lunora add <auth|email|storage|crons|presence|…>"),{code:o.USAGE,items:[]};if(!b(U(r,"lunora"))||I(r)===void 0)return e.logger.error("add: not a Lunora project here (need a lunora/ directory and a wrangler.jsonc). Run `lunora init` first."),{code:o.USAGE,items:[]};if(t.kind==="auth-ui"&&M(w(r)))return e.logger.error(`add: ${P}`),{code:o.USAGE,items:[]};const a=await Y(t,e),c=[];if(a.includes("storage")){const s=await J(e);c.push(u=>G(u,s))}if(a.includes("mail")){const s=await K(e);s!==void 0&&c.push(u=>W(u,s))}if(a.some(s=>s==="auth"||s.startsWith("auth-"))){const s=await Q(e);c.push(u=>V(u,s))}const n=c.length>0?s=>{let u=s;for(const T of c)u=T(u);return u}:void 0,i=await D({allowUnsafeSource:e.allowUnsafeSource,confirm:e.confirm,cwd:r,from:e.from,logger:e.logger,names:[...a],ref:e.ref,source:e.source,transformManifest:n,yes:ee(e)});return i.code===0&&Z(r,e.logger),{code:i.code,items:a}},fe=N(async({argument:e,cwd:r,logger:t,options:a})=>{const c=await re({allowUnsafeSource:a.allowUnsafeSource===!0,bucket:a.bucket,cwd:r,db:a.db,feature:e[0],from:a.from,logger:t,mailTo:a.mailTo,provider:a.provider,ref:a.ref,source:a.source,yes:a.yes===!0});return{code:c.code,data:{items:c.items},...c.error===void 0?{}:{error:c.error}}});export{fe as execute,re as runAddFeature};
|
|
@@ -1,94 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { runCodegen } from '@lunora/codegen';
|
|
4
|
-
import { p as parseApiSpec } from '../packem_shared/api-spec-CtA6ilu4.mjs';
|
|
5
|
-
import { a as renderCodegenHint } from '../packem_shared/codegen-error-DJG-ghs_.mjs';
|
|
6
|
-
import { d as defineHandler } from '../packem_shared/command-D3lB_4Az.mjs';
|
|
7
|
-
import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-wUvAN6AL.mjs';
|
|
8
|
-
import { r as runSchemaDriftGate } from '../packem_shared/schema-drift-gate-BtBt0as0.mjs';
|
|
9
|
-
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-DxI3mebw.mjs';
|
|
10
|
-
import { validateWranglerProject } from '@lunora/config';
|
|
11
|
-
|
|
12
|
-
const runTypecheckStep = async (cwd, spawner) => {
|
|
13
|
-
if (!existsSync(join(cwd, "tsconfig.json"))) {
|
|
14
|
-
return { warning: "no tsconfig.json found — skipping TypeScript type-check" };
|
|
15
|
-
}
|
|
16
|
-
const result = await spawner({ args: ["exec", "tsc", "--noEmit", "-p", "tsconfig.json"], command: "pnpm", cwd });
|
|
17
|
-
return result.code === 0 ? {} : { error: `type errors: tsc --noEmit exited ${String(result.code)}` };
|
|
18
|
-
};
|
|
19
|
-
const reportVerifyResult = (logger, errors, warnings, wranglerPath) => {
|
|
20
|
-
if (errors.length === 0 && warnings.length === 0) {
|
|
21
|
-
logger.success("verify: project is valid");
|
|
22
|
-
return { code: 0, errors: [], warnings: [], wranglerPath };
|
|
23
|
-
}
|
|
24
|
-
if (warnings.length > 0) {
|
|
25
|
-
logger.warn("verify: warnings:");
|
|
26
|
-
for (const warning of warnings) {
|
|
27
|
-
logger.warn(` - ${warning}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (errors.length > 0) {
|
|
31
|
-
logger.error("verify: errors:");
|
|
32
|
-
for (const error of errors) {
|
|
33
|
-
logger.error(` - ${error}`);
|
|
34
|
-
const hint = renderCodegenHint(error);
|
|
35
|
-
if (hint !== void 0) {
|
|
36
|
-
logger.error(hint);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return { code: 1, errors, warnings, wranglerPath };
|
|
40
|
-
}
|
|
41
|
-
logger.success("verify: project is valid (with warnings)");
|
|
42
|
-
return { code: 0, errors: [], warnings, wranglerPath };
|
|
43
|
-
};
|
|
44
|
-
const runVerifyCommand = async (options) => {
|
|
45
|
-
const cwd = options.cwd ?? process.cwd();
|
|
46
|
-
const logger = loggerForFormat(options.format, options.logger);
|
|
47
|
-
const formatError = validateOutputFormat("verify", options.format);
|
|
48
|
-
if (formatError !== void 0) {
|
|
49
|
-
options.logger.error(formatError);
|
|
50
|
-
return { code: 1, error: formatError, errors: [], warnings: [], wranglerPath: void 0 };
|
|
51
|
-
}
|
|
52
|
-
const validation = validateWranglerProject({ projectRoot: cwd });
|
|
53
|
-
const errors = [...validation.report.errors];
|
|
54
|
-
const warnings = [...validation.report.warnings];
|
|
55
|
-
try {
|
|
56
|
-
const codegen = runCodegen({ apiSpec: options.apiSpec, dryRun: true, projectRoot: cwd });
|
|
57
|
-
const gate = runSchemaDriftGate({ allowDrift: options.allowSchemaDrift === true, codegen, logger, readOnly: true });
|
|
58
|
-
if (gate.blocked) {
|
|
59
|
-
errors.push(gate.reason);
|
|
60
|
-
}
|
|
61
|
-
} catch (error) {
|
|
62
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
63
|
-
errors.push(`codegen failed: ${message}`);
|
|
64
|
-
}
|
|
65
|
-
if (options.typecheck !== false) {
|
|
66
|
-
const typecheck = await runTypecheckStep(cwd, options.spawner ?? defaultSpawner);
|
|
67
|
-
if (typecheck.error !== void 0) {
|
|
68
|
-
errors.push(typecheck.error);
|
|
69
|
-
}
|
|
70
|
-
if (typecheck.warning !== void 0) {
|
|
71
|
-
warnings.push(typecheck.warning);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const result = reportVerifyResult(logger, errors, warnings, validation.wranglerPath);
|
|
75
|
-
if (isJsonFormat(options.format)) {
|
|
76
|
-
printJson(result);
|
|
77
|
-
}
|
|
78
|
-
return result;
|
|
79
|
-
};
|
|
80
|
-
const execute = defineHandler(async ({ cwd, logger, options }) => {
|
|
81
|
-
const result = await runVerifyCommand({
|
|
82
|
-
allowSchemaDrift: options.allowSchemaDrift === true,
|
|
83
|
-
apiSpec: parseApiSpec(options.apiSpec),
|
|
84
|
-
cwd,
|
|
85
|
-
format: options.format,
|
|
86
|
-
logger,
|
|
87
|
-
// `--no-typecheck` is declared as a `no-*` option but cerebro exposes it
|
|
88
|
-
// under the negated `typecheck` key (false when passed, true when absent).
|
|
89
|
-
typecheck: options.typecheck === false ? false : void 0
|
|
90
|
-
});
|
|
91
|
-
return { code: result.code };
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
export { execute, runVerifyCommand };
|
|
1
|
+
import{d as f}from"../packem_shared/command-BpMv2n0o.mjs";import{EXIT_CODE as y}from"../packem_shared/EXIT_CODE-DQVhSE-1.mjs";import{runRpcCommand as l}from"./runRpcCommand.mjs";const i="__lunora_admin__:createWorkflowInstance",N="__lunora_admin__:sendWorkflowEvent",u="Usage: lunora workflow create <exportName> [--id <id>] [--params <json>] | lunora workflow send-event <exportName> <instanceId> <eventType> [--payload <json>]",m=r=>{if(r===void 0)return{value:void 0};try{return{value:JSON.parse(r)}}catch{return}},n=(r,e)=>(r.error(e),{body:void 0,code:y.USAGE,error:e,requestUrl:""}),s=r=>{const{body:e}=r;return typeof e=="object"&&e!==null&&"result"in e?{...r,body:e.result}:r},p=async r=>{const{logger:e}=r,d={cwd:r.cwd,fetchImpl:r.fetchImpl,format:r.format,logger:e,token:r.token,url:r.url};if(r.subcommand==="create"){const a=m(r.params);return r.exportName?a===void 0?n(e,"could not parse --params as JSON"):s(await l({...d,args:JSON.stringify({exportName:r.exportName,...r.id===void 0?{}:{id:r.id},params:a.value}),functionPath:i})):n(e,u)}if(r.subcommand==="send-event"){const a=m(r.payload);return!r.exportName||!r.id||!r.type?n(e,u):a===void 0?n(e,"could not parse --payload as JSON"):s(await l({...d,args:JSON.stringify({exportName:r.exportName,id:r.id,payload:a.value,type:r.type}),functionPath:N}))}return n(e,`workflow: unknown subcommand "${r.subcommand??""}". ${u}`)},k=f(async({argument:r,cwd:e,format:d,logger:a,options:t})=>{const c=r[0],o=await p({cwd:e,exportName:r[1],format:d,id:c==="send-event"?r[2]:t.id,logger:a,params:t.params,payload:t.payload,subcommand:c,token:t.token,type:r[3],url:t.url});return{code:o.code,data:o.body,error:o.error}});export{k as execute,p as runWorkflowCommand};
|
|
@@ -1,94 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const STUDIO_PATH = "/_lunora/studio";
|
|
9
|
-
const findWranglerFile = (projectRoot) => {
|
|
10
|
-
for (const candidate of ["wrangler.jsonc", "wrangler.json"]) {
|
|
11
|
-
const fullPath = join(projectRoot, candidate);
|
|
12
|
-
if (existsSync(fullPath)) {
|
|
13
|
-
return fullPath;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return void 0;
|
|
17
|
-
};
|
|
18
|
-
const readWrangler = (projectRoot) => {
|
|
19
|
-
const file = findWranglerFile(projectRoot);
|
|
20
|
-
if (!file) {
|
|
21
|
-
return void 0;
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
const parsed = parse(readFileSync(file, "utf8"));
|
|
25
|
-
return parsed !== null && typeof parsed === "object" ? parsed : void 0;
|
|
26
|
-
} catch {
|
|
27
|
-
return void 0;
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
const resolveDevPort = (wrangler) => {
|
|
31
|
-
if (!wrangler) {
|
|
32
|
-
return DEFAULT_DEV_PORT;
|
|
33
|
-
}
|
|
34
|
-
const { dev } = wrangler;
|
|
35
|
-
if (dev !== null && typeof dev === "object") {
|
|
36
|
-
const { port } = dev;
|
|
37
|
-
if (typeof port === "number" && Number.isFinite(port)) {
|
|
38
|
-
return port;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return DEFAULT_DEV_PORT;
|
|
42
|
-
};
|
|
43
|
-
const resolveRemoteUrl = (wrangler) => {
|
|
44
|
-
if (!wrangler) {
|
|
45
|
-
return void 0;
|
|
46
|
-
}
|
|
47
|
-
const { routes } = wrangler;
|
|
48
|
-
if (Array.isArray(routes) && routes.length > 0) {
|
|
49
|
-
const first = routes[0];
|
|
50
|
-
if (typeof first === "string") {
|
|
51
|
-
return `https://${first.split("/")[0] ?? first}${STUDIO_PATH}`;
|
|
52
|
-
}
|
|
53
|
-
if (first !== null && typeof first === "object") {
|
|
54
|
-
const { pattern } = first;
|
|
55
|
-
if (typeof pattern === "string" && pattern.length > 0) {
|
|
56
|
-
return `https://${pattern.split("/")[0] ?? pattern}${STUDIO_PATH}`;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
const { name } = wrangler;
|
|
61
|
-
if (typeof name === "string" && name.length > 0) {
|
|
62
|
-
return `https://${name}.workers.dev${STUDIO_PATH}`;
|
|
63
|
-
}
|
|
64
|
-
return void 0;
|
|
65
|
-
};
|
|
66
|
-
const runViewCommand = async (options) => {
|
|
67
|
-
const cwd = options.cwd ?? process.cwd();
|
|
68
|
-
const wrangler = readWrangler(cwd);
|
|
69
|
-
const { logger } = options;
|
|
70
|
-
let url;
|
|
71
|
-
if (options.remote) {
|
|
72
|
-
url = resolveRemoteUrl(wrangler);
|
|
73
|
-
if (!url) {
|
|
74
|
-
logger.error("view --remote: could not determine the remote URL from wrangler config (set `routes` or `name`).");
|
|
75
|
-
return { code: 1, url: void 0 };
|
|
76
|
-
}
|
|
77
|
-
} else {
|
|
78
|
-
url = `http://localhost:${String(resolveDevPort(wrangler))}${STUDIO_PATH}`;
|
|
79
|
-
}
|
|
80
|
-
logger.info(`opening ${url}`);
|
|
81
|
-
try {
|
|
82
|
-
await openUrl(url, { opener: options.opener });
|
|
83
|
-
} catch (error) {
|
|
84
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
85
|
-
logger.error(`view: failed to open URL: ${message}`);
|
|
86
|
-
return { code: 1, url };
|
|
87
|
-
}
|
|
88
|
-
return { code: 0, url };
|
|
89
|
-
};
|
|
90
|
-
const execute = defineHandler(
|
|
91
|
-
({ cwd, logger, options }) => runViewCommand({ cwd, logger, remote: options.remote === true })
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
export { execute, runViewCommand };
|
|
1
|
+
import{writeFileSync as h,existsSync as S,readFileSync as p}from"node:fs";import{isAbsolute as v,join as w}from"node:path";import{byCodepoint as b,scoreAdvisor as y,parseAdvisorMap as x,compareToBaseline as j}from"@lunora/advisor";import{runCodegen as A}from"@lunora/codegen";import{resolveLazyFunctions as M}from"@lunora/config";import{wranglerCodegenInputs as F}from"@lunora/config/cloudflare";import{d as D}from"../packem_shared/command-BpMv2n0o.mjs";import{EXIT_CODE as E}from"../packem_shared/EXIT_CODE-DQVhSE-1.mjs";import{D as u}from"./cli.mjs";const l={clean:"·",exempt:"–",failing:"✗",warned:"!"},d=(e,r)=>e.length>=r?e:e+" ".repeat(r-e.length),R=e=>`${e.id} (${e.visibility} ${e.kind})`,f=e=>{let r=0;for(const n of e)r=Math.max(r,n.id.length);return r},g=(e,r)=>` ${d(String(e.score),3)} ${l[e.coverage]} ${d(e.id,r)} ${e.visibility} ${e.kind}`,k=e=>{if(!e.comparable)return[` baseline not comparable (${e.reason}) — regenerate it; this run cannot verify anything`];if(!e.regressed)return[` no regression against baseline (score ${e.scoreDelta>=0?"+":""}${String(e.scoreDelta)})`];const r=[` REGRESSED against baseline (score ${e.scoreDelta>=0?"+":""}${String(e.scoreDelta)})`];for(const n of e.dropped)r.push(` ${n.id}: ${String(n.before)} → ${String(n.after)}`);for(const n of e.newFailing)r.push(` ${n}: now failing`);for(const n of e.worsened)r.push(` ${n}: more findings than the baseline`);return e.projectRegressed&&r.push(" project: new schema/config rules fired"),r},C=(e,r)=>{const n=e.procedures.filter(i=>i.coverage!=="clean"&&i.coverage!=="exempt"),t=f(n),o=[`advisor health ${String(e.score)}/100 — ${e.grade}`,` ${String(e.summary.clean)} clean · ${String(e.summary.warned)} warned · ${String(e.summary.failing)} failing · ${String(e.summary.exempt)} exempt (${String(e.summary.procedures)} procedures, ${String(e.summary.rulesFired)} rules fired)`];return e.project.checks.length>0&&o.push("",` project ${String(e.project.score)}/100 — ${e.project.checks.map(i=>i.name).join(", ")}`),n.length>0&&o.push("",...n.map(i=>g(i,t)),""," run with --all for every procedure, or --entry <file#export> for one"),r!==void 0&&o.push("",...k(r)),o.join(`
|
|
2
|
+
`)},T=e=>e.coverage==="exempt"?[` exempt: ${e.exemptReason===void 0||e.exemptReason===""?"no reason given":e.exemptReason}`]:e.checks.map(r=>{const n=r.occurrences>1?`, ×${String(r.occurrences)}`:"";return` ${r.name} (−${String(r.weight)}${n})`}),B=e=>{const r=new Map;for(const n of e){const t=r.get(n.file);t===void 0?r.set(n.file,[n]):t.push(n)}return[...r].toSorted(([n],[t])=>b(n,t))},I=e=>{const r=f(e.procedures),n=[`advisor health ${String(e.score)}/100 — ${e.grade}`,"",` legend: ${l.clean} clean ${l.warned} warned ${l.failing} failing ${l.exempt} exempt`];for(const[t,o]of B(e.procedures)){n.push("",` ${t}`);for(const i of o)n.push(g(i,r),...T(i))}return n.join(`
|
|
3
|
+
`)},L=(e,r)=>{const n=e.procedures.find(o=>o.id===r);if(n===void 0){const o=e.procedures.slice(0,10).map(i=>` ${i.id}`);return[`no procedure ${r} in the map. Known ids:`,...o,e.procedures.length>10?" …":""].filter(Boolean).join(`
|
|
4
|
+
`)}const t=[`${R(n)} — ${String(n.score)}/100, ${n.coverage}`,` weight in the global mean: ${String(n.weight)}`];if(n.checks.length===0)return t.push(""," no rule fired"),t.join(`
|
|
5
|
+
`);t.push(""," rules fired:");for(const o of n.checks)t.push(` [${o.level}] ${o.name} −${String(o.weight)}${o.occurrences>1?` (×${String(o.occurrences)})`:""}`);return t.join(`
|
|
6
|
+
`)},N=new Date(0).toISOString(),m=(e,r)=>v(r)?r:w(e,r),P=e=>{if(e===void 0)return{value:void 0};if(e===null||e==="")return{error:"--min-score needs a value between 0 and 100"};const r=Number(e);return Number.isFinite(r)&&r>=0&&r<=100?{value:r}:{error:"--min-score must be a number between 0 and 100"}},_=(e,r,n)=>{const t=m(r,n===null||n===""?u:n);if(!S(t))return{error:`baseline not found at ${t} — generate one with \`lunora advisor\` and commit it`};const o=x(JSON.parse(p(t,"utf8")));return o===void 0?{error:`baseline at ${t} is malformed — regenerate it with \`lunora advisor\``}:{comparison:j(e,o)}},z=e=>`baseline is not comparable (${e}) — regenerate it; this run verified nothing`,G=(e,r,n)=>r.entry!==void 0?L(e,r.entry):r.all===!0?I(e):C(e,n),H=e=>{const r=e.cwd??process.cwd(),n=e.format==="json",{logger:t}=e,o=P(e.minScore);if("error"in o)return e.logger.error(o.error),{code:E.USAGE,error:o.error};const{advisorContext:i,advisories:$}=A({dryRun:!0,lazyFunctions:M(),projectRoot:r,...F(r)}),a=y(i?.procedureProtections??[],$,{generatedAt:e.generatedAt??N}),s={map:a};if(e.baseline!==void 0){const c=_(a,r,e.baseline);if("error"in c)return e.logger.error(c.error),{...s,error:c.error};s.comparison=c.comparison,c.comparison.comparable||e.logger.error(z(c.comparison.reason))}if(e.write!==!1){const c=m(r,e.out??u);h(c,`${JSON.stringify(a,void 0,4)}
|
|
7
|
+
`,"utf8"),s.written=c}return s.belowMinScore=o.value!==void 0&&a.score<o.value,s.belowMinScore&&t.error(`advisor score ${String(a.score)} is below the required ${String(o.value)}`),n||(t.info(G(a,e,s.comparison)),s.written!==void 0&&t.success(`wrote ${s.written}`)),s},J=e=>e.error!==void 0||e.belowMinScore===!0?!0:e.comparison!==void 0&&(!e.comparison.comparable||e.comparison.regressed),Z=D(({cwd:e,format:r,logger:n,options:t})=>{const o=H({all:t.all,baseline:t.baseline,cwd:e,entry:t.entry,format:r,logger:n,minScore:t.minScore,out:t.out,write:t.write});return{code:o.code??(J(o)?1:0),data:{belowMinScore:o.belowMinScore,comparison:o.comparison,map:o.map,written:o.written},error:o.error}});export{Z as execute,H as runAdvisorCommand};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as u}from"../packem_shared/cap-error-body-YBKO32BF.mjs";import{r as y}from"../packem_shared/admin-token-VdUnvnKW.mjs";import{r as S,a as A}from"../packem_shared/admin-url-DJB8P6Jh.mjs";import{d as w}from"../packem_shared/command-BpMv2n0o.mjs";import{r as E}from"../packem_shared/deploy-target-resolve-BTCW1Iv4.mjs";import{exitCodeForStatus as $,EXIT_CODE as n}from"../packem_shared/EXIT_CODE-DQVhSE-1.mjs";import{resolve as N}from"node:path";import{w as U}from"../packem_shared/mcp-config-file-GR1Y_CVw.mjs";const f=["cpu","heap"],p=1e3,g=5e4,b=1e4,T=3e4,h=[31,139],v=(r,e)=>{const t=r??"cpu";if(!f.includes(t))return{error:`profile: invalid --type "${t}" — expected ${f.join(" | ")}`};const o=e===void 0?b:Number(e);return!Number.isInteger(o)||o<p||o>g?{error:`profile: invalid --duration-ms "${e??""}" — expected an integer from ${String(p)} to ${String(g)}`}:{durationMs:o,profileType:t}},I=async r=>{r.logger.info(`Profiling ${r.url} for ${String(r.durationMs)} ms — keep traffic flowing to it…`);try{const e=await r.fetch(r.url,{body:JSON.stringify(r.body),headers:{...r.headers,"Content-Type":"application/json"},method:"POST",signal:AbortSignal.timeout(r.durationMs+T)});if(!e.ok){const o=r.describeBody(await e.text());return{code:$(e.status),error:`profile failed (HTTP ${String(e.status)})${o.length>0?`: ${o}`:""}${r.hintForStatus(e.status)}.`}}const t=new Uint8Array(await e.arrayBuffer());if(t[0]!==h[0]||t[1]!==h[1]){const o=r.describeBody(new TextDecoder().decode(t));return{code:n.FAILURE,error:`profile failed: the endpoint answered 200 with something that is not a gzip profile${o.length>0?`: ${o}`:""}.`}}return{bytes:t}}catch(e){const t=e instanceof Error?e.message:String(e);return{code:n.UNAVAILABLE,error:`profile failed: ${t}.`}}},_=(r,e,t,o)=>{const a=N(r,e??t);try{return U(a,o),{file:a}}catch(s){return{error:`could not write ${a}: ${s instanceof Error?s.message:String(s)}`}}},i=(r,e,t)=>(r.error(t),{code:e,error:t}),M=r=>{try{const e=JSON.parse(r);if(typeof e.error?.message=="string"&&e.error.message.length>0)return u(e.error.message)}catch{}return u(r.trim())},O=r=>{switch(r){case 401:case 403:return" — check that the token matches the one the app passes to createNodeProfileHandler";case 404:return" — check the URL: it must be the route the app mounted createNodeProfileHandler on";case 409:return" — a capture is already running in that app process; wait for it to finish";default:return""}},P=r=>{const{logger:e}=r,t=E(r.cwd,r.target);if(t.error!==void 0)return i(e,n.USAGE,`profile: ${t.error}`);if(t.target==="cloudflare")return i(e,n.USAGE,"profile: this project deploys to Cloudflare. `lunora profile` profiles a Node-target app; on Cloudflare run `lunora cloudflare profile`.");if(t.target!=="node")return i(e,n.USAGE,"profile: only the node target is supported here — pass --target node")},k=r=>{const{logger:e}=r;if(r.url===void 0||r.url==="")return i(e,n.USAGE,"profile: pass --url with the full URL of the route the app mounts createNodeProfileHandler on (there is no default for a Node app)");const t=S(r.url,e,r.cwd);if(t===void 0)return{code:n.USAGE,error:"could not resolve a usable profile URL"};const{token:o}=y({cwd:r.cwd,token:r.token,url:t});return o===void 0?i(e,n.AUTH,"profile: no admin token — pass --token, or set LUNORA_ADMIN_TOKEN"):{token:o,url:t}},R=async r=>{const{logger:e}=r,t=v(r.profileType,r.durationMs);if("error"in t)return i(e,n.USAGE,t.error);const o=P(r);if(o!==void 0)return o;const a=k(r);if("code"in a)return a;const{durationMs:s,profileType:d}=t,c=await I({body:{duration_ms:s,profile_type:d},describeBody:M,durationMs:s,fetch:r.fetchImpl??A,headers:{Authorization:`Bearer ${a.token}`},hintForStatus:O,logger:e,url:a.url});if("code"in c)return i(e,c.code,c.error);const m=(r.now??new Date).toISOString().replaceAll(/[:.]/gu,"-"),l=_(r.cwd,r.out,`profile-${d}-${m}.pprof.gz`,c.bytes);return"error"in l?i(e,n.FAILURE,`profile failed: ${l.error}.`):(e.success(`Wrote ${String(c.bytes.byteLength)} bytes to ${l.file}`),e.info("Open it with `go tool pprof -http=: <file>` (pprof reads gzip directly) or upload it to a flamegraph viewer."),{code:n.SUCCESS,data:{bytes:c.bytes.byteLength,durationMs:s,file:l.file,profileType:d,url:a.url}})},z=w(async({cwd:r,logger:e,options:t})=>{const o=await R({cwd:r,durationMs:t.durationMs,logger:e,out:t.out,profileType:t.type,target:t.target,token:t.token,url:t.url});return{code:o.code,data:o.data,error:o.error}});export{z as execute,R as runProfileCommand};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{writeFileSync as b,existsSync as S,cpSync as I,statSync as N,lstatSync as M,readdirSync as _,mkdirSync as O,readFileSync as x}from"node:fs";import{join as f,sep as B,relative as K,resolve as E,dirname as V}from"node:path";import{SDK_TARGETS as G,SDK_LANGUAGES as P,generateSdk as Q,isTypedSchema as J}from"@lunora/codegen";import{LunoraError as d}from"@lunora/errors";import{d as q}from"../packem_shared/command-BpMv2n0o.mjs";import{r as k,a as H,b as W,s as X}from"../packem_shared/resolve-Bdc9KEUv.mjs";import{r as U}from"../packem_shared/cli-manifest-DoQ_3bzs.mjs";const $="gh:anolilab/lunora/sdks",v="lunora-transport.json",z=/_test\.|Tests?\./u,A=t=>t.startsWith("test_")||z.test(t),C=(t,n="")=>_(t).toSorted((e,r)=>e.localeCompare(r)).flatMap(e=>{const r=f(t,e),a=n.length>0?`${n}/${e}`:e;return N(r).isDirectory()?C(r,a):[a]}),F=(t,n)=>{const e=M(n);if(e.isSymbolicLink())throw new d("INTERNAL",`refusing to vendor "${K(t,n)}" — it is a symlink, not a regular file`);if(e.isDirectory())for(const r of _(n))A(r)||F(t,f(n,r))},R=(t,n,e,r)=>{const a=f(t,e);if(!S(a))throw new d("NOT_FOUND",`transport is missing ${e}`);F(t,a);const s=f(n,r);return I(a,s,{filter:o=>!A(o.slice(o.lastIndexOf(B)+1)),force:!0,recursive:!0}),N(s).isDirectory()?C(s).map(o=>`${r}/${o}`):[r]},L=(t,n)=>n.vendor.every(e=>S(f(t,e.from))),Y=async(t,n)=>{const{language:e,logger:r,outputDirectory:a,registryOptions:s,target:o}=n,{cleanup:l,directory:h}=await W(e,{...s,ref:t},$);try{if(!L(h,o)){r.warn(`${$}/${e} does not exist at ${t}.`);return}return{files:o.vendor.flatMap(c=>R(h,a,c.from,c.to)).toSorted((c,u)=>c.localeCompare(u)),ref:t,source:`${$}/${e}`,versionMatched:t===k()}}finally{l()}},Z=(t,n)=>{const{language:e,outputDirectory:r,target:a}=n,s=f(t,e);if(!S(s))throw new d("NOT_FOUND",`no transport at ${s} — --from must point at a directory of per-language transports (the repo's \`sdks/\`)`);if(!L(s,a)){const o=a.vendor.map(l=>l.from).join(", ");throw new d("NOT_FOUND",`${s} is not a ${e} transport — expected it to contain ${o}`)}return{files:a.vendor.flatMap(o=>R(s,r,o.from,o.to)).toSorted((o,l)=>o.localeCompare(l)),ref:"local",source:s,versionMatched:!1}},ee=async t=>{const{allowUnsafeSource:n,from:e,language:r,logger:a,outputDirectory:s,ref:o,source:l,target:h}=t;if(e!==void 0)return Z(e,{language:r,outputDirectory:s,target:h});const c={allowUnsafeSource:n,logger:a,names:[],source:l},u=async i=>Y(await H(i,a),{language:r,logger:a,outputDirectory:s,registryOptions:c,target:h});if(o!==void 0&&o.length>0){const i=await u(o);if(i===void 0)throw new d("NOT_FOUND",`--ref ${o} carries no ${r} transport — pick a ref that does, or pass --from <dir> to copy a local one`);return i}const g=k(),y=await u(g).catch(i=>{const w=i instanceof Error?i.message.split(`
|
|
2
|
+
`)[0]??i.message:String(i);a.warn(`could not fetch the transport at ${g} (${w}).`)});if(y!==void 0)return y;const m=await u(void 0);if(m===void 0)throw new d("NOT_FOUND",`no ${r} transport at ${g} or on the release branch. This language may not be released yet — pass --from <dir> to copy one from a checkout, or --ref <tag> to name a ref that has it.`);return a.warn(`FALLBACK: the transport is NOT version-matched to this CLI (${U()}). Wanted ${g}, used ${m.ref}. The vendored wire protocol may not be the one this surface was generated against; ${v} records what was actually copied.`),m},te=(t,n,e)=>{const r={cliVersion:U(),files:e.files,language:n,note:e.versionMatched?"Vendored by `lunora sdk generate` at the ref matching the CLI that generated the surface beside it. Regenerate with a newer CLI to upgrade.":"Vendored by `lunora sdk generate` from a ref that is NOT this CLI's release tag, so the transport and the generated surface may be different protocol vintages.",ref:e.ref,source:e.source,versionMatched:e.versionMatched};b(f(t,v),`${JSON.stringify(r,void 0,4)}
|
|
3
|
+
`,"utf8")},re=f("lunora","_generated","openrpc.json"),ne=t=>{if(!S(t))throw new d("NOT_FOUND",`no OpenRPC document at ${t} — run \`lunora codegen --api-spec openrpc\` (or \`--api-spec both\`) first, or pass --spec`);let n;try{n=JSON.parse(x(t,"utf8"))}catch(e){throw new d("BAD_REQUEST",`${t} is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}if(n===null||typeof n!="object"||!Array.isArray(n.methods))throw new d("BAD_REQUEST",`${t} is not an OpenRPC document (no \`methods\` array)`);return n},fe=q(async({argument:t,cwd:n,logger:e,options:r})=>{const a=t[0]??"generate";if(a!=="generate")throw new d("BAD_REQUEST",`unknown subcommand "${a}" — the only one is \`lunora sdk generate\``);const s=r.lang??"python",o=G[s];if(o===void 0)throw new d("BAD_REQUEST",`unsupported --lang "${s}" — expected one of: ${P.join(" | ")}`);const l=X("sdk generate",{allowUnsafeSource:r.allowUnsafeSource,logger:e,names:[],source:r.source});if(l!==void 0)throw new d("BAD_REQUEST",l);const h=E(n,r.spec??re),c=E(n,r.out??f("sdk",s)),u=ne(h);u.methods.every(p=>p["x-lunora-function-kind"]==="stream")&&e.warn(`${h} declares no methods — writing an empty SDK.`);const{files:g,undeclared:y,unrepresentable:m}=await Q(u,o);O(c,{recursive:!0});const i=await ee({allowUnsafeSource:r.allowUnsafeSource,from:r.from,language:s,logger:e,outputDirectory:c,ref:r.ref,source:r.source,target:o});te(c,s,i);for(const[p,j]of Object.entries(g)){const D=f(c,p);O(V(D),{recursive:!0}),b(D,j,"utf8")}const w=u.methods.filter(p=>p["x-lunora-function-kind"]!=="stream"),T=w.filter(p=>!J(p.result?.schema)).length;return e.success(`Generated ${s} SDK for ${String(w.length)} function(s) → ${c}`),e.info(`Vendored the ${s} transport (${String(i.files.length)} file(s)) from ${i.source} @ ${i.ref}${i.versionMatched?" — version-matched to this CLI":""}; see ${v}.`),e.info(o.requires.length>0?`Install in the consuming project: ${o.requires.join(", ")}.`:"Nothing to install — the transport is vendored and needs only the standard library."),y.length>0&&e.warn(`${String(y.length)} schema(s) are not expressible as a named ${s} model, so those arguments or returns stay untyped: ${y.join(", ")}`),m.length>0&&e.warn(`${String(m.length)} function(s) take or return a \`v.bigint()\`/\`v.bytes()\`, which no generated model can carry — their parameters stay untyped, so pass wire values directly: ${m.join(", ")}`),T>0&&e.warn(`${String(T)} of ${String(w.length)} function(s) return an untyped result — declare \`.output()\` on them for typed returns.`),{code:0}});export{fe as execute};
|