@squadbase/vantage 0.0.1 → 0.1.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 (167) hide show
  1. package/README.md +21 -4
  2. package/dist/chunk-A2UUGASH.js +12 -0
  3. package/dist/chunk-A2UUGASH.js.map +1 -0
  4. package/dist/{chunk-ZGDU5YLH.js → chunk-PRFBSQA4.js} +9 -5
  5. package/dist/chunk-PRFBSQA4.js.map +1 -0
  6. package/dist/chunk-WQZYXXQW.js +2249 -0
  7. package/dist/chunk-WQZYXXQW.js.map +1 -0
  8. package/dist/{chunk-73J5ZD4C.js → chunk-YLAB6UQS.js} +17 -3
  9. package/dist/chunk-YLAB6UQS.js.map +1 -0
  10. package/dist/cli.js +607 -36
  11. package/dist/cli.js.map +1 -1
  12. package/dist/components/index.d.ts +554 -0
  13. package/dist/components/index.js +1983 -0
  14. package/dist/components/index.js.map +1 -0
  15. package/dist/markdown/index.d.ts +9 -0
  16. package/dist/markdown/index.js +26 -0
  17. package/dist/markdown/index.js.map +1 -0
  18. package/dist/query/index.d.ts +27 -1
  19. package/dist/query/index.js +18 -0
  20. package/dist/query/index.js.map +1 -1
  21. package/dist/server/node.js +6 -1
  22. package/dist/server/node.js.map +1 -1
  23. package/dist/ui/index.d.ts +316 -200
  24. package/dist/ui/index.js +566 -511
  25. package/dist/ui/index.js.map +1 -1
  26. package/dist/vite/index.js +2 -2
  27. package/docs/en/agent-skills.md +89 -0
  28. package/docs/en/api-and-server.md +84 -0
  29. package/docs/en/build-and-deploy.md +280 -0
  30. package/docs/en/cli-reference.md +311 -0
  31. package/docs/en/components.md +233 -0
  32. package/docs/en/data-fetching.md +78 -0
  33. package/docs/en/environment-variables.md +69 -0
  34. package/docs/en/getting-started.md +95 -0
  35. package/docs/en/index.md +65 -0
  36. package/docs/en/markdown/markdown-renderer.md +44 -0
  37. package/docs/en/pages-and-metadata.md +56 -0
  38. package/docs/en/parts/app-shell.md +54 -0
  39. package/docs/en/parts/dashboard-card.md +64 -0
  40. package/docs/en/parts/data-table.md +86 -0
  41. package/docs/en/parts/date-range-picker.md +41 -0
  42. package/docs/en/parts/echart.md +53 -0
  43. package/docs/en/parts/filter-bar.md +66 -0
  44. package/docs/en/parts/funnel-steps.md +33 -0
  45. package/docs/en/parts/metric-value.md +23 -0
  46. package/docs/en/parts/multi-select.md +27 -0
  47. package/docs/en/parts/page-shell.md +45 -0
  48. package/docs/en/parts/searchable-select.md +47 -0
  49. package/docs/en/parts/section-header.md +20 -0
  50. package/docs/en/parts/segmented-control.md +25 -0
  51. package/docs/en/parts/status-badge.md +44 -0
  52. package/docs/en/parts/trend-indicator.md +26 -0
  53. package/docs/en/routing.md +95 -0
  54. package/docs/en/ui/accordion.md +36 -0
  55. package/docs/en/ui/alert.md +31 -0
  56. package/docs/en/ui/badge.md +23 -0
  57. package/docs/en/ui/breadcrumb.md +38 -0
  58. package/docs/en/ui/button.md +39 -0
  59. package/docs/en/ui/calendar.md +28 -0
  60. package/docs/en/ui/card.md +35 -0
  61. package/docs/en/ui/checkbox.md +34 -0
  62. package/docs/en/ui/cn.md +34 -0
  63. package/docs/en/ui/collapsible.md +21 -0
  64. package/docs/en/ui/command.md +37 -0
  65. package/docs/en/ui/dialog.md +52 -0
  66. package/docs/en/ui/dropdown-menu.md +50 -0
  67. package/docs/en/ui/empty.md +22 -0
  68. package/docs/en/ui/error-state.md +50 -0
  69. package/docs/en/ui/input-group.md +30 -0
  70. package/docs/en/ui/input.md +28 -0
  71. package/docs/en/ui/label.md +19 -0
  72. package/docs/en/ui/loading.md +19 -0
  73. package/docs/en/ui/popover.md +34 -0
  74. package/docs/en/ui/progress.md +28 -0
  75. package/docs/en/ui/scroll-area.md +23 -0
  76. package/docs/en/ui/select.md +63 -0
  77. package/docs/en/ui/separator.md +15 -0
  78. package/docs/en/ui/sheet.md +28 -0
  79. package/docs/en/ui/sidebar.md +92 -0
  80. package/docs/en/ui/skeleton.md +16 -0
  81. package/docs/en/ui/slider.md +21 -0
  82. package/docs/en/ui/spinner.md +14 -0
  83. package/docs/en/ui/switch.md +19 -0
  84. package/docs/en/ui/table.md +24 -0
  85. package/docs/en/ui/tabs.md +23 -0
  86. package/docs/en/ui/textarea.md +15 -0
  87. package/docs/en/ui/toggle-group.md +26 -0
  88. package/docs/en/ui/toggle.md +19 -0
  89. package/docs/en/ui/tooltip.md +22 -0
  90. package/docs/en/ui/use-is-mobile.md +18 -0
  91. package/docs/en/ui-and-theming.md +95 -0
  92. package/docs/index.json +1306 -0
  93. package/docs/ja/agent-skills.md +87 -0
  94. package/docs/ja/api-and-server.md +84 -0
  95. package/docs/ja/build-and-deploy.md +279 -0
  96. package/docs/ja/cli-reference.md +305 -0
  97. package/docs/ja/components.md +229 -0
  98. package/docs/ja/data-fetching.md +78 -0
  99. package/docs/ja/environment-variables.md +68 -0
  100. package/docs/ja/getting-started.md +95 -0
  101. package/docs/ja/index.md +65 -0
  102. package/docs/ja/markdown/markdown-renderer.md +43 -0
  103. package/docs/ja/pages-and-metadata.md +56 -0
  104. package/docs/ja/parts/app-shell.md +54 -0
  105. package/docs/ja/parts/dashboard-card.md +64 -0
  106. package/docs/ja/parts/data-table.md +85 -0
  107. package/docs/ja/parts/date-range-picker.md +41 -0
  108. package/docs/ja/parts/echart.md +52 -0
  109. package/docs/ja/parts/filter-bar.md +64 -0
  110. package/docs/ja/parts/funnel-steps.md +33 -0
  111. package/docs/ja/parts/metric-value.md +25 -0
  112. package/docs/ja/parts/multi-select.md +27 -0
  113. package/docs/ja/parts/page-shell.md +45 -0
  114. package/docs/ja/parts/searchable-select.md +47 -0
  115. package/docs/ja/parts/section-header.md +20 -0
  116. package/docs/ja/parts/segmented-control.md +26 -0
  117. package/docs/ja/parts/status-badge.md +44 -0
  118. package/docs/ja/parts/trend-indicator.md +26 -0
  119. package/docs/ja/routing.md +95 -0
  120. package/docs/ja/ui/accordion.md +37 -0
  121. package/docs/ja/ui/alert.md +31 -0
  122. package/docs/ja/ui/badge.md +23 -0
  123. package/docs/ja/ui/breadcrumb.md +38 -0
  124. package/docs/ja/ui/button.md +39 -0
  125. package/docs/ja/ui/calendar.md +28 -0
  126. package/docs/ja/ui/card.md +35 -0
  127. package/docs/ja/ui/checkbox.md +34 -0
  128. package/docs/ja/ui/cn.md +34 -0
  129. package/docs/ja/ui/collapsible.md +21 -0
  130. package/docs/ja/ui/command.md +36 -0
  131. package/docs/ja/ui/dialog.md +51 -0
  132. package/docs/ja/ui/dropdown-menu.md +50 -0
  133. package/docs/ja/ui/empty.md +22 -0
  134. package/docs/ja/ui/error-state.md +50 -0
  135. package/docs/ja/ui/input-group.md +30 -0
  136. package/docs/ja/ui/input.md +28 -0
  137. package/docs/ja/ui/label.md +19 -0
  138. package/docs/ja/ui/loading.md +19 -0
  139. package/docs/ja/ui/popover.md +34 -0
  140. package/docs/ja/ui/progress.md +28 -0
  141. package/docs/ja/ui/scroll-area.md +24 -0
  142. package/docs/ja/ui/select.md +64 -0
  143. package/docs/ja/ui/separator.md +15 -0
  144. package/docs/ja/ui/sheet.md +28 -0
  145. package/docs/ja/ui/sidebar.md +92 -0
  146. package/docs/ja/ui/skeleton.md +16 -0
  147. package/docs/ja/ui/slider.md +21 -0
  148. package/docs/ja/ui/spinner.md +14 -0
  149. package/docs/ja/ui/switch.md +19 -0
  150. package/docs/ja/ui/table.md +24 -0
  151. package/docs/ja/ui/tabs.md +24 -0
  152. package/docs/ja/ui/textarea.md +15 -0
  153. package/docs/ja/ui/toggle-group.md +27 -0
  154. package/docs/ja/ui/toggle.md +19 -0
  155. package/docs/ja/ui/tooltip.md +22 -0
  156. package/docs/ja/ui/use-is-mobile.md +18 -0
  157. package/docs/ja/ui-and-theming.md +95 -0
  158. package/package.json +29 -4
  159. package/registry/blocks/sales-overview.tsx +43 -19
  160. package/registry/ui/data-table.tsx +702 -102
  161. package/skills/vantage-add-feature/SKILL.md +150 -0
  162. package/skills/vantage-app/SKILL.md +258 -0
  163. package/skills/vantage-pitfalls/SKILL.md +115 -0
  164. package/templates/AGENTS.md +268 -0
  165. package/theme.css +178 -40
  166. package/dist/chunk-73J5ZD4C.js.map +0 -1
  167. package/dist/chunk-ZGDU5YLH.js.map +0 -1
