@nifrajs/cli 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +25 -25
  2. package/dist/assure.d.ts +2 -2
  3. package/dist/assure.d.ts.map +1 -1
  4. package/dist/assure.js +17 -10
  5. package/dist/assure.js.map +1 -1
  6. package/dist/capabilities-tool.d.ts +7 -0
  7. package/dist/capabilities-tool.d.ts.map +1 -1
  8. package/dist/capabilities-tool.js +68 -16
  9. package/dist/capabilities-tool.js.map +1 -1
  10. package/dist/check.d.ts +64 -22
  11. package/dist/check.d.ts.map +1 -1
  12. package/dist/check.js +400 -83
  13. package/dist/check.js.map +1 -1
  14. package/dist/cli.d.ts +37 -0
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +291 -53
  17. package/dist/cli.js.map +1 -1
  18. package/dist/diff-tool.d.ts +3 -3
  19. package/dist/diff-tool.js +7 -7
  20. package/dist/docs-search.d.ts +3 -3
  21. package/dist/docs-search.js +6 -6
  22. package/dist/doctor.d.ts +8 -4
  23. package/dist/doctor.d.ts.map +1 -1
  24. package/dist/doctor.js +74 -14
  25. package/dist/doctor.js.map +1 -1
  26. package/dist/examples.d.ts +5 -5
  27. package/dist/examples.js +5 -5
  28. package/dist/init-agents.d.ts +14 -14
  29. package/dist/init-agents.js +14 -14
  30. package/dist/internal/typescript-import.d.ts +24 -0
  31. package/dist/internal/typescript-import.d.ts.map +1 -0
  32. package/dist/internal/typescript-import.js +32 -0
  33. package/dist/internal/typescript-import.js.map +1 -0
  34. package/dist/introspect.d.ts +12 -12
  35. package/dist/introspect.js +24 -24
  36. package/dist/levels-tool.d.ts +8 -8
  37. package/dist/levels-tool.d.ts.map +1 -1
  38. package/dist/levels-tool.js +33 -30
  39. package/dist/levels-tool.js.map +1 -1
  40. package/dist/load.d.ts +17 -6
  41. package/dist/load.d.ts.map +1 -1
  42. package/dist/load.js +45 -7
  43. package/dist/load.js.map +1 -1
  44. package/dist/manifest-tool.d.ts +1 -1
  45. package/dist/manifest-tool.d.ts.map +1 -1
  46. package/dist/manifest-tool.js +4 -2
  47. package/dist/manifest-tool.js.map +1 -1
  48. package/dist/mcp-docs-tools.d.ts +1 -1
  49. package/dist/mcp-docs-tools.d.ts.map +1 -1
  50. package/dist/mcp-docs-tools.js +14 -10
  51. package/dist/mcp-docs-tools.js.map +1 -1
  52. package/dist/mcp-http.d.ts +5 -5
  53. package/dist/mcp-http.js +7 -7
  54. package/dist/mcp-protocol.d.ts +2 -2
  55. package/dist/mcp-protocol.js +2 -2
  56. package/dist/mcp-render.d.ts +3 -3
  57. package/dist/mcp-render.js +15 -7
  58. package/dist/mcp-render.js.map +1 -1
  59. package/dist/mcp-run.d.ts +2 -2
  60. package/dist/mcp-run.js +2 -2
  61. package/dist/mcp.d.ts +14 -14
  62. package/dist/mcp.d.ts.map +1 -1
  63. package/dist/mcp.js +119 -47
  64. package/dist/mcp.js.map +1 -1
  65. package/dist/openapi-tool.d.ts +1 -1
  66. package/dist/openapi-tool.js +2 -2
  67. package/dist/pipeline-guard.d.ts +83 -0
  68. package/dist/pipeline-guard.d.ts.map +1 -0
  69. package/dist/pipeline-guard.js +136 -0
  70. package/dist/pipeline-guard.js.map +1 -0
  71. package/dist/port.d.ts +9 -9
  72. package/dist/port.js +27 -27
  73. package/dist/recipes/1.8.0.d.ts +2 -2
  74. package/dist/recipes/1.8.0.js +5 -5
  75. package/dist/recipes/index.d.ts +2 -2
  76. package/dist/recipes/index.js +1 -1
  77. package/dist/scaffold.d.ts +3 -3
  78. package/dist/scaffold.js +8 -8
  79. package/dist/sync-routes.d.ts +28 -0
  80. package/dist/sync-routes.d.ts.map +1 -0
  81. package/dist/sync-routes.js +55 -0
  82. package/dist/sync-routes.js.map +1 -0
  83. package/dist/types-search.d.ts +6 -6
  84. package/dist/types-search.d.ts.map +1 -1
  85. package/dist/types-search.js +53 -8
  86. package/dist/types-search.js.map +1 -1
  87. package/dist/upgrade.d.ts +7 -7
  88. package/dist/upgrade.js +12 -12
  89. package/dist/verification.d.ts +51 -0
  90. package/dist/verification.d.ts.map +1 -0
  91. package/dist/verification.js +80 -0
  92. package/dist/verification.js.map +1 -0
  93. package/docs/examples.json +178 -88
  94. package/docs/llms-full.txt +1766 -766
  95. package/docs/types.json +2171 -2807
  96. package/package.json +22 -11
  97. package/src/assure.ts +17 -18
  98. package/src/capabilities-tool.ts +82 -16
  99. package/src/check.ts +493 -100
  100. package/src/cli.ts +306 -54
  101. package/src/diff-tool.ts +8 -8
  102. package/src/docs-search.ts +6 -6
  103. package/src/doctor.ts +81 -16
  104. package/src/examples.ts +7 -7
  105. package/src/init-agents.ts +17 -17
  106. package/src/internal/typescript-import.ts +33 -0
  107. package/src/introspect.ts +28 -28
  108. package/src/levels-tool.ts +37 -31
  109. package/src/load.ts +65 -12
  110. package/src/manifest-tool.ts +4 -2
  111. package/src/mcp-docs-tools.ts +20 -10
  112. package/src/mcp-http.ts +7 -7
  113. package/src/mcp-protocol.ts +2 -2
  114. package/src/mcp-render.ts +15 -7
  115. package/src/mcp-run.ts +2 -2
  116. package/src/mcp.ts +127 -47
  117. package/src/openapi-tool.ts +2 -2
  118. package/src/pipeline-guard.ts +186 -0
  119. package/src/port.ts +31 -31
  120. package/src/recipes/1.8.0.ts +5 -5
  121. package/src/recipes/index.ts +2 -2
  122. package/src/scaffold.ts +8 -8
  123. package/src/sync-routes.ts +69 -0
  124. package/src/types-search.ts +57 -8
  125. package/src/upgrade.ts +12 -12
  126. package/src/verification.ts +123 -0
