@lunora/cli 1.0.0-alpha.12 → 1.0.0-alpha.121

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.
Files changed (95) hide show
  1. package/LICENSE.md +6 -0
  2. package/__assets__/package-og.svg +1 -1
  3. package/dist/bin.mjs +2 -10
  4. package/dist/index.d.mts +357 -321
  5. package/dist/index.d.ts +357 -321
  6. package/dist/index.mjs +1 -19
  7. package/dist/packem_chunks/handler.mjs +1 -150
  8. package/dist/packem_chunks/handler10.mjs +1 -22
  9. package/dist/packem_chunks/handler11.mjs +1 -192
  10. package/dist/packem_chunks/handler12.mjs +2 -131
  11. package/dist/packem_chunks/handler13.mjs +2 -65
  12. package/dist/packem_chunks/handler14.mjs +1 -58
  13. package/dist/packem_chunks/handler15.mjs +1 -79
  14. package/dist/packem_chunks/handler16.mjs +1 -43
  15. package/dist/packem_chunks/handler17.mjs +1 -105
  16. package/dist/packem_chunks/handler18.mjs +3 -170
  17. package/dist/packem_chunks/handler19.mjs +1 -89
  18. package/dist/packem_chunks/handler2.mjs +2 -114
  19. package/dist/packem_chunks/handler20.mjs +1 -94
  20. package/dist/packem_chunks/handler21.mjs +2 -311
  21. package/dist/packem_chunks/handler22.mjs +99 -0
  22. package/dist/packem_chunks/handler23.mjs +11 -0
  23. package/dist/packem_chunks/handler3.mjs +2 -204
  24. package/dist/packem_chunks/handler4.mjs +1 -33
  25. package/dist/packem_chunks/handler5.mjs +1 -49
  26. package/dist/packem_chunks/handler6.mjs +1 -91
  27. package/dist/packem_chunks/handler7.mjs +1 -42
  28. package/dist/packem_chunks/handler8.mjs +1 -174
  29. package/dist/packem_chunks/handler9.mjs +8 -16
  30. package/dist/packem_chunks/planDevCommand.mjs +7 -500
  31. package/dist/packem_chunks/runCodegenCommand.mjs +4 -52
  32. package/dist/packem_chunks/runDeployCommand.mjs +1 -504
  33. package/dist/packem_chunks/runInitCommand.mjs +996 -1265
  34. package/dist/packem_chunks/runMigrateGenerateCommand.mjs +9 -395
  35. package/dist/packem_chunks/runResetCommand.mjs +1 -41
  36. package/dist/packem_chunks/runRpcCommand.mjs +1 -68
  37. package/dist/packem_shared/COMMANDS-P8RHe9Zp.mjs +3 -0
  38. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-DL87PIEl.mjs +8 -0
  39. package/dist/packem_shared/admin-url-DfVehV3e.mjs +1 -0
  40. package/dist/packem_shared/api-spec-BENwiyUa.mjs +1 -0
  41. package/dist/packem_shared/buildRegistryIndex-DwySASBu.mjs +1 -0
  42. package/dist/packem_shared/codegen-error-DJN6pTH5.mjs +3 -0
  43. package/dist/packem_shared/command-Bjv4VmYA.mjs +1 -0
  44. package/dist/packem_shared/commands-BhX2Bo9B.mjs +19 -0
  45. package/dist/packem_shared/createLogger--C3x1FNE.mjs +2 -0
  46. package/dist/packem_shared/createRecordingSpawner-ByIqBepG.mjs +1 -0
  47. package/dist/packem_shared/detect-package-manager-B2eIuAiP.mjs +1 -0
  48. package/dist/packem_shared/diffSnapshots-9bDd9nOK.mjs +5 -0
  49. package/dist/packem_shared/docker-CKvYE9YF.mjs +1 -0
  50. package/dist/packem_shared/insertSchemaExtension-DZReBZ4_.mjs +8 -0
  51. package/dist/packem_shared/open-url-CTU_g9gr.mjs +1 -0
  52. package/dist/packem_shared/output-format-D7cKB-O5.mjs +2 -0
  53. package/dist/packem_shared/parseManifest-x3WsxKHz.mjs +1 -0
  54. package/dist/packem_shared/prompt-cancelled-C8Sj7OqI.mjs +1 -0
  55. package/dist/packem_shared/resolve-target-vxaXHmvg.mjs +1 -0
  56. package/dist/packem_shared/runAddCommand--TBYJQYi.mjs +1 -0
  57. package/dist/packem_shared/schema-drift-gate-CpqG-xP4.mjs +1 -0
  58. package/dist/packem_shared/schemaIrToSnapshot-Clwd2A8e.mjs +1 -0
  59. package/dist/packem_shared/storage-DOvAKGi4.mjs +1 -0
  60. package/dist/packem_shared/tui-prompts-CCt3jm1k.mjs +4 -0
  61. package/dist/packem_shared/vectorize-metadata-BvZbbqUD.mjs +1 -0
  62. package/dist/packem_shared/wrangler-name-HIl0Z6yx.mjs +1 -0
  63. package/dist/packem_shared/wrangler-secrets-BMRJwKQU.mjs +1 -0
  64. package/package.json +35 -16
  65. package/skills/README.md +28 -14
  66. package/skills/lunora/SKILL.md +48 -9
  67. package/skills/lunora-functions/SKILL.md +38 -3
  68. package/skills/lunora-migration-helper/SKILL.md +36 -17
  69. package/skills/lunora-performance-audit/SKILL.md +36 -6
  70. package/skills/lunora-quickstart/SKILL.md +86 -24
  71. package/skills/lunora-realtime/SKILL.md +43 -30
  72. package/dist/packem_shared/COMMANDS-D3h9Iwvl.mjs +0 -944
  73. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs +0 -244
  74. package/dist/packem_shared/admin-url-4UzT-CI4.mjs +0 -19
  75. package/dist/packem_shared/api-spec-CtA6ilu4.mjs +0 -13
  76. package/dist/packem_shared/buildRegistryIndex-BcYe607_.mjs +0 -38
  77. package/dist/packem_shared/command-BC30oSBW.mjs +0 -14
  78. package/dist/packem_shared/commands-DVr4lduS.mjs +0 -812
  79. package/dist/packem_shared/createLogger-B40gPzQo.mjs +0 -78
  80. package/dist/packem_shared/createRecordingSpawner-DxI3mebw.mjs +0 -43
  81. package/dist/packem_shared/detect-package-manager-DYp7n3mJ.mjs +0 -61
  82. package/dist/packem_shared/diffSnapshots-BeDvvNiF.mjs +0 -161
  83. package/dist/packem_shared/docker-hMQ97KSQ.mjs +0 -21
  84. package/dist/packem_shared/insertSchemaExtension-DAqbfr9Z.mjs +0 -64
  85. package/dist/packem_shared/open-url-Dfq6fAyT.mjs +0 -41
  86. package/dist/packem_shared/output-format-wUvAN6AL.mjs +0 -17
  87. package/dist/packem_shared/parseArgs-YXFuKdEk.mjs +0 -56
  88. package/dist/packem_shared/parseManifest--vZf2FY1.mjs +0 -94
  89. package/dist/packem_shared/resolve-target-qbsJ_5sF.mjs +0 -16
  90. package/dist/packem_shared/runAddCommand-C-NOz8NJ.mjs +0 -4
  91. package/dist/packem_shared/schema-drift-gate-BtBt0as0.mjs +0 -79
  92. package/dist/packem_shared/schemaIrToSnapshot-DdsljJT-.mjs +0 -43
  93. package/dist/packem_shared/storage-DL9OE4oE.mjs +0 -84
  94. package/dist/packem_shared/tui-prompts-M6OWsuyw.mjs +0 -663
  95. package/dist/packem_shared/wrangler-name-cy4yhm9j.mjs +0 -12