package/dist/cli.js CHANGED
@@ -1,17 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import { PAGE_EXTENSIONS, scanProject, vantagePlugin, generateArtifacts, VANTAGE_DIR, MANIFEST_SCHEMA_VERSION, FORBIDDEN_FILES, API_METHODS, PUBLIC_ENV_PREFIX } from './chunk-ZGDU5YLH.js';
3
- import './chunk-73J5ZD4C.js';
2
+ import { PAGE_EXTENSIONS, scanProject, vantagePlugin, generateArtifacts, VANTAGE_DIR, MANIFEST_SCHEMA_VERSION, FORBIDDEN_FILES, API_METHODS, PUBLIC_ENV_PREFIX } from './chunk-PRFBSQA4.js';
3
+ import './chunk-YLAB6UQS.js';
4
4
  import './chunk-B7LLBNLV.js';
5
5
  import path2 from 'path';
6
- import pc2 from 'picocolors';
6
+ import pc3 from 'picocolors';
7
7
  import fs2 from 'fs';
8
8
  import { createRequire } from 'module';
9
9
  import { loadEnv, createServer, build as build$1 } from 'vite';
10
10
  import { build as build$2 } from 'esbuild';
11
+ import { fileURLToPath } from 'url';
11
12
  import { spawn } from 'child_process';
12
13
 
13
14
  // @squadbase/vantage — generated build. Do not edit.
14
- var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["json", "help", "force", "verbose", "version", "h", "v"]);
15
+ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["json", "help", "force", "verbose", "version", "all", "list", "regex", "h", "v"]);
15
16
  function parseArgs(argv) {
16
17
  const positionals = [];
17
18
  const flags = {};
@@ -43,6 +44,12 @@ function parseArgs(argv) {
43
44
  }
44
45
  return { positionals, flags };
45
46
  }