package/dist/examples.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * `nifra_example` — verified, copy-pasteable code examples for agents. The corpus is `examples.json`
2
+ * `nifra_example` - verified, copy-pasteable code examples for agents. The corpus is `examples.json`
3
3
  * (written into this package by `bun run gen:llms`): the same doc snippets `check:docs` typechecks
4
4
  * against the live `@nifrajs/*` API. So every example this returns is GUARANTEED to compile against the
5
- * installed version — the antidote to an agent hallucinating a framework API from stale training.
5
+ * installed version - the antidote to an agent hallucinating a framework API from stale training.
6
6
  *
7
7
  * Keyword-scored over each example's name/topic/slug (curated identifiers, heavily weighted) and its
8
8
  * code body. No query → a grouped index of what's available (the cheap discovery call).
@@ -42,18 +42,18 @@ export function renderExamplesResult(examples, query, limit) {
42
42
  const index = [...byTopic.entries()]
43
43
  .map(([topic, names]) => `- **${topic}**: ${names.join(", ")}`)
44
44
  .join("\n");
45
- return `# nifra examples — index (${examples.length} verified snippets; pass \`query\` to fetch code)\n\nEvery snippet is typechecked against the installed nifra version — prefer these over recalling an API.\n\n${index}`;
45
+ return `# nifra examples - index (${examples.length} verified snippets; pass \`query\` to fetch code)\n\nEvery snippet is typechecked against the installed nifra version - prefer these over recalling an API.\n\n${index}`;
46
46
  }
47
47
  const matches = searchExamples(examples, query, limit);
48
48
  if (matches.length === 0) {
49
49
  return `No examples matched ${JSON.stringify(query)}. Call without a query for the index, or try a broader term (e.g. "auth", "upload", "isr", "client").`;
50
50
  }
51
51
  return matches
52
- .map((m) => `## ${m.name} — ${m.topic}\n\n\`\`\`ts\n${m.code}\n\`\`\``)
52
+ .map((m) => `## ${m.name} - ${m.topic}\n\n\`\`\`ts\n${m.code}\n\`\`\``)
53
53
  .join("\n\n---\n\n");
54
54
  }