@@ -1,58 +1 @@
1
- import { readLinkedProject } from '@lunora/config';
2
- import { d as defineHandler } from '../packem_shared/command-BC30oSBW.mjs';
3
- import { defaultSpawner } from '../packem_shared/createRecordingSpawner-DxI3mebw.mjs';
4
-
5
- const LOG_FORMATS = /* @__PURE__ */ new Set(["json", "pretty"]);
6
- const runLogsCommand = async (options) => {
7
- const cwd = options.cwd ?? process.cwd();
8
- if (options.format !== void 0 && !LOG_FORMATS.has(options.format)) {
9
- options.logger.error(`logs: unknown --format "${options.format}" — expected pretty | json`);
10
- return { code: 1, descriptor: void 0, error: "invalid format" };
11
- }
12
- const args = ["exec", "wrangler", "tail"];
13
- if (options.worker !== void 0) {
14
- args.push(options.worker);
15
- }
16
- const env = options.env ?? readLinkedProject(cwd)?.env;
17
- if (env !== void 0) {
18
- args.push("--env", env);
19
- }
20
- if (options.format !== void 0) {
21
- args.push("--format", options.format);
22
- }
23
- if (options.status !== void 0) {
24
- args.push("--status", options.status);
25
- }
26
- if (options.search !== void 0) {
27
- args.push("--search", options.search);
28
- }
29
- if (options.temporary) {
30
- args.push("--temporary");
31
- }
32
- const descriptor = {
33
- args,
34
- command: "pnpm",
35
- cwd
36
- };
37
- options.logger.info(`tailing logs via ${descriptor.command} ${descriptor.args.join(" ")}`);
38
- const spawner = options.spawner ?? defaultSpawner;
39
- const result = await spawner(descriptor);
40
- return {
41
- code: result.code,
42
- descriptor
43
- };
44
- };
45
- const execute = defineHandler(
46
- ({ argument, cwd, logger, options }) => runLogsCommand({
47
- cwd,
48
- env: options.env,
49
- format: options.format,
50
- logger,
51
- search: options.search,
52
- status: options.status,
53
- temporary: options.temporary === true,
54
- worker: argument[0]
55
- })
56
- );
57
-
58
- export { execute, runLogsCommand };
1
+ import{existsSync as c,rmSync as m}from"node:fs";import{join as u}from"node:path";import{writeLinkedProject as s,LINKED_PROJECT_FILE as t}from"@lunora/config";import{i as d}from"../packem_shared/command-Bjv4VmYA.mjs";import{d as a}from"../packem_shared/wrangler-name-HIl0Z6yx.mjs";const k=r=>{try{const{protocol:o}=new URL(r);return o==="http:"||o==="https:"}catch{return!1}},p=(r,o)=>{const e=u(r,t);return c(e)?(m(e),o.success(`link: removed ${t}`),{code:0}):(o.warn(`link: no ${t} to remove`),{code:0})},v=r=>{const o=r.cwd??process.cwd(),{logger:e}=r;if(r.remove)return p(o,e);if(r.url===void 0||r.url==="")return e.error("link requires a deployed Worker URL. Usage: lunora link --url <https://your-worker>"),{code:1};if(!k(r.url))return e.error(`link: invalid --url "${r.url}" — expected an http(s) URL`),{code:1};const i=r.now??(()=>new Date().toISOString()),n={env:r.env,linkedAt:i(),workerName:r.name??a(o),workerUrl:r.url},l=s(o,n);return e.success(`link: ${n.workerName??"(unnamed worker)"} -> ${r.url}`),e.info(`link: wrote ${l}`),n.env!==void 0&&e.info(`link: environment "${n.env}"`),{code:0,link:n}},h=d(({cwd:r,logger:o,options:e})=>v({cwd:r,env:e.env,logger:o,name:e.name,remove:e.remove===!0,url:e.url}));export{h as execute,v as runLinkCommand};
@@ -1,79 +1 @@
1
- import { runCodegen } from '@lunora/codegen';
2
- import { validateWranglerProject, inferLunoraBindings, reconcileWranglerBindings } from '@lunora/config';
3
- import { p as parseApiSpec } from '../packem_shared/api-spec-CtA6ilu4.mjs';
4
- import { d as defineHandler } from '../packem_shared/command-BC30oSBW.mjs';
5
- import { r as runSchemaDriftGate } from '../packem_shared/schema-drift-gate-BtBt0as0.mjs';
6
-
7
- const provisionBindings = async (cwd, logger) => {
8
- try {
9
- const inferred = await inferLunoraBindings({ projectRoot: cwd });
10
- const reconciled = reconcileWranglerBindings(cwd, inferred);
11
- if (reconciled.changed) {
12
- logger.success(`provisioned bindings: ${reconciled.added.join(", ")} → ${reconciled.wranglerPath ?? "wrangler.jsonc"}`);
13
- }
14
- for (const warning of reconciled.warnings) {
15
- logger.warn(warning);
16
- }
17
- } catch (error) {
18
- const message = error instanceof Error ? error.message : String(error);
19
- logger.warn(`binding inference skipped: ${message}`);
20
- }
21
- };
22
- const runPrepareCommand = async (options) => {
23
- const cwd = options.cwd ?? process.cwd();
24
- options.logger.info("running codegen");
25
- let codegen;
26
- try {
27
- codegen = runCodegen({ apiSpec: options.apiSpec, projectRoot: cwd });
28
- options.logger.success("codegen complete");
29
- } catch (error) {
30
- const message = error instanceof Error ? error.message : String(error);
31
- options.logger.error(`codegen failed: ${message}`);
32
- return {
33
- code: 1,
34
- error: `codegen failed: ${message}`,
35
- validation: { problems: [], wranglerPath: void 0 }
36
- };
37
- }
38
- const gate = runSchemaDriftGate({
39
- allowDrift: options.allowSchemaDrift === true,
40
- codegen,
41
- logger: options.logger,
42
- updateBaseline: options.updateSchemaBaseline === true
43
- });
44
- if (gate.blocked) {
45
- return {
46
- code: 1,
47
- error: "schema drift gate blocked prepare",
48
- schemaDrift: { blocked: true, reason: gate.reason },
49
- validation: { problems: [], wranglerPath: void 0 }
50
- };
51
- }
52
- await provisionBindings(cwd, options.logger);
53
- const validation = validateWranglerProject({ projectRoot: cwd });
54
- if (validation.problems.length > 0) {
55
- options.logger.error("wrangler.jsonc validation failed:");
56
- for (const problem of validation.problems) {
57
- options.logger.error(` - ${problem}`);
58
- }
59
- return {
60
- code: 1,
61
- error: "wrangler validation failed",
62
- validation
63
- };
64
- }
65
- gate.rebless?.();
66
- options.logger.success("project is ready to deploy");
67
- return { code: 0, validation };
68
- };
69
- const execute = defineHandler(
70
- ({ cwd, logger, options }) => runPrepareCommand({
71
- allowSchemaDrift: options.allowSchemaDrift === true,
72
- apiSpec: parseApiSpec(options.apiSpec),
73
- cwd,
74
- logger,
75
- updateSchemaBaseline: options.updateSchemaBaseline === true
76
- })
77
- );
78
-
79
- export { execute, runPrepareCommand };
1
+ import{runCodegen as i}from"@lunora/codegen";import{validateWranglerProject as s,inferLunoraBindings as g,reconcileWranglerBindings as l,reconcileWranglerCompatibilityDate as d,reconcileWranglerCrons as p}from"@lunora/config";import{r as m}from"../packem_shared/api-spec-BENwiyUa.mjs";import{l as f}from"../packem_shared/codegen-error-DJN6pTH5.mjs";import{i as w}from"../packem_shared/command-Bjv4VmYA.mjs";import{k as u}from"../packem_shared/schema-drift-gate-CpqG-xP4.mjs";const h=async(r,n,a=[])=>{try{const e=await g({projectRoot:r}),o=l(r,e);o.changed&&n.success(`provisioned bindings: ${o.added.join(", ")} → ${o.wranglerPath??"wrangler.jsonc"}`);for(const t of o.warnings)n.warn(t)}catch(e){const o=e instanceof Error?e.message:String(e);n.warn(`binding inference skipped: ${o}`)}try{const e=d(r);e.changed&&n.success(`bumped compatibility_date to ${e.date??"unknown"} (Workers Cache enabled) → ${e.wranglerPath??"wrangler.jsonc"}`)}catch(e){const o=e instanceof Error?e.message:String(e);n.warn(`compatibility date sync skipped: ${o}`)}try{const e=p(r,a);e.changed&&n.success(`synced ${String(a.length)} cron trigger(s) → ${e.wranglerPath??"wrangler.jsonc"}`)}catch(e){const o=e instanceof Error?e.message:String(e);n.warn(`cron trigger sync skipped: ${o}`)}},b=async r=>{const n=r.cwd??process.cwd();r.logger.info("running codegen");let a;try{a=i({apiSpec:r.apiSpec,projectRoot:n}),r.logger.success("codegen complete")}catch(t){const c=t instanceof Error?t.message:String(t);return r.logger.error(f(t)),{code:1,error:`codegen failed: ${c}`,validation:{problems:[],wranglerPath:void 0}}}const e=u({allowDrift:r.allowSchemaDrift===!0,codegen:a,logger:r.logger,updateBaseline:r.updateSchemaBaseline===!0});if(e.blocked)return{code:1,error:"schema drift gate blocked prepare",schemaDrift:{blocked:!0,reason:e.reason},validation:{problems:[],wranglerPath:void 0}};await h(n,r.logger,a.cronTriggers);const o=s({projectRoot:n});if(o.problems.length>0){r.logger.error("wrangler.jsonc validation failed:");for(const t of o.problems)r.logger.error(` - ${t}`);return{code:1,error:"wrangler validation failed",validation:o}}return e.rebless?.(),r.logger.success("project is ready to deploy"),{code:0,validation:o}},P=w(({cwd:r,logger:n,options:a})=>b({allowSchemaDrift:a.allowSchemaDrift===!0,apiSpec:m(a.apiSpec),cwd:r,logger:n,updateSchemaBaseline:a.updateSchemaBaseline===!0}));export{P as execute,b as runPrepareCommand};
@@ -1,43 +1 @@
1
- import { d as defineHandler } from '../packem_shared/command-BC30oSBW.mjs';
2
- import { r as runAddCommand, b as runRegistryViewCommand, a as runBuildIndexCommand } from '../packem_shared/commands-DVr4lduS.mjs';
3
-
4
- const execute = defineHandler(({ argument, cwd, logger, options }) => {
5
- const subcommand = argument[0];
6
- const names = argument.slice(1);
7
- if (subcommand === "add") {
8
- return runAddCommand({
9
- allowUnsafeSource: options.allowUnsafeSource === true,
10
- cwd,
11
- diff: options.diff === true,
12
- dryRun: options.dryRun === true,
13
- from: options.from,
14
- json: options.json === true,
15
- logger,
16
- names,
17
- overwrite: options.overwrite === true,
18
- ref: options.ref,
19
- source: options.source,
20
- yes: options.yes === true
21
- });
22
- }
23
- if (subcommand === "list") {
24
- return runAddCommand({ cwd, from: options.from, json: options.json === true, list: true, logger, names: [], ref: options.ref, source: options.source });
25
- }
26
- if (subcommand === "view") {
27
- return runRegistryViewCommand({
28
- allowUnsafeSource: options.allowUnsafeSource === true,
29
- from: options.from,
30
- logger,
31
- names,
32
- ref: options.ref,
33
- source: options.source
34
- });
35
- }
36
- if (subcommand === "build") {
37
- return runBuildIndexCommand({ check: options.check === true, from: options.from, logger, out: options.out });
38
- }
39
- logger.error("registry: unknown subcommand. Usage: lunora registry <add|list|view|build> [names…]");
40
- return { code: 1 };
41
- });
42
-
43
- export { execute };
1
+ import{i as n}from"../packem_shared/command-Bjv4VmYA.mjs";import{M as c,k as f,q as a}from"../packem_shared/commands-BhX2Bo9B.mjs";const i=n(({argument:u,cwd:s,logger:o,options:e})=>{const r=u[0],t=u.slice(1);return r==="add"?c({allowUnsafeSource:e.allowUnsafeSource===!0,cwd:s,diff:e.diff===!0,dryRun:e.dryRun===!0,from:e.from,json:e.json===!0,logger:o,names:t,overwrite:e.overwrite===!0,ref:e.ref,source:e.source,yes:e.yes===!0}):r==="list"?c({cwd:s,from:e.from,json:e.json===!0,list:!0,logger:o,names:[],ref:e.ref,source:e.source}):r==="view"?f({allowUnsafeSource:e.allowUnsafeSource===!0,cwd:s,from:e.from,logger:o,names:t,ref:e.ref,source:e.source}):r==="build"?a({check:e.check===!0,from:e.from,logger:o,out:e.out}):(o.error("registry: unknown subcommand. Usage: lunora registry <add|list|view|build> [names…]"),{code:1})});export{i as execute};
@@ -1,105 +1 @@
1
- import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, writeFileSync } from 'node:fs';
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-BC30oSBW.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 a,readFileSync as g,readdirSync as p,statSync as m,mkdirSync as f,writeFileSync as w}from"node:fs";import{fileURLToPath as S}from"node:url";import{AGENT_RULES_DIR as u,detectAgentRules as y,LUNORA_SKILL_NAMES as L}from"@lunora/config";import{join as l,relative as R,dirname as d}from"@visulima/path";import{i as v}from"../packem_shared/command-Bjv4VmYA.mjs";const $=(e=d(S(import.meta.url)))=>{let t=e;for(let r=0;r<6;r+=1){const n=l(t,"package.json");if(a(n))try{if(JSON.parse(g(n,"utf8")).name==="@lunora/cli"){const o=l(t,"skills");return a(o)?o:void 0}}catch{}const s=d(t);if(s===t)break;t=s}},I=e=>p(e).filter(t=>{const r=l(e,t);return m(r).isDirectory()&&a(l(r,"SKILL.md"))}),h=(e,t,r)=>{f(t,{recursive:!0});let n=!1;for(const s of p(e)){const o=l(e,s),i=l(t,s);if(m(o).isDirectory()){n=h(o,i,r)||n;continue}a(i)&&!r||(w(i,g(o)),n=!0)}return n},A=e=>{const t=e.cwd??process.cwd(),r=e.overwrite===!0,n=$();if(n===void 0)return e.logger.error("rules: could not locate the bundled skills (is @lunora/cli installed correctly?)."),{code:1,installed:[],skipped:[]};const s=[],o=[];for(const c of I(n)){const k=l(t,u,c);h(l(n,c),k,r)?s.push(c):o.push(c)}const i=R(t,l(t,u))||u;return s.length>0&&e.logger.success(`Installed ${String(s.length)} Lunora skill(s) into ${i}/: ${s.join(", ")}.`),o.length>0&&e.logger.info(`Skipped ${String(o.length)} existing skill(s) (re-run with --overwrite to replace): ${o.join(", ")}.`),e.logger.info("Your AI coding agent will pick these up automatically. Start with the `lunora` skill."),{code:0,installed:s,skipped:o}},j=e=>{const t=e.cwd??process.cwd(),r=y(t);return r.installed?(e.logger.success(`Lunora agent rules are installed (${String(r.present.length)}/${String(L.length)} skills).`),r.missing.length>0&&e.logger.info(`Missing: ${r.missing.join(", ")}. Run \`lunora rules install\` to add them.`),{code:0,installed:r.present,skipped:[]}):(e.logger.warn("Lunora agent rules are not installed. Run `lunora rules install` so your AI agent knows how to use Lunora."),{code:e.strict===!0?1:0,installed:r.present,skipped:[]})},b=v(({argument:e,cwd:t,logger:r,options:n})=>{const s=e[0]??"check";return s==="install"?A({cwd:t,logger:r,overwrite:n.overwrite===!0}):s==="check"?j({cwd:t,logger:r,strict:n.strict===!0}):(r.error("rules: unknown subcommand. Usage: lunora rules <install|check>"),{code:1})});export{b as execute,$ as resolveBundledSkillsDirectory,j as runRulesCheck,A as runRulesInstall};
@@ -1,170 +1,3 @@
1
- import { existsSync } from 'node:fs';
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-BC30oSBW.mjs';
9
- import { a as resolveProductionWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
10
- import { b as tuiConfirm } from '../packem_shared/tui-prompts-M6OWsuyw.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{existsSync as y}from"node:fs";import{mkdtemp as S,writeFile as v,rm as j}from"node:fs/promises";import{tmpdir as $}from"node:os";import{discoverSchema as k,schemaFromIr as C}from"@lunora/codegen";import{seedPlan as R}from"@lunora/seed";import{join as m}from"@visulima/path";import{Project as x}from"ts-morph";import{i as z}from"../packem_shared/command-Bjv4VmYA.mjs";import{s as A}from"../packem_shared/resolve-target-vxaXHmvg.mjs";import{i as F}from"../packem_shared/tui-prompts-CCt3jm1k.mjs";import{runImportCommand as I}from"../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-DL87PIEl.mjs";import{runResetCommand as T}from"./runResetCommand.mjs";const w=r=>{if(r===void 0)return!0;try{const{hostname:e}=new URL(r);return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}catch{return!1}},N=(r,e)=>typeof e=="bigint"?Number(e):e instanceof ArrayBuffer?[...new Uint8Array(e)]:e,c=r=>({code:r,conflicts:0,generated:0,inserted:0,ndjson:""}),U=(r,e)=>{if(!y(e))return r.logger.error(`schema not found: ${e} — run \`vis generate lunora-table --name=<name>\` to create one`),c(1);if(r.reset===!0&&(r.prod===!0||!w(r.url)))return r.logger.error("--reset only clears local .wrangler/state and cannot be combined with --prod or a remote --url"),c(1)},P=async(r,e,t,o)=>{const l=await S(m($(),"lunora-seed-")),a=m(l,"rows.ndjson");await v(a,r,"utf8");try{const n=await I({batchSize:o.batchSize,fetchImpl:o.fetchImpl,file:a,logger:o.logger,prod:o.prod,token:o.token,url:o.url}),d=n.body?.conflicts??0;return d>0&&o.logger.warn(`${String(d)} 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.`),{code:n.code,conflicts:d,generated:e,inserted:n.inserted,ndjson:r}}finally{await j(l,{force:!0,recursive:!0}).catch(()=>{})}},_=(r,e)=>{if(r.table===void 0||e.tables.some(o=>o.name===r.table))return;const t=e.tables.map(o=>o.name).join(", ");return r.logger.error(`unknown table "${r.table}" — schema defines: ${t||"(no tables)"}`),c(1)},q=async(r,e)=>{if(!(!(r.prod===!0||!w(r.url))||r.yes===!0)){if(!process.stdin.isTTY&&r.confirm===void 0)return r.logger.error("seed: refusing to insert into a non-local target without confirmation — re-run with --yes"),c(1);if(!await(r.confirm??F)(`This will insert ${String(e)} generated row(s) into ${r.url??"the production worker"}. Continue?`))return r.logger.info("seed: aborted"),c(1)}},B=async r=>{const e=r.cwd??process.cwd(),t=m(e,"lunora","schema.ts"),o=U(r,t);if(o!==void 0)return o;const l=new x({skipAddingFilesFromTsConfig:!0}),a=k(l,t),n=_(r,a);if(n!==void 0)return n;const d=C(a),g=R(d,{defaultCount:r.count??10,only:r.table===void 0?void 0:[r.table],seed:r.seed??0}),u=[];for(const{rows:f,table:h}of g)for(const b of f)u.push(JSON.stringify({doc:b,table:h},N));const i=u.length>0?`${u.join(`
2
+ `)}
3
+ `:"",s=u.length;if(r.dryRun===!0)return i.length>0&&process.stdout.write(i),r.logger.info(`generated ${String(s)} row(s) across ${String(g.length)} table(s) — dry run, nothing inserted`),{code:0,conflicts:0,generated:s,inserted:0,ndjson:i};if(r.reset===!0){const f=await T({cwd:e,logger:r.logger,yes:!0});if(f.code!==0)return{code:f.code,conflicts:0,generated:s,inserted:0,ndjson:i}}if(s===0)return r.logger.warn("no rows generated — nothing to insert"),{code:0,conflicts:0,generated:0,inserted:0,ndjson:i};const p=await q(r,s);return p!==void 0?p:P(i,s,e,r)},W=z(async({cwd:r,logger:e,options:t})=>({code:(await B({batchSize:t.batchSize,count:t.count,cwd:r,dryRun:t.dryRun===!0,logger:e,prod:t.prod===!0,reset:t.reset===!0,seed:t.seed,table:t.table,token:t.token,url:A({cwd:r,prod:t.prod===!0,url:t.url}),yes:t.yes===!0})).code}));export{W as execute,B as runSeedCommand};
@@ -1,89 +1 @@
1
- import { existsSync } from 'node:fs';
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 { d as defineHandler } from '../packem_shared/command-BC30oSBW.mjs';
6
- import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-wUvAN6AL.mjs';
7
- import { r as runSchemaDriftGate } from '../packem_shared/schema-drift-gate-BtBt0as0.mjs';
8
- import { defaultSpawner } from '../packem_shared/createRecordingSpawner-DxI3mebw.mjs';
9
- import { validateWranglerProject } from '@lunora/config';
10
-
11
- const runTypecheckStep = async (cwd, spawner) => {
12
- if (!existsSync(join(cwd, "tsconfig.json"))) {
13
- return { warning: "no tsconfig.json found — skipping TypeScript type-check" };
14
- }
15
- const result = await spawner({ args: ["exec", "tsc", "--noEmit", "-p", "tsconfig.json"], command: "pnpm", cwd });
16
- return result.code === 0 ? {} : { error: `type errors: tsc --noEmit exited ${String(result.code)}` };
17
- };
18
- const reportVerifyResult = (logger, errors, warnings, wranglerPath) => {
19
- if (errors.length === 0 && warnings.length === 0) {
20
- logger.success("verify: project is valid");
21
- return { code: 0, errors: [], warnings: [], wranglerPath };
22
- }
23
- if (warnings.length > 0) {
24
- logger.warn("verify: warnings:");
25
- for (const warning of warnings) {
26
- logger.warn(` - ${warning}`);
27
- }
28
- }
29
- if (errors.length > 0) {
30
- logger.error("verify: errors:");
31
- for (const error of errors) {
32
- logger.error(` - ${error}`);
33
- }
34
- return { code: 1, errors, warnings, wranglerPath };
35
- }
36
- logger.success("verify: project is valid (with warnings)");
37
- return { code: 0, errors: [], warnings, wranglerPath };
38
- };
39
- const runVerifyCommand = async (options) => {
40
- const cwd = options.cwd ?? process.cwd();
41
- const logger = loggerForFormat(options.format, options.logger);
42
- const formatError = validateOutputFormat("verify", options.format);
43
- if (formatError !== void 0) {
44
- options.logger.error(formatError);
45
- return { code: 1, error: formatError, errors: [], warnings: [], wranglerPath: void 0 };
46
- }
47
- const validation = validateWranglerProject({ projectRoot: cwd });
48
- const errors = [...validation.report.errors];
49
- const warnings = [...validation.report.warnings];
50
- try {
51
- const codegen = runCodegen({ apiSpec: options.apiSpec, dryRun: true, projectRoot: cwd });
52
- const gate = runSchemaDriftGate({ allowDrift: options.allowSchemaDrift === true, codegen, logger, readOnly: true });
53
- if (gate.blocked) {
54
- errors.push(gate.reason);
55
- }
56
- } catch (error) {
57
- const message = error instanceof Error ? error.message : String(error);
58
- errors.push(`codegen failed: ${message}`);
59
- }
60
- if (options.typecheck !== false) {
61
- const typecheck = await runTypecheckStep(cwd, options.spawner ?? defaultSpawner);
62
- if (typecheck.error !== void 0) {
63
- errors.push(typecheck.error);
64
- }
65
- if (typecheck.warning !== void 0) {
66
- warnings.push(typecheck.warning);
67
- }
68
- }
69
- const result = reportVerifyResult(logger, errors, warnings, validation.wranglerPath);
70
- if (isJsonFormat(options.format)) {
71
- printJson(result);
72
- }
73
- return result;
74
- };
75
- const execute = defineHandler(async ({ cwd, logger, options }) => {
76
- const result = await runVerifyCommand({
77
- allowSchemaDrift: options.allowSchemaDrift === true,
78
- apiSpec: parseApiSpec(options.apiSpec),
79
- cwd,
80
- format: options.format,
81
- logger,
82
- // `--no-typecheck` is declared as a `no-*` option but cerebro exposes it
83
- // under the negated `typecheck` key (false when passed, true when absent).
84
- typecheck: options.typecheck === false ? false : void 0
85
- });
86
- return { code: result.code };
87
- });
88
-
89
- export { execute, runVerifyCommand };
1
+ import{existsSync as p}from"node:fs";import{join as d}from"node:path";import{runCodegen as g}from"@lunora/codegen";import{r as m}from"../packem_shared/api-spec-BENwiyUa.mjs";import{c as w}from"../packem_shared/codegen-error-DJN6pTH5.mjs";import{i as u}from"../packem_shared/command-Bjv4VmYA.mjs";import{M as y,P as v}from"../packem_shared/detect-package-manager-B2eIuAiP.mjs";import{i as S,r as $,d as j,s as P}from"../packem_shared/output-format-D7cKB-O5.mjs";import{k}from"../packem_shared/schema-drift-gate-CpqG-xP4.mjs";import{defaultSpawner as U}from"../packem_shared/createRecordingSpawner-ByIqBepG.mjs";import{validateWranglerProject as x}from"@lunora/config";const b=async(r,o)=>{if(!p(d(r,"tsconfig.json")))return{warning:"no tsconfig.json found — skipping TypeScript type-check"};const e=y(v(r),"tsc",["--noEmit","-p","tsconfig.json"]),t=await o({args:e.args,command:e.command,cwd:r});return t.code===0?{}:{error:`type errors: tsc --noEmit exited ${String(t.code)}`}},D="/_lunora/health",h=r=>(r.endsWith("/")?r.slice(0,-1):r)+D,E=async(r,o)=>{const e=h(r);let t;try{t=await o(e)}catch(a){const n=a instanceof Error?a.message:String(a);return{error:`health probe failed: could not reach ${e} (${n})`}}return t.ok?{}:{error:`health probe failed: ${e} returned HTTP ${String(t.status)}`}},R=async(r,o)=>{if(r.healthUrl===void 0||r.healthUrl==="")return;const e=await E(r.healthUrl,r.healthFetch??(t=>fetch(t)));if(e.error===void 0){o.success(`verify: health probe ok (${h(r.healthUrl)})`);return}return e.error},T=(r,o,e,t)=>{if(o.length===0&&e.length===0)return r.success("verify: project is valid"),{code:0,errors:[],warnings:[],wranglerPath:t};if(e.length>0){r.warn("verify: warnings:");for(const a of e)r.warn(` - ${a}`)}if(o.length>0){r.error("verify: errors:");for(const a of o){r.error(` - ${a}`);const n=w(a);n!==void 0&&r.error(n)}return{code:1,errors:o,warnings:e,wranglerPath:t}}return r.success("verify: project is valid (with warnings)"),{code:0,errors:[],warnings:e,wranglerPath:t}},C=async r=>{const o=r.cwd??process.cwd(),e=P(r.format,r.logger),t=S("verify",r.format);if(t!==void 0)return r.logger.error(t),{code:1,error:t,errors:[],warnings:[],wranglerPath:void 0};const a=x({projectRoot:o}),n=[...a.report.errors],c=[...a.report.warnings];try{const i=g({apiSpec:r.apiSpec,dryRun:!0,projectRoot:o}),s=k({allowDrift:r.allowSchemaDrift===!0,codegen:i,logger:e,readOnly:!0});s.blocked&&n.push(s.reason)}catch(i){const s=i instanceof Error?i.message:String(i);n.push(`codegen failed: ${s}`)}if(r.typecheck!==!1){const i=await b(o,r.spawner??U);i.error!==void 0&&n.push(i.error),i.warning!==void 0&&c.push(i.warning)}const l=await R(r,e);l!==void 0&&n.push(l);const f=T(e,n,c,a.wranglerPath);return $(r.format)&&j(f),f},G=u(async({cwd:r,logger:o,options:e})=>({code:(await C({allowSchemaDrift:e.allowSchemaDrift===!0,apiSpec:m(e.apiSpec),cwd:r,format:e.format,healthUrl:e.healthUrl,logger:o,typecheck:e.typecheck===!1?!1:void 0})).code}));export{G as execute,C as runVerifyCommand};