47
+ function applyApiBaseUrlFlag(args) {
48
+ const value = args.flags["api-base-url"];
49
+ if (typeof value === "string" && value.length) {
50
+ process.env.PUBLIC_API_BASE_URL = value;
51
+ }
52
+ }
46
53
  function parsePort(value, fallback) {
47
54
  if (typeof value === "string") {
48
55
  const n = Number(value);
@@ -68,18 +75,18 @@ function resolveQuickRoot(target) {
68
75
  }
69
76
  var log = {
70
77
  info: (msg) => console.log(msg),
71
- step: (msg) => console.log(pc2.cyan("\u2192 ") + msg),
72
- ok: (msg) => console.log(pc2.green("\u2713 ") + msg),
73
- warn: (msg) => console.log(pc2.yellow("! ") + msg),
74
- error: (msg) => console.error(pc2.red("\u2717 ") + msg),
75
- brand: (msg) => console.log(pc2.bold(pc2.magenta("vantage ")) + msg)
78
+ step: (msg) => console.log(pc3.cyan("\u2192 ") + msg),
79
+ ok: (msg) => console.log(pc3.green("\u2713 ") + msg),
80
+ warn: (msg) => console.log(pc3.yellow("! ") + msg),
81
+ error: (msg) => console.error(pc3.red("\u2717 ") + msg),
82
+ brand: (msg) => console.log(pc3.bold(pc3.magenta("vantage ")) + msg)
76
83
  };
77
84
  function printDiagnostics(diags) {
78
85
  for (const d of diags) {
79
- const badge = d.severity === "error" ? pc2.red(pc2.bold(" ERROR ")) : pc2.yellow(pc2.bold(" WARN "));
80
- console.log(`${badge} ${pc2.dim(d.code)} ${d.message}`);
81
- if (d.files?.length) console.log(` ${pc2.dim("files:")} ${d.files.join(", ")}`);
82
- if (d.fix) console.log(` ${pc2.dim("fix:")} ${d.fix}`);
86
+ const badge = d.severity === "error" ? pc3.red(pc3.bold(" ERROR ")) : pc3.yellow(pc3.bold(" WARN "));
87
+ console.log(`${badge} ${pc3.dim(d.code)} ${d.message}`);
88
+ if (d.files?.length) console.log(` ${pc3.dim("files:")} ${d.files.join(", ")}`);
89
+ if (d.fix) console.log(` ${pc3.dim("fix:")} ${d.fix}`);
83
90
  }
84
91
  }
85
92
  function printJson(payload) {
@@ -128,15 +135,96 @@ export async function GET({ request, params }: ApiContext) {
128
135
  }
129
136
  `;
130
137
  }
131
- function resolveRegistryDir(root) {
138
+ function resolvePackageDir(root, sub) {
132
139
  try {
133
140
  const require2 = createRequire(path2.join(root, "noop.js"));
134
141
  const pkgJson = require2.resolve(`${PKG}/package.json`);
135
- return path2.join(path2.dirname(pkgJson), "registry");
142
+ return path2.join(path2.dirname(pkgJson), sub);
136
143
  } catch {
137
144
  return null;
138
145
  }
139
146
  }
147
+ function resolveRegistryDir(root) {
148
+ return resolvePackageDir(root, "registry");
149
+ }
150
+ function listBundledSkills(skillsDir) {
151
+ try {
152
+ return fs2.readdirSync(skillsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && fs2.existsSync(path2.join(skillsDir, e.name, "SKILL.md"))).map((e) => e.name).sort();
153
+ } catch {
154
+ return [];
155
+ }
156
+ }
157
+ function copySkill(root, skillsDir, name, force) {
158
+ const src = path2.join(skillsDir, name);
159
+ if (!fs2.existsSync(path2.join(src, "SKILL.md"))) {
160
+ const available = listBundledSkills(skillsDir);
161
+ log.error(`Unknown skill "${name}". Available: ${available.join(", ") || "(none)"}`);
162
+ return 1;
163
+ }
164
+ const dest = path2.join(root, ".claude", "skills", name);
165
+ if (fs2.existsSync(dest) && !force) {
166
+ log.error(`${path2.relative(root, dest)} already exists. Use --force to overwrite.`);
167
+ return 1;
168
+ }
169
+ fs2.mkdirSync(path2.dirname(dest), { recursive: true });
170
+ fs2.cpSync(src, dest, { recursive: true, force: true });
171
+ log.ok(`Added skill ${path2.relative(root, dest)}/`);
172
+ return 0;
173
+ }
174
+ function addSkill(root, name, all, force) {
175
+ const skillsDir = resolvePackageDir(root, "skills");
176
+ if (!skillsDir) {
177
+ log.error("Could not resolve the Vantage skills directory.");
178
+ return 1;
179
+ }
180
+ const available = listBundledSkills(skillsDir);
181
+ if (available.length === 0) {
182
+ log.error("No skills are bundled with this version of Vantage.");
183
+ return 1;
184
+ }
185
+ const targets = all ? available : name ? [name] : [];
186
+ if (targets.length === 0) {
187
+ log.error(`Usage: vantage add skill <name>|--all. Available: ${available.join(", ")}`);
188
+ return 1;
189
+ }
190
+ let failed = 0;
191
+ for (const target of targets) {
192
+ if (copySkill(root, skillsDir, target, force) !== 0) failed++;
193
+ }
194
+ return failed === 0 ? 0 : 1;
195
+ }
196
+ var AGENTS_FILE = "AGENTS.md";
197
+ function bundledAgentsPath(root) {
198
+ const dir = resolvePackageDir(root, "templates");
199
+ if (!dir) return null;
200
+ const src = path2.join(dir, AGENTS_FILE);
201
+ return fs2.existsSync(src) ? src : null;
202
+ }
203
+ function addAgents(root, force) {
204
+ const src = bundledAgentsPath(root);
205
+ if (!src) {
206
+ log.error("AGENTS.md is not bundled with this version of Vantage.");
207
+ return 1;
208
+ }
209
+ const dest = path2.join(root, AGENTS_FILE);
210
+ if (fs2.existsSync(dest) && !force) {
211
+ log.error(`${AGENTS_FILE} already exists. Use --force to overwrite.`);
212
+ return 1;
213
+ }
214
+ fs2.copyFileSync(src, dest);
215
+ log.ok(`Added ${path2.relative(root, dest) || AGENTS_FILE}`);
216
+ return 0;
217
+ }
218
+ function syncAgentsFile(root) {
219
+ const dest = path2.join(root, AGENTS_FILE);
220
+ if (!fs2.existsSync(dest)) return "absent";
221
+ const src = bundledAgentsPath(root);
222
+ if (!src) return "unchanged";
223
+ const next = fs2.readFileSync(src, "utf8");
224
+ if (fs2.readFileSync(dest, "utf8") === next) return "unchanged";
225
+ fs2.writeFileSync(dest, next);
226
+ return "updated";
227
+ }
140
228
  function copyFromRegistry(root, kind, name, force) {
141
229
  const registry = resolveRegistryDir(root);
142
230
  if (!registry) {
@@ -165,8 +253,11 @@ async function add(root, args) {
165
253
  const kind = args.positionals[1];
166
254
  const name = args.positionals[2];
167
255
  const force = Boolean(args.flags.force);
256
+ const all = Boolean(args.flags.all);
257
+ if (kind === "skill") return addSkill(root, name, all, force);
258
+ if (kind === "agents") return addAgents(root, force);
168
259
  if (!kind || !name) {
169
- log.error("Usage: vantage add <page|api|ui|block> <name>");
260
+ log.error("Usage: vantage add <page|api|ui|block|skill|agents> <name>");
170
261
  return 1;
171
262
  }
172
263
  if (kind === "page") {
@@ -194,7 +285,7 @@ async function add(root, args) {
194
285
  }
195
286
  if (kind === "ui") return copyFromRegistry(root, "ui", name, force);
196
287
  if (kind === "block") return copyFromRegistry(root, "block", name, force);
197
- log.error(`Unknown add target "${kind}". Use one of: page, api, ui, block.`);
288
+ log.error(`Unknown add target "${kind}". Use one of: page, api, ui, block, skill, agents.`);
198
289
  return 1;
199
290
  }
200
291
  var ALLOWED_ENV_KEYS = /* @__PURE__ */ new Set(["MODE", "DEV", "PROD", "SSR", "BASE_URL", "PUBLIC_"]);
@@ -419,6 +510,7 @@ async function build(root, args) {
419
510
  return 1;
420
511
  }
421
512
  const mode = "production";
513
+ applyApiBaseUrlFlag(args);
422
514
  const env = { ...process.env, ...loadEnv(mode, root, "") };
423
515
  const quiet = Boolean(args.flags.json);
424
516
  if (!quiet) log.step("Building client\u2026");
@@ -522,6 +614,7 @@ async function dev(root, args) {
522
614
  return 1;
523
615
  }
524
616
  const mode = "development";
617
+ applyApiBaseUrlFlag(args);
525
618
  const env = { ...process.env, ...loadEnv(mode, root, "") };
526
619
  const port = parsePort(args.flags.port, 5173);
527
620
  const server = await createServer({
@@ -545,6 +638,158 @@ async function dev(root, args) {
545
638
  return new Promise(() => {
546
639
  });
547
640
  }
641
+ var SUPPORTED_SCHEMA_VERSION = 1;
642
+ var DOC_LANGS = ["ja", "en"];
643
+ var DEFAULT_DOC_LANG = "ja";
644
+ function isDocLang(value) {
645
+ return typeof value === "string" && DOC_LANGS.includes(value);
646
+ }
647
+ function docsDir() {
648
+ return fileURLToPath(new URL("../docs/", import.meta.url));
649
+ }
650
+ function loadCatalog() {
651
+ try {
652
+ const raw = fs2.readFileSync(path2.join(docsDir(), "index.json"), "utf8");
653
+ const parsed = JSON.parse(raw);
654
+ if (parsed.schemaVersion !== SUPPORTED_SCHEMA_VERSION) return null;
655
+ return Array.isArray(parsed.docs) ? parsed.docs : null;
656
+ } catch {
657
+ return null;
658
+ }
659
+ }
660
+ function docsForLang(catalog, lang) {
661
+ return catalog.filter((doc) => doc.lang === lang);
662
+ }
663
+ function readDoc(entry) {
664
+ return fs2.readFileSync(path2.join(docsDir(), entry.file), "utf8");
665
+ }
666
+ function resolveDoc(entries, query) {
667
+ const needle = query.toLowerCase().replace(/^\/+|\/+$/g, "").replace(/\.mdx?$/, "");
668
+ const exact = entries.filter((doc) => doc.slug.toLowerCase() === needle);
669
+ if (exact.length === 1) return { kind: "found", doc: exact[0] };
670
+ const byLeaf = entries.filter((doc) => (doc.slug.split("/").pop() ?? "").toLowerCase() === needle);
671
+ if (byLeaf.length === 1) return { kind: "found", doc: byLeaf[0] };
672
+ if (byLeaf.length > 1) return { kind: "ambiguous", matches: byLeaf };
673
+ const partial = entries.filter(
674
+ (doc) => doc.slug.toLowerCase().includes(needle) || doc.title.toLowerCase().includes(needle)
675
+ );
676
+ return { kind: "missing", suggestions: partial };
677
+ }
678
+ function groupBySection(entries) {
679
+ const groups = [];
680
+ for (const doc of entries) {
681
+ const last = groups[groups.length - 1];
682
+ if (last && last.section === doc.section) last.docs.push(doc);
683
+ else groups.push({ section: doc.section, title: doc.sectionTitle, docs: [doc] });
684
+ }
685
+ return groups;
686
+ }
687
+
688
+ // src/cli/docs.ts
689
+ function paint(markdown) {
690
+ if (!process.stdout.isTTY) return markdown;
691
+ let inFence = false;
692
+ return markdown.split("\n").map((line) => {
693
+ if (/^\s*(```|~~~)/.test(line)) {
694
+ inFence = !inFence;
695
+ return pc3.dim(line);
696
+ }
697
+ if (inFence) return line;
698
+ if (/^#{1,6}\s/.test(line)) return pc3.bold(pc3.magenta(line));
699
+ if (/^>\s?/.test(line)) return pc3.dim(line);
700
+ return line;
701
+ }).join("\n");
702
+ }
703
+ function printList(entries) {
704
+ const width = Math.max(...entries.map((doc) => doc.slug.length), 0);
705
+ for (const group of groupBySection(entries)) {
706
+ console.log("");
707
+ console.log(pc3.bold(group.title));
708
+ for (const doc of group.docs) {
709
+ const slug = doc.slug.padEnd(width);
710
+ console.log(` ${pc3.cyan(slug)} ${doc.description || doc.title}`);
711
+ }
712
+ }
713
+ console.log("");
714
+ console.log(pc3.dim("vantage docs <name> show one page --json machine-readable"));
715
+ console.log(pc3.dim("vantage docs --all show every page --lang ja | en"));
716
+ }
717
+ function toJson(doc, content) {
718
+ return {
719
+ slug: doc.slug,
720
+ lang: doc.lang,
721
+ title: doc.title,
722
+ description: doc.description,
723
+ section: doc.section,
724
+ sectionTitle: doc.sectionTitle,
725
+ content
726
+ };
727
+ }
728
+ async function docs(_root, args) {
729
+ const catalog = loadCatalog();
730
+ if (!catalog) {
731
+ log.error("The bundled documentation is missing. Reinstall @squadbase/vantage, or run `pnpm build` in the framework repo.");
732
+ return 1;
733
+ }
734
+ const langFlag = args.flags.lang;
735
+ if (langFlag !== void 0 && !isDocLang(langFlag)) {
736
+ log.error(`Unknown --lang "${String(langFlag)}". Available: ${DOC_LANGS.join(", ")}`);
737
+ return 1;
738
+ }
739
+ const lang = isDocLang(langFlag) ? langFlag : DEFAULT_DOC_LANG;
740
+ const entries = docsForLang(catalog, lang);
741
+ if (entries.length === 0) {
742
+ log.error(`No documentation bundled for "${lang}".`);
743
+ return 1;
744
+ }
745
+ const json = Boolean(args.flags.json);
746
+ const name = args.positionals[1];
747
+ if (args.flags.all) {
748
+ const pages = entries.map((doc) => ({ doc, content: readDoc(doc) }));
749
+ if (json) {
750
+ printJson({ lang, docs: pages.map(({ doc, content: content2 }) => toJson(doc, content2)) });
751
+ return 0;
752
+ }
753
+ process.stdout.write(pages.map(({ content: content2 }) => content2.trimEnd()).join("\n\n---\n\n") + "\n");
754
+ return 0;
755
+ }
756
+ if (!name || args.flags.list) {
757
+ if (json) {
758
+ printJson({
759
+ lang,
760
+ docs: entries.map(({ slug, title, description, section, sectionTitle }) => ({
761
+ slug,
762
+ title,
763
+ description,
764
+ section,
765
+ sectionTitle
766
+ }))
767
+ });
768
+ return 0;
769
+ }
770
+ printList(entries);
771
+ return 0;
772
+ }
773
+ const found = resolveDoc(entries, name);
774
+ if (found.kind === "ambiguous") {
775
+ log.error(`"${name}" matches several pages: ${found.matches.map((d) => d.slug).join(", ")}`);
776
+ return 1;
777
+ }
778
+ if (found.kind === "missing") {
779
+ const suggestions = found.suggestions.map((d) => d.slug);
780
+ log.error(
781
+ suggestions.length ? `No page named "${name}". Did you mean: ${suggestions.slice(0, 8).join(", ")}?` : `No page named "${name}". Run \`vantage docs\` to list every page.`
782
+ );
783
+ return 1;
784
+ }
785
+ const content = readDoc(found.doc);
786
+ if (json) {
787
+ printJson(toJson(found.doc, content));
788
+ return 0;
789
+ }
790
+ process.stdout.write(paint(content.trimEnd()) + "\n");
791
+ return 0;
792
+ }
548
793
  async function doctor(root, args) {
549
794
  const facets = [];
550
795
  const nodeMajor = Number(process.versions.node.split(".")[0]);
@@ -639,67 +884,390 @@ async function routes(root, args) {
639
884
  });