55
55
  /** Load the bundled example corpus. Resolves relative to this module so it works from `src/` (repo dev)
56
- * and `dist/` (published) alike — `docs/examples.json` sits at the package root next to both. */
56
+ * and `dist/` (published) alike - `docs/examples.json` sits at the package root next to both. */
57
57
  export async function loadExamplesCorpus() {
58
58
  const url = new URL("../docs/examples.json", import.meta.url);
59
59
  try {
@@ -1,18 +1,18 @@
1
1
  /**
2
- * `nifra init-agents` — retrofit an EXISTING app with the agent-discovery files a freshly scaffolded
2
+ * `nifra init-agents` - retrofit an EXISTING app with the agent-discovery files a freshly scaffolded
3
3
  * app ships, so an already-built project adopts the nifra MCP in one command:
4
4
  *
5
- * .mcp.json — Claude Code's project MCP registry (launches `bunx @nifrajs/cli mcp`)
6
- * .cursor/mcp.json — Cursor's MCP registry (same server config)
7
- * CLAUDE.md — Claude's MCP-first preamble + `@AGENTS.md` import
8
- * AGENTS.md — a `## MCP server` section appended (or a minimal file if none exists)
5
+ * .mcp.json - Claude Code's project MCP registry (launches `bunx @nifrajs/cli mcp`)
6
+ * .cursor/mcp.json - Cursor's MCP registry (same server config)
7
+ * CLAUDE.md - Claude's MCP-first preamble + `@AGENTS.md` import
8
+ * AGENTS.md - a `## MCP server` section appended (or a minimal file if none exists)
9
9
  *
10
- * The generators are imported from `create-nifra/agent-files` — the SAME source of truth `create-nifra`
11
- * uses at scaffold time — so a retrofitted app and a freshly scaffolded one get byte-identical configs.
10
+ * The generators are imported from `create-nifra/agent-files` - the SAME source of truth `create-nifra`
11
+ * uses at scaffold time - so a retrofitted app and a freshly scaffolded one get byte-identical configs.
12
12
  *
13
13
  * Safety: this writes into the user's existing tree, so it NEVER silently clobbers a file they may have
14
14
  * customized. By default an existing `.mcp.json` / `CLAUDE.md` / `.cursor/mcp.json` is SKIPPED with a
15
- * notice; `--force` overwrites. `AGENTS.md` is special-cased — if it already has the MCP section it's
15
+ * notice; `--force` overwrites. `AGENTS.md` is special-cased - if it already has the MCP section it's
16
16
  * left alone, otherwise the section is APPENDED (never overwriting the user's conventions), and `--force`
17
17
  * is not needed for that append since it's additive. Every write path is resolved + confined under the
18
18
  * cwd (no `..` traversal escaping the project root).
@@ -21,10 +21,10 @@
21
21
  export interface InitAgentsFileResult {
22
22
  /** Project-root-relative POSIX path. */
23
23
  readonly path: string;
24
- /** `wrote` — created or (with --force) overwrote; `appended` — added the MCP section to an existing
25
- * AGENTS.md; `skipped` — already present and not forced; `present` — MCP section already there. */
24
+ /** `wrote` - created or (with --force) overwrote; `appended` - added the MCP section to an existing
25
+ * AGENTS.md; `skipped` - already present and not forced; `present` - MCP section already there. */
26
26
  readonly action: "wrote" | "appended" | "skipped" | "present";
27
- /** Why it was skipped/left, for the notice (e.g. "exists — pass --force to overwrite"). */
27
+ /** Why it was skipped/left, for the notice (e.g. "exists - pass --force to overwrite"). */
28
28
  readonly note?: string;
29
29
  }
30
30
  export interface InitAgentsResult {
@@ -36,19 +36,19 @@ export interface InitAgentsOptions {
36
36
  readonly force?: boolean;
37
37
  }
38
38
  /** Confine a project-relative path under `cwd` and return the absolute path. Rejects a spec that escapes
39
- * the root (defense-in-depth — these specs are constants, but the cwd-confinement invariant is enforced
39
+ * the root (defense-in-depth - these specs are constants, but the cwd-confinement invariant is enforced
40
40
  * at the seam, not assumed). Exported so the invariant is directly testable. */
41
41
  export declare function safeJoin(cwd: string, rel: string): string;
42
42
  /**
43
43
  * Retrofit `cwd` with the four agent-discovery files. Pure enough to unit-test (no argv, no process.exit,
44
- * no console) — the CLI wrapper handles printing + the exit code.
44
+ * no console) - the CLI wrapper handles printing + the exit code.
45
45
  */
46
46
  export declare function initAgents(cwd: string, opts?: InitAgentsOptions): Promise<InitAgentsResult>;
47
47
  /** Format the retrofit result for the terminal. */
48
48
  export declare function renderInitAgents(result: InitAgentsResult): string;
49
49
  /**
50
50
  * CLI entry: run the retrofit at `cwd` and print the result. Returns `true` (the command always succeeds
51
- * unless a write throws — which propagates as a non-zero exit via the dispatcher's catch). `--json`
51
+ * unless a write throws - which propagates as a non-zero exit via the dispatcher's catch). `--json`
52
52
  * emits the structured result for agents/CI.
53
53
  */
54
54
  export declare function runInitAgents(cwd: string, opts?: {
@@ -1,18 +1,18 @@
1
1
  /**
2
- * `nifra init-agents` — retrofit an EXISTING app with the agent-discovery files a freshly scaffolded
2
+ * `nifra init-agents` - retrofit an EXISTING app with the agent-discovery files a freshly scaffolded
3
3
  * app ships, so an already-built project adopts the nifra MCP in one command:
4
4
  *
5
- * .mcp.json — Claude Code's project MCP registry (launches `bunx @nifrajs/cli mcp`)
6
- * .cursor/mcp.json — Cursor's MCP registry (same server config)
7
- * CLAUDE.md — Claude's MCP-first preamble + `@AGENTS.md` import
8
- * AGENTS.md — a `## MCP server` section appended (or a minimal file if none exists)
5
+ * .mcp.json - Claude Code's project MCP registry (launches `bunx @nifrajs/cli mcp`)
6
+ * .cursor/mcp.json - Cursor's MCP registry (same server config)
7
+ * CLAUDE.md - Claude's MCP-first preamble + `@AGENTS.md` import
8
+ * AGENTS.md - a `## MCP server` section appended (or a minimal file if none exists)
9
9
  *
10
- * The generators are imported from `create-nifra/agent-files` — the SAME source of truth `create-nifra`
11
- * uses at scaffold time — so a retrofitted app and a freshly scaffolded one get byte-identical configs.
10
+ * The generators are imported from `create-nifra/agent-files` - the SAME source of truth `create-nifra`
11
+ * uses at scaffold time - so a retrofitted app and a freshly scaffolded one get byte-identical configs.
12
12
  *
13
13
  * Safety: this writes into the user's existing tree, so it NEVER silently clobbers a file they may have
14
14
  * customized. By default an existing `.mcp.json` / `CLAUDE.md` / `.cursor/mcp.json` is SKIPPED with a
15
- * notice; `--force` overwrites. `AGENTS.md` is special-cased — if it already has the MCP section it's
15
+ * notice; `--force` overwrites. `AGENTS.md` is special-cased - if it already has the MCP section it's
16
16
  * left alone, otherwise the section is APPENDED (never overwriting the user's conventions), and `--force`
17
17
  * is not needed for that append since it's additive. Every write path is resolved + confined under the
18
18
  * cwd (no `..` traversal escaping the project root).
@@ -21,7 +21,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
21
21
  import { isAbsolute, relative, resolve } from "node:path";
22
22
  import { AGENTS_MD_PATH, agentsMcpSection, CLAUDE_MD_PATH, CURSOR_MCP_JSON_PATH, claudeMd, MCP_JSON_PATH, mcpJson, } from "create-nifra/agent-files";
23
23
  /** Confine a project-relative path under `cwd` and return the absolute path. Rejects a spec that escapes
24
- * the root (defense-in-depth — these specs are constants, but the cwd-confinement invariant is enforced
24
+ * the root (defense-in-depth - these specs are constants, but the cwd-confinement invariant is enforced
25
25
  * at the seam, not assumed). Exported so the invariant is directly testable. */
26
26
  export function safeJoin(cwd, rel) {
27
27
  const abs = resolve(cwd, rel);
@@ -41,7 +41,7 @@ const fileExists = (path) => readFile(path)
41
41
  async function writeOwned(cwd, rel, content, force) {
42
42
  const abs = safeJoin(cwd, rel);
43
43
  if (!force && (await fileExists(abs))) {
44
- return { path: rel, action: "skipped", note: "exists — pass --force to overwrite" };
44
+ return { path: rel, action: "skipped", note: "exists - pass --force to overwrite" };
45
45
  }
46
46
  // `.cursor/mcp.json` needs its parent dir; `recursive` is a no-op for the root-level files.
47
47
  await mkdir(resolve(abs, ".."), { recursive: true });
@@ -51,7 +51,7 @@ async function writeOwned(cwd, rel, content, force) {
51
51
  /**
52
52
  * AGENTS.md is additive, not owned: if it exists and already has the MCP section, leave it; if it exists
53
53
  * without the section, append the section (preserving the user's conventions); if it's absent, write a
54
- * minimal AGENTS.md that is just the MCP section under a heading. `--force` is irrelevant here — we never
54
+ * minimal AGENTS.md that is just the MCP section under a heading. `--force` is irrelevant here - we never
55
55
  * overwrite the user's existing guidance.
56
56
  */
57
57
  async function ensureAgentsMd(cwd) {
@@ -78,7 +78,7 @@ async function ensureAgentsMd(cwd) {
78
78
  }
79
79
  /**
80
80
  * Retrofit `cwd` with the four agent-discovery files. Pure enough to unit-test (no argv, no process.exit,
81
- * no console) — the CLI wrapper handles printing + the exit code.
81
+ * no console) - the CLI wrapper handles printing + the exit code.
82
82
  */
83
83
  export async function initAgents(cwd, opts = {}) {
84
84
  const force = opts.force ?? false;
@@ -105,12 +105,12 @@ export function renderInitAgents(result) {
105
105
  const wroteAny = result.files.some((f) => f.action === "wrote" || f.action === "appended");
106
106
  const footer = wroteAny
107
107
  ? "\nThe nifra MCP is now registered. Restart your agent so it picks up .mcp.json, then prefer nifra_docs / nifra_example and gate on nifra check."
108
- : "\nNothing to do — every file was already present (use --force to overwrite the owned ones).";
108
+ : "\nNothing to do - every file was already present (use --force to overwrite the owned ones).";
109
109
  return `nifra init-agents\n\n${lines.join("\n")}\n${footer}`;
110
110
  }
111
111
  /**
112
112
  * CLI entry: run the retrofit at `cwd` and print the result. Returns `true` (the command always succeeds
113
- * unless a write throws — which propagates as a non-zero exit via the dispatcher's catch). `--json`
113
+ * unless a write throws - which propagates as a non-zero exit via the dispatcher's catch). `--json`
114
114
  * emits the structured result for agents/CI.
115
115
  */
116
116
  export async function runInitAgents(cwd, opts = {}) {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The one place the CLI imports TypeScript from.
3
+ *
4
+ * The interpolated-SQL rule parses source with the TypeScript compiler, because the regex it replaced
5
+ * could not tell `sql\`… ${id} …\`` (bound) from a plain template (injectable) without guessing at
6
+ * string and comment boundaries. That is the right tool, but it is a ~25 MB dependency, and the CLI's
7
+ * own typecheck step already treats `tsc` as something the PROJECT provides rather than something the
8
+ * CLI ships. Making it a hard dependency would have contradicted that for every install.
9
+ *
10
+ * So it is an optional peer, resolved at the moment the rule runs. Every Nifra project has TypeScript
11
+ * - the templates all ship a `typecheck` script - so this resolves in practice; the point is that an
12
+ * install does not pay for it.
13
+ */
14
+ /** The slice of the compiler the SQL scanner uses. Structural, so the peer stays optional. */
15
+ export type TypeScriptApi = typeof import("typescript");
16
+ /**
17
+ * Import the project's TypeScript, or `undefined` when it is not installed.
18
+ *
19
+ * Only a RESOLUTION failure is absence. A compiler that resolves and then fails while evaluating is a
20
+ * broken install, not a missing one, and telling that user to install what they already have sends
21
+ * them the wrong way - so that error is rethrown for the caller to report.
22
+ */
23
+ export declare function importTypeScript(): Promise<TypeScriptApi | undefined>;
24
+ //# sourceMappingURL=typescript-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript-import.d.ts","sourceRoot":"","sources":["../../src/internal/typescript-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,8FAA8F;AAC9F,MAAM,MAAM,aAAa,GAAG,cAAc,YAAY,CAAC,CAAA;AAEvD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAQ3E"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The one place the CLI imports TypeScript from.
3
+ *
4
+ * The interpolated-SQL rule parses source with the TypeScript compiler, because the regex it replaced
5
+ * could not tell `sql\`… ${id} …\`` (bound) from a plain template (injectable) without guessing at
6
+ * string and comment boundaries. That is the right tool, but it is a ~25 MB dependency, and the CLI's
7
+ * own typecheck step already treats `tsc` as something the PROJECT provides rather than something the
8
+ * CLI ships. Making it a hard dependency would have contradicted that for every install.
9
+ *
10
+ * So it is an optional peer, resolved at the moment the rule runs. Every Nifra project has TypeScript
11
+ * - the templates all ship a `typecheck` script - so this resolves in practice; the point is that an
12
+ * install does not pay for it.
13
+ */
14
+ /**
15
+ * Import the project's TypeScript, or `undefined` when it is not installed.
16
+ *
17
+ * Only a RESOLUTION failure is absence. A compiler that resolves and then fails while evaluating is a
18
+ * broken install, not a missing one, and telling that user to install what they already have sends
19
+ * them the wrong way - so that error is rethrown for the caller to report.
20
+ */
21
+ export async function importTypeScript() {
22
+ try {
23
+ return (await import("typescript"));
24
+ }
25
+ catch (cause) {
26
+ const message = cause instanceof Error ? cause.message : String(cause);
27
+ if (/cannot find (?:package|module)|ERR_MODULE_NOT_FOUND/i.test(message))
28
+ return undefined;
29
+ throw cause;
30
+ }
31
+ }
32
+ //# sourceMappingURL=typescript-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript-import.js","sourceRoot":"","sources":["../../src/internal/typescript-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,CAAkB,CAAA;IACtD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACtE,IAAI,sDAAsD,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,SAAS,CAAA;QAC1F,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Introspect a loaded nifra project into a Markdown brief — the API routes (`backend.routes()`), the
3
- * page routes (`discoverRoutes`), and a conventions summary — for piping into an AI coding agent's
2
+ * Introspect a loaded nifra project into a Markdown brief - the API routes (`backend.routes()`), the
3
+ * page routes (`discoverRoutes`), and a conventions summary - for piping into an AI coding agent's
4
4
  * prompt. Used by `nifra context` (stdout) and the `nifra mcp` server (a tool result), so an agent sees
5
5
  * *this* project's actual surface, not just generic docs.
6
6
  */
@@ -10,31 +10,31 @@ import type { LoadedApp } from "./load.js";
10
10
  /** Read the backend's registered routes, if it's a `server()` with a `.routes()` method. */
11
11
  export declare function backendRoutes(backend: unknown): ReflectedRoute[];
12
12
  /**
13
- * Render a JSON Schema as a compact TypeScript-like type (`{ id: string, name?: string }`) — the
13
+ * Render a JSON Schema as a compact TypeScript-like type (`{ id: string, name?: string }`) - the
14
14
  * shape agents already think in, at a fraction of the raw JSON Schema's tokens (~70-80% smaller).
15
15
  * Anything the renderer doesn't model falls back to the raw JSON for that subtree, so the output
16
16
  * is always faithful, just not always minimal.
17
17
  */
18
18
  export declare function tsTypeOf(schema: unknown, depth?: number): string;
19
19
  /**
20
- * The typed-client call form for a route — the exact `client<typeof app>` proxy chain an agent should
20
+ * The typed-client call form for a route - the exact `client<typeof app>` proxy chain an agent should
21
21
  * write, derived from the same convention `@nifrajs/client` implements (so it never has to read the
22
22
  * client tests to learn it): a static segment is a property (`.users`), a path param/wildcard is a call
23
23
  * that appends the value (`({ id })`), the root path is `.index`, and the HTTP verb is the terminal call.
24
- * Body verbs (POST/PUT/PATCH) take the body first then call-options; other verbs take call-options first —
24
+ * Body verbs (POST/PUT/PATCH) take the body first then call-options; other verbs take call-options first -
25
25
  * so the `{ query }` argument lands in the right slot for each.
26
26
  */
27
27
  export declare function clientCall(method: string, path: string, schema: unknown): string;
28
28
  /** Markdown section listing the backend's API routes with their request + response field shapes. */
29
29
  export declare function apiRoutesSection(routes: readonly ReflectedRoute[]): string;
30
- /** Compact API-routes INDEX for the no-arg `nifra_context` call — `METHOD path` per route, WITHOUT the
30
+ /** Compact API-routes INDEX for the no-arg `nifra_context` call - `METHOD path` per route, WITHOUT the
31
31
  * body/query/response shapes or the per-route `call` line. Bounds the first-call payload on a big backend:
32
32
  * an agent gets the full route list (so it knows what's mounted) plus a pointer to fetch any route's full
33
33
  * contract via the `path`/`kind` slice, instead of every schema up front. */
34
34
  export declare function apiRoutesIndexSection(routes: readonly ReflectedRoute[]): string;
35
35
  /** Markdown section listing the file-routed pages (URL pattern → source file). */
36
36
  export declare function pageRoutesSection(manifest: Manifest | undefined): string;
37
- /** Optional narrowing for {@link describeProject} — a path prefix and/or one section. A filtered
37
+ /** Optional narrowing for {@link describeProject} - a path prefix and/or one section. A filtered
38
38
  * brief omits the conventions block (the agent already has it from its first full call), so
39
39
  * follow-up calls cost a fraction of the tokens. */
40
40
  export interface ContextFilter {
@@ -42,9 +42,9 @@ export interface ContextFilter {
42
42
  readonly kind?: "api" | "pages";
43
43
  }
44
44
  /**
45
- * Build the project brief as Markdown. A no-arg call returns a tight **INDEX** — the route list (API
45
+ * Build the project brief as Markdown. A no-arg call returns a tight **INDEX** - the route list (API
46
46
  * routes as `METHOD path`, page routes as `pattern → file`) + conventions + a pointer to fetch full
47
- * contracts via the slice — so learning a big project is cheap, not a full-surface schema dump. Passing a
47
+ * contracts via the slice - so learning a big project is cheap, not a full-surface schema dump. Passing a
48
48
  * {@link ContextFilter} (`path` prefix and/or `kind`) returns the narrowed, FULL detail (per-route
49
49
  * body/query/response shapes + the typed-client `call` form), and omits the conventions block (the agent
50
50
  * already has it from the index call).
@@ -61,7 +61,7 @@ export interface RouteJson {
61
61
  readonly response?: string;
62
62
  }
63
63
  /**
64
- * The backend's API routes as structured JSON — what the `nifra_routes` MCP tool returns, so an agent
64
+ * The backend's API routes as structured JSON - what the `nifra_routes` MCP tool returns, so an agent
65
65
  * consumes the contract programmatically (`list_routes` / `get_route_schema`) instead of parsing the
66
66
  * Markdown brief. Optionally filtered to routes whose path starts with `pathPrefix`. Reuses the exact
67
67
  * same `call` form and TS-shaped contracts the Markdown brief shows.
@@ -76,7 +76,7 @@ export interface RouteTableEntry {
76
76
  readonly path: string;
77
77
  /** Methods this route serves, sorted (page: `GET`, plus `POST` when it has an `action`). */
78
78
  readonly methods: readonly string[];
79
- /** Source file (page only — the route module path relative to `routes/`). */
79
+ /** Source file (page only - the route module path relative to `routes/`). */
80
80
  readonly file?: string;
81
81
  /** True when this API route is auto-mounted under the page router's `apiPrefix` (so it's reachable
82
82
  * through the same web app, no hand-wired `if (pathname.startsWith("/api/"))`). Pages are never
@@ -98,7 +98,7 @@ export interface RouteTableInput {
98
98
  readonly apiPrefix?: string;
99
99
  }
100
100
  /**
101
- * Build the unified, sorted route table from page routes + backend API routes. Pure — the caller
101
+ * Build the unified, sorted route table from page routes + backend API routes. Pure - the caller
102
102
  * supplies page `hasAction` (resolved via a module load) and the API descriptors (`backend.routes()`).
103
103
  * Page routes serve `GET` (+ `POST` when they export an `action`); API routes carry their declared
104
104
  * method, and are flagged `autoMounted` when at/under `apiPrefix`. Sorted by path, then kind, then the
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Introspect a loaded nifra project into a Markdown brief — the API routes (`backend.routes()`), the
3
- * page routes (`discoverRoutes`), and a conventions summary — for piping into an AI coding agent's
2
+ * Introspect a loaded nifra project into a Markdown brief - the API routes (`backend.routes()`), the
3
+ * page routes (`discoverRoutes`), and a conventions summary - for piping into an AI coding agent's
4
4
  * prompt. Used by `nifra context` (stdout) and the `nifra mcp` server (a tool result), so an agent sees
5
5
  * *this* project's actual surface, not just generic docs.
6
6
  */
@@ -11,7 +11,7 @@ export function backendRoutes(backend) {
11
11
  return [...reflectRoutes(backend)];
12
12
  }
13
13
  /**
14
- * Render a JSON Schema as a compact TypeScript-like type (`{ id: string, name?: string }`) — the
14
+ * Render a JSON Schema as a compact TypeScript-like type (`{ id: string, name?: string }`) - the
15
15
  * shape agents already think in, at a fraction of the raw JSON Schema's tokens (~70-80% smaller).
16
16
  * Anything the renderer doesn't model falls back to the raw JSON for that subtree, so the output
17
17
  * is always faithful, just not always minimal.
@@ -58,7 +58,7 @@ export function tsTypeOf(schema, depth = 0) {
58
58
  }
59
59
  }
60
60
  /** One route's request/response field shapes, indented under its line. Reads the declared schemas off the
61
- * descriptor so an agent gets the exact input + output contract — not just "this route is validated". */
61
+ * descriptor so an agent gets the exact input + output contract - not just "this route is validated". */
62
62
  function schemaLines(schema) {
63
63
  const s = schema;
64
64
  if (!s)
@@ -77,11 +77,11 @@ function schemaLines(schema) {
77
77
  }
78
78
  const IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
79
79
  /**
80
- * The typed-client call form for a route — the exact `client<typeof app>` proxy chain an agent should
80
+ * The typed-client call form for a route - the exact `client<typeof app>` proxy chain an agent should
81
81
  * write, derived from the same convention `@nifrajs/client` implements (so it never has to read the
82
82
  * client tests to learn it): a static segment is a property (`.users`), a path param/wildcard is a call
83
83
  * that appends the value (`({ id })`), the root path is `.index`, and the HTTP verb is the terminal call.
84
- * Body verbs (POST/PUT/PATCH) take the body first then call-options; other verbs take call-options first —
84
+ * Body verbs (POST/PUT/PATCH) take the body first then call-options; other verbs take call-options first -
85
85
  * so the `{ query }` argument lands in the right slot for each.
86
86
  */
87
87
  export function clientCall(method, path, schema) {
@@ -125,9 +125,9 @@ export function apiRoutesSection(routes) {
125
125
  ...schemaLines(r.schema),
126
126
  ` - call: \`${clientCall(r.method, r.path, r.schema)}\` → \`{ ok, status, data, error }\``,
127
127
  ]);
128
- return `## API routes (backend.ts)\n\nEach route's \`body\`/\`query\`/\`response\` shape is its contract — the typed client derives request inputs and \`res.data\` from these, so a screen built on \`client<typeof app>\` stays in sync automatically. The \`call\` line is the exact \`client<typeof app>\` form: static path segments are properties, a path param is a call (\`({ id })\`), the verb is the terminal call (body first for POST/PUT/PATCH), and every call returns the never-throwing \`{ ok, status, data, error }\` Result.\n\n${lines.join("\n")}`;
128
+ return `## API routes (backend.ts)\n\nEach route's \`body\`/\`query\`/\`response\` shape is its contract - the typed client derives request inputs and \`res.data\` from these, so a screen built on \`client<typeof app>\` stays in sync automatically. The \`call\` line is the exact \`client<typeof app>\` form: static path segments are properties, a path param is a call (\`({ id })\`), the verb is the terminal call (body first for POST/PUT/PATCH), and every call returns the never-throwing \`{ ok, status, data, error }\` Result.\n\n${lines.join("\n")}`;
129
129
  }
130
- /** Compact API-routes INDEX for the no-arg `nifra_context` call — `METHOD path` per route, WITHOUT the
130
+ /** Compact API-routes INDEX for the no-arg `nifra_context` call - `METHOD path` per route, WITHOUT the
131
131
  * body/query/response shapes or the per-route `call` line. Bounds the first-call payload on a big backend:
132
132
  * an agent gets the full route list (so it knows what's mounted) plus a pointer to fetch any route's full
133
133
  * contract via the `path`/`kind` slice, instead of every schema up front. */
@@ -138,7 +138,7 @@ export function apiRoutesIndexSection(routes) {
138
138
  const lines = [...routes]
139
139
  .sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method))
140
140
  .map((r) => `- \`${r.method} ${r.path}\``);
141
- return `## API routes (backend.ts)\n\n${routes.length} route${routes.length === 1 ? "" : "s"}. Call \`nifra_context\` again with \`path\` (a route prefix) and/or \`kind: "api"\` for the body/query/response contracts + the exact \`client<typeof app>\` call form — or \`nifra_routes\` for the same as structured JSON.\n\n${lines.join("\n")}`;
141
+ return `## API routes (backend.ts)\n\n${routes.length} route${routes.length === 1 ? "" : "s"}. Call \`nifra_context\` again with \`path\` (a route prefix) and/or \`kind: "api"\` for the body/query/response contracts + the exact \`client<typeof app>\` call form - or \`nifra_routes\` for the same as structured JSON.\n\n${lines.join("\n")}`;
142
142
  }
143
143
  /** Markdown section listing the file-routed pages (URL pattern → source file). */
144
144
  export function pageRoutesSection(manifest) {
@@ -154,27 +154,27 @@ const CONVENTIONS = `## Conventions (summary)
154
154
 
155
155
  - **Backend:** \`server()\` from \`@nifrajs/core\`; returning a value sends JSON. Validate untrusted input with
156
156
  a route schema (\`{ body, query, params }\` using \`t\` from \`@nifrajs/schema\` or any Standard Schema) and read
157
- the typed \`c.body\` / \`c.query\` / \`c.params\` — never hand-parse.
157
+ the typed \`c.body\` / \`c.query\` / \`c.params\` - never hand-parse.
158
158
  - **Cross-cutting concerns** (rate limit / \`429\`, CORS, auth, CSRF, caching, security headers, body limits)
159
159
  → \`@nifrajs/middleware\`, applied with \`app.use(...)\`. Don't hand-roll them; call \`nifra_docs("middleware")\`
160
160
  for the full list + usage.
161
161
  - **Need the exact TypeScript of a \`@nifrajs/*\` symbol?** Call \`nifra_types({ name })\` (e.g. \`RateLimitStore\`,
162
- \`RouteSchema\`) — the authoritative, complete declaration. Never read \`@nifrajs\` \`.d.ts\` files.
162
+ \`RouteSchema\`) - the authoritative, complete declaration. Never read \`@nifrajs\` \`.d.ts\` files.
163
163
  - **Response contract (no drift):** declare \`{ response: t.object({...}) }\` on a route to lock its output
164
- shape — the handler is type-checked against it and the client sees exactly that shape. The contract above
164
+ shape - the handler is type-checked against it and the client sees exactly that shape. The contract above
165
165
  is the single source of truth for both sides.
166
- - **Client — ALWAYS use this for API calls:** \`client<typeof app>(url)\` derives request inputs AND
166
+ - **Client - ALWAYS use this for API calls:** \`client<typeof app>(url)\` derives request inputs AND
167
167
  \`res.data\` from the backend's route types, so the compiler catches any frontend/backend drift. Never
168
- hand-roll \`fetch\` + ad-hoc response types for an internal API — that's exactly how screens drift. It
168
+ hand-roll \`fetch\` + ad-hoc response types for an internal API - that's exactly how screens drift. It
169
169
  never throws: branch on \`res.ok ? res.data : res.error\`.
170
170
  - **Pages:** file-routed under \`routes/\`; \`loader\`/\`action\` are server-only but the module is also bundled
171
- for the browser — **never top-level-import server-only code** (DB, secrets, \`process.env\`) into a route
171
+ for the browser - **never top-level-import server-only code** (DB, secrets, \`process.env\`) into a route
172
172
  file; reach it via \`ctx.api\` / \`ctx.env\`.
173
173
  - \`app.fetch(Request)\` is the universal entry. Full reference: this repo's \`AGENTS.md\`, or \`llms-full.txt\`.`;
174
174
  /**
175
- * Build the project brief as Markdown. A no-arg call returns a tight **INDEX** — the route list (API
175
+ * Build the project brief as Markdown. A no-arg call returns a tight **INDEX** - the route list (API
176
176
  * routes as `METHOD path`, page routes as `pattern → file`) + conventions + a pointer to fetch full
177
- * contracts via the slice — so learning a big project is cheap, not a full-surface schema dump. Passing a
177
+ * contracts via the slice - so learning a big project is cheap, not a full-surface schema dump. Passing a
178
178
  * {@link ContextFilter} (`path` prefix and/or `kind`) returns the narrowed, FULL detail (per-route
179
179
  * body/query/response shapes + the typed-client `call` form), and omits the conventions block (the agent
180
180
  * already has it from the index call).
@@ -185,7 +185,7 @@ export function describeProject(app, filter) {
185
185
  manifest = discoverRoutes(app.routesDir);
186
186
  }
187
187
  catch {
188
- // No (or unreadable) routes/ — the page-routes section reports that.
188
+ // No (or unreadable) routes/ - the page-routes section reports that.
189
189
  }
190
190
  const prefix = filter?.path;
191
191
  let routes = backendRoutes(app.backend);
@@ -201,10 +201,10 @@ export function describeProject(app, filter) {
201
201
  const isIndex = filter?.kind === undefined && (prefix === undefined || prefix === "");
202
202
  const sections = [`# nifra project: ${app.cwd.slice(app.cwd.lastIndexOf("/") + 1)}`];
203
203
  if (isIndex) {
204
- sections.push("A full-stack nifra app — Web-standard, one app on Bun, Node, Deno, and the edge. This is the route INDEX; fetch a route's full body/query/response contract on demand (see below).",
205
- // Point agents at the verified surface, not recalled APIs — nifra is young, so training data is the
204
+ sections.push("A full-stack nifra app - Web-standard, one app on Bun, Node, Deno, and the edge. This is the route INDEX; fetch a route's full body/query/response contract on demand (see below).",
205
+ // Point agents at the verified surface, not recalled APIs - nifra is young, so training data is the
206
206
  // wrong source. The MCP tools (nifra_docs / nifra_example) are checked against the installed version.
207
- "> **Build against THIS surface + the verified tools — do not write nifra APIs from memory** (the\n> framework is young; recalled APIs drift). For framework code, call `nifra_example` (snippets\n> typechecked against the installed version) or `nifra_docs`; verify edits with `nifra_run` + `nifra_check`.");
207
+ "> **Build against THIS surface + the verified tools - do not write nifra APIs from memory** (the\n> framework is young; recalled APIs drift). For framework code, call `nifra_example` (snippets\n> typechecked against the installed version) or `nifra_docs`; verify edits with `nifra_run` + `nifra_check`.");
208
208
  }
209
209
  if (filter?.kind !== "pages") {
210
210
  // Index → compact `METHOD path` list; a slice → the full schema + call-form detail.
@@ -217,7 +217,7 @@ export function describeProject(app, filter) {
217
217
  return sections.join("\n\n");
218
218
  }
219
219
  /**
220
- * The backend's API routes as structured JSON — what the `nifra_routes` MCP tool returns, so an agent
220
+ * The backend's API routes as structured JSON - what the `nifra_routes` MCP tool returns, so an agent
221
221
  * consumes the contract programmatically (`list_routes` / `get_route_schema`) instead of parsing the
222
222
  * Markdown brief. Optionally filtered to routes whose path starts with `pathPrefix`. Reuses the exact
223
223
  * same `call` form and TS-shaped contracts the Markdown brief shows.
@@ -261,7 +261,7 @@ function isUnderPrefix(path, prefix) {
261
261
  return path === prefix || path.startsWith(`${prefix}/`);
262
262
  }
263
263
  /**
264
- * Build the unified, sorted route table from page routes + backend API routes. Pure — the caller
264
+ * Build the unified, sorted route table from page routes + backend API routes. Pure - the caller
265
265
  * supplies page `hasAction` (resolved via a module load) and the API descriptors (`backend.routes()`).
266
266
  * Page routes serve `GET` (+ `POST` when they export an `action`); API routes carry their declared
267
267
  * method, and are flagged `autoMounted` when at/under `apiPrefix`. Sorted by path, then kind, then the
@@ -342,7 +342,7 @@ export async function describeRoutes(app, opts = {}) {
342
342
  manifest = discoverRoutes(app.routesDir);
343
343
  }
344
344
  catch {
345
- // No (or unreadable) routes/ — fall through with no pages; the table still shows API routes.
345
+ // No (or unreadable) routes/ - fall through with no pages; the table still shows API routes.
346
346
  }
347
347
  const pages = [];
348
348
  for (const route of manifest?.routes ?? []) {
@@ -1,20 +1,20 @@
1
1
  /**
2
- * `nifra levels` — the verification ladder, computed from gates that already exist:
2
+ * `nifra levels` - the verification ladder, computed from gates that already exist:
3
3
  *
4
- * L0 typed contract — `nifra check` passes (compiler-enforced frontend↔backend contract)
5
- * L1 route assurance — `nifra.assurance.ts` present and every route satisfies its policy
6
- * L2 capability lockfile — capability/effect assurance passes and the lockfile is in sync
7
- * L3 route manifest — the emitted manifest hash-verifies and matches the current app
8
- * L4 invariant-tested — every route passes through an explicitly isolated executor
4
+ * L0 typed contract - `nifra check` passes (compiler-enforced frontend↔backend contract)
5
+ * L1 route assurance - `nifra.assurance.ts` present and every route satisfies its policy
6
+ * L2 capability lockfile - capability/effect assurance passes and the lockfile is in sync
7
+ * L3 route manifest - the emitted manifest hash-verifies and matches the current app
8
+ * L4 invariant-tested - every route passes through an explicitly isolated executor
9
9
  *
10
- * A level counts only when every level below it holds — the ladder is cumulative, so "L3" is one
10
+ * A level counts only when every level below it holds - the ladder is cumulative, so "L3" is one
11
11
  * honest word for a whole posture. Levels are computed, never self-declared.
12
12
  */
13
13
  export interface VerificationLevelStatus {
14
14
  readonly level: number;
15
15
  readonly name: string;
16
16
  readonly ok: boolean;
17
- /** Why the level does not hold — a gate failure or a missing prerequisite. Empty when ok. */
17
+ /** Why the level does not hold - a gate failure or a missing prerequisite. Empty when ok. */
18
18
  readonly reasons: readonly string[];
19
19
  }
20
20
  export interface VerificationLevelsResult {
@@ -1 +1 @@
1
- {"version":3,"file":"levels-tool.d.ts","sourceRoot":"","sources":["../src/levels-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiBH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED,MAAM,WAAW,wBAAwB;IACvC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAA;CACpD;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,iGAAiG;AACjG,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAwInC;AAqBD,2FAA2F;AAC3F,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GACtF,OAAO,CAAC,OAAO,CAAC,CAkBlB"}
1
+ {"version":3,"file":"levels-tool.d.ts","sourceRoot":"","sources":["../src/levels-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED,MAAM,WAAW,wBAAwB;IACvC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAA;CACpD;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,iGAAiG;AACjG,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAgJnC;AAqBD,2FAA2F;AAC3F,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GACtF,OAAO,CAAC,OAAO,CAAC,CAkBlB"}