640
885
  return 0;
641
886
  }
642
- console.log(pc2.bold("\nPages"));
643
- if (model.pages.length === 0) console.log(pc2.dim(" (none)"));
887
+ console.log(pc3.bold("\nPages"));
888
+ if (model.pages.length === 0) console.log(pc3.dim(" (none)"));
644
889
  for (const p of model.pages) {
645
- console.log(` ${pc2.green(p.routePath.padEnd(28))} ${pc2.dim(p.file)}`);
890
+ console.log(` ${pc3.green(p.routePath.padEnd(28))} ${pc3.dim(p.file)}`);
646
891
  }
647
892
  if (model.layouts.length || model.notFound || model.error) {
648
- console.log(pc2.bold("\nSpecial"));
893
+ console.log(pc3.bold("\nSpecial"));
649
894
  for (const l of model.layouts) {
650
- console.log(` ${pc2.cyan(("layout " + (l.dir === "" ? "/" : "/" + l.dir)).padEnd(28))} ${pc2.dim(l.file)}`);
895
+ console.log(` ${pc3.cyan(("layout " + (l.dir === "" ? "/" : "/" + l.dir)).padEnd(28))} ${pc3.dim(l.file)}`);
651
896
  }
652
- if (model.notFound) console.log(` ${pc2.cyan("404".padEnd(28))} ${pc2.dim(model.notFound)}`);
653
- if (model.error) console.log(` ${pc2.cyan("error".padEnd(28))} ${pc2.dim(model.error)}`);
897
+ if (model.notFound) console.log(` ${pc3.cyan("404".padEnd(28))} ${pc3.dim(model.notFound)}`);
898
+ if (model.error) console.log(` ${pc3.cyan("error".padEnd(28))} ${pc3.dim(model.error)}`);
654
899
  }
655
900
  if (model.hasServer) {
656
- console.log(pc2.bold("\nAPI"));
657
- if (model.apis.length === 0) console.log(pc2.dim(" (none)"));
901
+ console.log(pc3.bold("\nAPI"));
902
+ if (model.apis.length === 0) console.log(pc3.dim(" (none)"));
658
903
  for (const a of model.apis) {
659
- console.log(` ${pc2.yellow(a.routePath.padEnd(28))} ${pc2.dim(a.file)}`);
904
+ console.log(` ${pc3.yellow(a.routePath.padEnd(28))} ${pc3.dim(a.file)}`);
905
+ }
906
+ }
907
+ console.log("");
908
+ return 0;
909
+ }
910
+
911
+ // src/cli/search-index.ts
912
+ var FIELD_WEIGHTS = { slug: 3, title: 3, description: 2, body: 1 };
913
+ var K1 = 1.2;
914
+ var B = 0.75;
915
+ var TOKEN_RE = /[a-z0-9]+|[぀-ヿ㐀-䶿一-鿿]+/g;
916
+ var LATIN_RE = /^[a-z0-9]+$/;
917
+ var TOKEN_RE_ANYCASE = /[a-zA-Z0-9]+|[぀-ヿ㐀-䶿一-鿿]+/g;
918
+ var CJK_RE = /[぀-ヿ㐀-䶿一-鿿]/;
919
+ var SCRIPT_RE = /[ぁ-ゟ]+|[゠-ヿ]+|[㐀-䶿一-鿿]+/g;
920
+ var HIRAGANA_RE = /^[ぁ-ゟ]$/;
921
+ function singular(word) {
922
+ if (word.length >= 5 && word.endsWith("ies")) return `${word.slice(0, -3)}y`;
923
+ if (word.length >= 4 && word.endsWith("s") && !/(ss|us|is)$/.test(word)) return word.slice(0, -1);
924
+ return word;
925
+ }
926
+ function tokenize(text) {
927
+ const normalized = text.normalize("NFKC").replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase();
928
+ const tokens = [];
929
+ for (const match of normalized.matchAll(TOKEN_RE)) {
930
+ const run = match[0];
931
+ if (LATIN_RE.test(run)) {
932
+ tokens.push(singular(run));
933
+ continue;
934
+ }
935
+ for (const segment of run.match(SCRIPT_RE) ?? []) {
936
+ if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue;
937
+ if (segment.length <= 2) {
938
+ tokens.push(segment);
939
+ continue;
940
+ }
941
+ tokens.push(segment);
942
+ for (let i = 0; i < segment.length - 1; i++) tokens.push(segment.slice(i, i + 2));
943
+ }
944
+ }
945
+ return tokens;
946
+ }
947
+ function queryPhrases(query) {
948
+ const phrases = [];
949
+ for (const match of query.normalize("NFKC").matchAll(TOKEN_RE_ANYCASE)) {
950
+ const run = match[0];
951
+ if (!CJK_RE.test(run)) {
952
+ phrases.push(run);
953
+ continue;
954
+ }
955
+ for (const segment of run.match(SCRIPT_RE) ?? []) {
956
+ if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue;
957
+ phrases.push(segment);
958
+ }
959
+ }
960
+ return [...new Set(phrases)];
961
+ }
962
+ function buildIndex(entries) {
963
+ const docs2 = entries.map((entry) => {
964
+ const body = readDoc(entry);
965
+ const tf = /* @__PURE__ */ new Map();
966
+ let length = 0;
967
+ const add2 = (text, weight) => {
968
+ for (const token of tokenize(text)) {
969
+ tf.set(token, (tf.get(token) ?? 0) + weight);
970
+ length += weight;
971
+ }
972
+ };
973
+ add2(entry.slug, FIELD_WEIGHTS.slug);
974
+ add2(entry.title, FIELD_WEIGHTS.title);
975
+ add2(entry.description, FIELD_WEIGHTS.description);
976
+ add2(body, FIELD_WEIGHTS.body);
977
+ return { entry, body, tf, length };
978
+ });
979
+ const df = /* @__PURE__ */ new Map();
980
+ for (const doc of docs2) {
981
+ for (const term of doc.tf.keys()) df.set(term, (df.get(term) ?? 0) + 1);
982
+ }
983
+ const total = docs2.length;
984
+ const avgLength = total ? docs2.reduce((sum, doc) => sum + doc.length, 0) / total : 1;
985
+ return {
986
+ search(query) {
987
+ const terms = [...new Set(tokenize(query))];
988
+ if (terms.length === 0) return [];
989
+ const hits = [];
990
+ for (const doc of docs2) {
991
+ let score = 0;
992
+ for (const term of terms) {
993
+ const tf = doc.tf.get(term);
994
+ if (!tf) continue;
995
+ const n = df.get(term) ?? 0;
996
+ const idf = Math.log(1 + (total - n + 0.5) / (n + 0.5));
997
+ const norm = 1 - B + B * doc.length / avgLength;
998
+ score += idf * (tf * (K1 + 1) / (tf + K1 * norm));
999
+ }
1000
+ if (score > 0) hits.push({ entry: doc.entry, score, terms, body: doc.body });
1001
+ }
1002
+ hits.sort((a, b) => b.score - a.score || a.entry.slug.localeCompare(b.entry.slug));
1003
+ return hits;
1004
+ }
1005
+ };
1006
+ }
1007
+ var SNIPPET_LENGTH = 150;
1008
+ function snippet(body, terms, length = SNIPPET_LENGTH) {
1009
+ let best = "";
1010
+ let bestHits = 0;
1011
+ let bestIndex = 0;
1012
+ let bestIsHeading = true;
1013
+ for (const raw of body.split("\n").slice(1)) {
1014
+ const line = raw.replace(/^\s*[-*]\s+/, "").replace(/\s+/g, " ").trim();
1015
+ if (!line || /^(```|~~~|\|\s*-{2,})/.test(line)) continue;
1016
+ const haystack = line.toLowerCase();
1017
+ const heading = line.startsWith("#");
1018
+ let hits = 0;
1019
+ let first = -1;
1020
+ for (const term of terms) {
1021
+ const at = haystack.indexOf(term);
1022
+ if (at === -1) continue;
1023
+ hits++;
1024
+ if (first === -1 || at < first) first = at;
660
1025
  }
1026
+ if (hits > bestHits || hits === bestHits && hits > 0 && bestIsHeading && !heading) {
1027
+ best = line;
1028
+ bestHits = hits;
1029
+ bestIndex = first;
1030
+ bestIsHeading = heading;
1031
+ }
1032
+ }
1033
+ if (!bestHits) return "";
1034
+ if (best.length <= length) return best;
1035
+ const start = Math.max(0, bestIndex - Math.floor(length / 4));
1036
+ const text = best.slice(start, start + length).trim();
1037
+ return `${start > 0 ? "\u2026" : ""}${text}${start + length < best.length ? "\u2026" : ""}`;
1038
+ }
1039
+
1040
+ // src/cli/search.ts
1041
+ var DEFAULT_LIMIT = 10;
1042
+ var MAX_REGEX_LINES = 3;
1043
+ function parseLimit(value, fallback) {
1044
+ if (typeof value === "string") {
1045
+ const n = Number(value);
1046
+ if (Number.isInteger(n) && n > 0) return n;
1047
+ }
1048
+ return fallback;
1049
+ }
1050
+ function escapeRegExp(value) {
1051
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1052
+ }
1053
+ function paintMatches(text, re) {
1054
+ if (!process.stdout.isTTY) return text;
1055
+ let out = "";
1056
+ let last = 0;
1057
+ for (const match of text.matchAll(re)) {
1058
+ const at = match.index ?? 0;
1059
+ if (!match[0]) continue;
1060
+ out += pc3.dim(text.slice(last, at)) + pc3.yellow(match[0]);
1061
+ last = at + match[0].length;
661
1062
  }
1063
+ return out + pc3.dim(text.slice(last));
1064
+ }
1065
+ function paintTerms(text, words) {
1066
+ if (!process.stdout.isTTY) return text;
1067
+ if (words.length === 0) return pc3.dim(text);
1068
+ return paintMatches(text, new RegExp(words.map(escapeRegExp).join("|"), "gi"));
1069
+ }
1070
+ function header(count, query, lang, mode) {
1071
+ const label = `${count} result${count === 1 ? "" : "s"} for "${query}"`;
1072
+ console.log("");
1073
+ console.log(pc3.bold(label) + pc3.dim(` ${lang} \xB7 ${mode}`));
662
1074
  console.log("");
1075
+ }
1076
+ function footer(total, shown, lines) {
1077
+ if (total > shown) {
1078
+ console.log("");
1079
+ console.log(pc3.dim(` ${total - shown} more \u2014 raise --limit to see them`));
1080
+ }
1081
+ console.log("");
1082
+ for (const line of lines) console.log(pc3.dim(line));
1083
+ }
1084
+ function noResults(query) {
1085
+ log.warn(`Nothing matches "${query}".`);
1086
+ console.log(pc3.dim(" Try fewer or more general words, or run `vantage docs --list` to browse every page."));
1087
+ }
1088
+ function meta(entry) {
1089
+ return {
1090
+ slug: entry.slug,
1091
+ title: entry.title,
1092
+ description: entry.description,
1093
+ section: entry.section,
1094
+ sectionTitle: entry.sectionTitle,
1095
+ command: `vantage docs ${entry.slug}`
1096
+ };
1097
+ }
1098
+ function runRanked(entries, query, lang, limit, json) {
1099
+ const hits = buildIndex(entries).search(query);
1100
+ const shown = hits.slice(0, limit);
1101
+ const passage = (hit) => snippet(hit.body, hit.terms);
1102
+ if (json) {
1103
+ printJson({
1104
+ query,
1105
+ mode: "bm25",
1106
+ lang,
1107
+ count: hits.length,
1108
+ results: shown.map((hit) => ({
1109
+ ...meta(hit.entry),
1110
+ score: Math.round(hit.score * 1e3) / 1e3,
1111
+ snippet: passage(hit)
1112
+ }))
1113
+ });
1114
+ return 0;
1115
+ }
1116
+ if (hits.length === 0) {
1117
+ noResults(query);
1118
+ return 0;
1119
+ }
1120
+ const words = queryPhrases(query);
1121
+ const width = Math.max(...shown.map((hit) => hit.entry.slug.length));
1122
+ header(hits.length, query, lang, "bm25");
1123
+ for (const hit of shown) {
1124
+ const title = `${hit.entry.title}${pc3.dim(` \xB7 ${hit.entry.sectionTitle}`)}`;
1125
+ console.log(` ${pc3.cyan(hit.entry.slug.padEnd(width))} ${title}`);
1126
+ const text = passage(hit);
1127
+ if (text) console.log(` ${" ".repeat(width)} ${paintTerms(text, words)}`);
1128
+ }
1129
+ footer(hits.length, shown.length, [
1130
+ "vantage docs <name> open one result --regex treat the query as a regular expression",
1131
+ "vantage search --json machine-readable --limit max results (default 10)"
1132
+ ]);
663
1133
  return 0;
664
1134
  }
1135
+ function runRegex(entries, query, lang, limit, json) {
1136
+ let scan;
1137
+ let probe;
1138
+ try {
1139
+ scan = new RegExp(query, "gi");
1140
+ probe = new RegExp(query, "i");
1141
+ } catch (err) {
1142
+ log.error(err instanceof Error ? err.message : `Invalid regular expression: ${String(err)}`);
1143
+ return 1;
1144
+ }
1145
+ const results = [];
1146
+ for (const entry of entries) {
1147
+ const lines = readDoc(entry).split("\n");
1148
+ const matches = [];
1149
+ let matchCount = 0;
1150
+ for (let i = 0; i < lines.length; i++) {
1151
+ const found = [...lines[i].matchAll(scan)];
1152
+ if (found.length === 0) continue;
1153
+ matchCount += found.length;
1154
+ if (matches.length < MAX_REGEX_LINES) {
1155
+ matches.push({ line: i + 1, text: lines[i].replace(/\s+/g, " ").trim() });
1156
+ }
1157
+ }
1158
+ const inMeta = probe.test(entry.slug) || probe.test(entry.title) || probe.test(entry.description);
1159
+ if (matchCount === 0 && !inMeta) continue;
1160
+ results.push({ entry, matchCount, matches });
1161
+ }
1162
+ results.sort((a, b) => b.matchCount - a.matchCount);
1163
+ const shown = results.slice(0, limit);
1164
+ if (json) {
1165
+ printJson({
1166
+ query,
1167
+ mode: "regex",
1168
+ lang,
1169
+ count: results.length,
1170
+ results: shown.map((result) => ({
1171
+ ...meta(result.entry),
1172
+ matchCount: result.matchCount,
1173
+ matches: result.matches
1174
+ }))
1175
+ });
1176
+ return 0;
1177
+ }
1178
+ if (results.length === 0) {
1179
+ noResults(query);
1180
+ return 0;
1181
+ }
1182
+ header(results.length, query, lang, "regex");
1183
+ for (const result of shown) {
1184
+ const count = pc3.dim(
1185
+ result.matchCount ? ` ${result.matchCount} match${result.matchCount === 1 ? "" : "es"}` : " name match"
1186
+ );
1187
+ console.log(` ${pc3.cyan(result.entry.slug)} ${result.entry.title}${count}`);
1188
+ for (const match of result.matches) {
1189
+ console.log(` ${pc3.dim(String(match.line).padStart(4))} ${paintMatches(match.text, scan)}`);
1190
+ }
1191
+ }
1192
+ footer(results.length, shown.length, [
1193
+ "vantage docs <name> open one result --limit max results (default 10)",
1194
+ "vantage search --json machine-readable --lang ja | en"
1195
+ ]);
1196
+ return 0;
1197
+ }
1198
+ async function search(_root, args) {
1199
+ const query = args.positionals.slice(1).join(" ").trim();
1200
+ if (!query) {
1201
+ log.error("Usage: vantage search <query> [--regex] [--limit <n>] [--lang ja|en] [--json]");
1202
+ return 1;
1203
+ }
1204
+ const catalog = loadCatalog();
1205
+ if (!catalog) {
1206
+ log.error("The bundled documentation is missing. Reinstall @squadbase/vantage, or run `pnpm build` in the framework repo.");
1207
+ return 1;
1208
+ }
1209
+ const langFlag = args.flags.lang;
1210
+ if (langFlag !== void 0 && !isDocLang(langFlag)) {
1211
+ log.error(`Unknown --lang "${String(langFlag)}". Available: ${DOC_LANGS.join(", ")}`);
1212
+ return 1;
1213
+ }
1214
+ const lang = isDocLang(langFlag) ? langFlag : DEFAULT_DOC_LANG;
1215
+ const entries = docsForLang(catalog, lang);
1216
+ if (entries.length === 0) {
1217
+ log.error(`No documentation bundled for "${lang}".`);
1218
+ return 1;
1219
+ }
1220
+ const limit = parseLimit(args.flags.limit, DEFAULT_LIMIT);
1221
+ const json = Boolean(args.flags.json);
1222
+ return args.flags.regex ? runRegex(entries, query, lang, limit, json) : runRanked(entries, query, lang, limit, json);
1223
+ }
665
1224
 
666
1225
  // src/cli/upgrade.ts
667
1226
  async function upgrade(root, args) {
668
1227
  const version = frameworkVersion();
669
1228
  const model = scanProject(root);
670
1229
  generateArtifacts({ root, model });
1230
+ const agents = syncAgentsFile(root);
671
1231
  if (args.flags.json) {
672
- printJson({ ok: true, version, transforms: [], regenerated: true });
1232
+ printJson({ ok: true, version, transforms: [], regenerated: true, agentsSynced: agents === "updated" });
673
1233
  return 0;
674
1234
  }
675
1235
  log.brand(`upgrade \u2192 v${version}`);
676
1236
  log.ok("Regenerated .vantage artifacts.");
1237
+ if (agents === "updated") log.ok("Synced AGENTS.md from the framework.");
677
1238
  log.info("No breaking code transforms required for this version.");
678
1239
  return 0;
679
1240
  }
680
1241
 
681
1242
  // src/cli.ts
682
- var HELP = `${pc2.bold(pc2.magenta("vantage"))} \u2014 data dashboard framework for Squadbase
1243
+ var HELP = `${pc3.bold(pc3.magenta("vantage"))} \u2014 data dashboard framework for Squadbase
683
1244
 
684
- ${pc2.bold("Usage")}
1245
+ ${pc3.bold("Usage")}
685
1246
  vantage <command> [path] [options]
686
1247
  vantage <path> Quick dev shortcut (folder or entry file)
687
1248
 
688
- ${pc2.bold("Commands")}
1249
+ ${pc3.bold("Commands")}
689
1250
  dev Start the dev server (HMR + optional API)
690
1251
  build Build client and optional server into dist/
691
1252
  preview Run the production build locally
692
1253
  check Static verification (routes, boundaries, forbidden files)
693
1254
  routes Show page and API URL map
694
- add <kind> <name> Scaffold a page | api | ui | block
1255
+ add <kind> <name> Scaffold a page | api | ui | block | skill | agents
1256
+ docs [name] Show the bundled guide and component reference
1257
+ search <query> Find components and docs by meaning, or by regex
695
1258
  doctor Environment and installation health checks
696
- upgrade Regenerate artifacts / apply migrations
1259
+ upgrade Regenerate artifacts, sync AGENTS.md / apply migrations
697
1260
 
698
- ${pc2.bold("Options")}
699
- --json Machine-readable output (check, routes, doctor, build)
1261
+ ${pc3.bold("Options")}
1262
+ --json Machine-readable output (check, routes, doctor, build, docs, search)
700
1263
  --port <n> Port for dev/preview
701
1264
  --root <dir> Project root (default: cwd)
702
1265
  --force Overwrite when scaffolding
1266
+ --list List pages without showing one (docs)
1267
+ --lang <ja|en> Documentation language (docs, search, default: ja)
1268
+ --regex Treat the query as a regular expression (search)
1269
+ --limit <n> Max results (search, default: 10)
1270
+ --all Add every bundled skill (add skill --all) | show every page (docs)
703
1271
  -v, --version Print version
704
1272
  -h, --help Print this help
705
1273
  `;
@@ -710,9 +1278,12 @@ var COMMANDS = {
710
1278
  check,
711
1279
  routes,
712
1280
  add,
1281
+ docs,
1282
+ search,
713
1283
  doctor,
714
1284
  upgrade
715
1285
  };
1286
+ var NO_ROOT_POSITIONAL = /* @__PURE__ */ new Set(["add", "docs", "search"]);
716
1287
  async function main() {
717
1288
  const args = parseArgs(process.argv.slice(2));
718
1289
  const command = args.positionals[0];
@@ -727,7 +1298,7 @@ async function main() {
727
1298
  let runFn = COMMANDS[command];
728
1299
  let root;
729
1300
  if (runFn) {
730
- const targetArg = command !== "add" ? args.positionals[1] : void 0;
1301
+ const targetArg = !NO_ROOT_POSITIONAL.has(command) ? args.positionals[1] : void 0;
731
1302
  if (targetArg !== void 0) {
732
1303
  const quick = resolveQuickRoot(targetArg);
733
1304
  if (!quick) {