@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.
- package/README.md +21 -4
- package/dist/chunk-A2UUGASH.js +12 -0
- package/dist/chunk-A2UUGASH.js.map +1 -0
- package/dist/{chunk-ZGDU5YLH.js → chunk-PRFBSQA4.js} +9 -5
- package/dist/chunk-PRFBSQA4.js.map +1 -0
- package/dist/chunk-WQZYXXQW.js +2249 -0
- package/dist/chunk-WQZYXXQW.js.map +1 -0
- package/dist/{chunk-73J5ZD4C.js → chunk-YLAB6UQS.js} +17 -3
- package/dist/chunk-YLAB6UQS.js.map +1 -0
- package/dist/cli.js +607 -36
- package/dist/cli.js.map +1 -1
- package/dist/components/index.d.ts +554 -0
- package/dist/components/index.js +1983 -0
- package/dist/components/index.js.map +1 -0
- package/dist/markdown/index.d.ts +9 -0
- package/dist/markdown/index.js +26 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/query/index.d.ts +27 -1
- package/dist/query/index.js +18 -0
- package/dist/query/index.js.map +1 -1
- package/dist/server/node.js +6 -1
- package/dist/server/node.js.map +1 -1
- package/dist/ui/index.d.ts +316 -200
- package/dist/ui/index.js +566 -511
- package/dist/ui/index.js.map +1 -1
- package/dist/vite/index.js +2 -2
- package/docs/en/agent-skills.md +89 -0
- package/docs/en/api-and-server.md +84 -0
- package/docs/en/build-and-deploy.md +280 -0
- package/docs/en/cli-reference.md +311 -0
- package/docs/en/components.md +233 -0
- package/docs/en/data-fetching.md +78 -0
- package/docs/en/environment-variables.md +69 -0
- package/docs/en/getting-started.md +95 -0
- package/docs/en/index.md +65 -0
- package/docs/en/markdown/markdown-renderer.md +44 -0
- package/docs/en/pages-and-metadata.md +56 -0
- package/docs/en/parts/app-shell.md +54 -0
- package/docs/en/parts/dashboard-card.md +64 -0
- package/docs/en/parts/data-table.md +86 -0
- package/docs/en/parts/date-range-picker.md +41 -0
- package/docs/en/parts/echart.md +53 -0
- package/docs/en/parts/filter-bar.md +66 -0
- package/docs/en/parts/funnel-steps.md +33 -0
- package/docs/en/parts/metric-value.md +23 -0
- package/docs/en/parts/multi-select.md +27 -0
- package/docs/en/parts/page-shell.md +45 -0
- package/docs/en/parts/searchable-select.md +47 -0
- package/docs/en/parts/section-header.md +20 -0
- package/docs/en/parts/segmented-control.md +25 -0
- package/docs/en/parts/status-badge.md +44 -0
- package/docs/en/parts/trend-indicator.md +26 -0
- package/docs/en/routing.md +95 -0
- package/docs/en/ui/accordion.md +36 -0
- package/docs/en/ui/alert.md +31 -0
- package/docs/en/ui/badge.md +23 -0
- package/docs/en/ui/breadcrumb.md +38 -0
- package/docs/en/ui/button.md +39 -0
- package/docs/en/ui/calendar.md +28 -0
- package/docs/en/ui/card.md +35 -0
- package/docs/en/ui/checkbox.md +34 -0
- package/docs/en/ui/cn.md +34 -0
- package/docs/en/ui/collapsible.md +21 -0
- package/docs/en/ui/command.md +37 -0
- package/docs/en/ui/dialog.md +52 -0
- package/docs/en/ui/dropdown-menu.md +50 -0
- package/docs/en/ui/empty.md +22 -0
- package/docs/en/ui/error-state.md +50 -0
- package/docs/en/ui/input-group.md +30 -0
- package/docs/en/ui/input.md +28 -0
- package/docs/en/ui/label.md +19 -0
- package/docs/en/ui/loading.md +19 -0
- package/docs/en/ui/popover.md +34 -0
- package/docs/en/ui/progress.md +28 -0
- package/docs/en/ui/scroll-area.md +23 -0
- package/docs/en/ui/select.md +63 -0
- package/docs/en/ui/separator.md +15 -0
- package/docs/en/ui/sheet.md +28 -0
- package/docs/en/ui/sidebar.md +92 -0
- package/docs/en/ui/skeleton.md +16 -0
- package/docs/en/ui/slider.md +21 -0
- package/docs/en/ui/spinner.md +14 -0
- package/docs/en/ui/switch.md +19 -0
- package/docs/en/ui/table.md +24 -0
- package/docs/en/ui/tabs.md +23 -0
- package/docs/en/ui/textarea.md +15 -0
- package/docs/en/ui/toggle-group.md +26 -0
- package/docs/en/ui/toggle.md +19 -0
- package/docs/en/ui/tooltip.md +22 -0
- package/docs/en/ui/use-is-mobile.md +18 -0
- package/docs/en/ui-and-theming.md +95 -0
- package/docs/index.json +1306 -0
- package/docs/ja/agent-skills.md +87 -0
- package/docs/ja/api-and-server.md +84 -0
- package/docs/ja/build-and-deploy.md +279 -0
- package/docs/ja/cli-reference.md +305 -0
- package/docs/ja/components.md +229 -0
- package/docs/ja/data-fetching.md +78 -0
- package/docs/ja/environment-variables.md +68 -0
- package/docs/ja/getting-started.md +95 -0
- package/docs/ja/index.md +65 -0
- package/docs/ja/markdown/markdown-renderer.md +43 -0
- package/docs/ja/pages-and-metadata.md +56 -0
- package/docs/ja/parts/app-shell.md +54 -0
- package/docs/ja/parts/dashboard-card.md +64 -0
- package/docs/ja/parts/data-table.md +85 -0
- package/docs/ja/parts/date-range-picker.md +41 -0
- package/docs/ja/parts/echart.md +52 -0
- package/docs/ja/parts/filter-bar.md +64 -0
- package/docs/ja/parts/funnel-steps.md +33 -0
- package/docs/ja/parts/metric-value.md +25 -0
- package/docs/ja/parts/multi-select.md +27 -0
- package/docs/ja/parts/page-shell.md +45 -0
- package/docs/ja/parts/searchable-select.md +47 -0
- package/docs/ja/parts/section-header.md +20 -0
- package/docs/ja/parts/segmented-control.md +26 -0
- package/docs/ja/parts/status-badge.md +44 -0
- package/docs/ja/parts/trend-indicator.md +26 -0
- package/docs/ja/routing.md +95 -0
- package/docs/ja/ui/accordion.md +37 -0
- package/docs/ja/ui/alert.md +31 -0
- package/docs/ja/ui/badge.md +23 -0
- package/docs/ja/ui/breadcrumb.md +38 -0
- package/docs/ja/ui/button.md +39 -0
- package/docs/ja/ui/calendar.md +28 -0
- package/docs/ja/ui/card.md +35 -0
- package/docs/ja/ui/checkbox.md +34 -0
- package/docs/ja/ui/cn.md +34 -0
- package/docs/ja/ui/collapsible.md +21 -0
- package/docs/ja/ui/command.md +36 -0
- package/docs/ja/ui/dialog.md +51 -0
- package/docs/ja/ui/dropdown-menu.md +50 -0
- package/docs/ja/ui/empty.md +22 -0
- package/docs/ja/ui/error-state.md +50 -0
- package/docs/ja/ui/input-group.md +30 -0
- package/docs/ja/ui/input.md +28 -0
- package/docs/ja/ui/label.md +19 -0
- package/docs/ja/ui/loading.md +19 -0
- package/docs/ja/ui/popover.md +34 -0
- package/docs/ja/ui/progress.md +28 -0
- package/docs/ja/ui/scroll-area.md +24 -0
- package/docs/ja/ui/select.md +64 -0
- package/docs/ja/ui/separator.md +15 -0
- package/docs/ja/ui/sheet.md +28 -0
- package/docs/ja/ui/sidebar.md +92 -0
- package/docs/ja/ui/skeleton.md +16 -0
- package/docs/ja/ui/slider.md +21 -0
- package/docs/ja/ui/spinner.md +14 -0
- package/docs/ja/ui/switch.md +19 -0
- package/docs/ja/ui/table.md +24 -0
- package/docs/ja/ui/tabs.md +24 -0
- package/docs/ja/ui/textarea.md +15 -0
- package/docs/ja/ui/toggle-group.md +27 -0
- package/docs/ja/ui/toggle.md +19 -0
- package/docs/ja/ui/tooltip.md +22 -0
- package/docs/ja/ui/use-is-mobile.md +18 -0
- package/docs/ja/ui-and-theming.md +95 -0
- package/package.json +29 -4
- package/registry/blocks/sales-overview.tsx +43 -19
- package/registry/ui/data-table.tsx +702 -102
- package/skills/vantage-add-feature/SKILL.md +150 -0
- package/skills/vantage-app/SKILL.md +258 -0
- package/skills/vantage-pitfalls/SKILL.md +115 -0
- package/templates/AGENTS.md +268 -0
- package/theme.css +178 -40
- package/dist/chunk-73J5ZD4C.js.map +0 -1
- 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-
|
|
3
|
-
import './chunk-
|
|
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
|
|
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(
|
|
72
|
-
ok: (msg) => console.log(
|
|
73
|
-
warn: (msg) => console.log(
|
|
74
|
-
error: (msg) => console.error(
|
|
75
|
-
brand: (msg) => console.log(
|
|
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" ?
|
|
80
|
-
console.log(`${badge} ${
|
|
81
|
-
if (d.files?.length) console.log(` ${
|
|
82
|
-
if (d.fix) console.log(` ${
|
|
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
|
|
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),
|
|
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(
|
|
643
|
-
if (model.pages.length === 0) console.log(
|
|
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(` ${
|
|
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(
|
|
893
|
+
console.log(pc3.bold("\nSpecial"));
|
|
649
894
|
for (const l of model.layouts) {
|
|
650
|
-
console.log(` ${
|
|
895
|
+
console.log(` ${pc3.cyan(("layout " + (l.dir === "" ? "/" : "/" + l.dir)).padEnd(28))} ${pc3.dim(l.file)}`);
|
|
651
896
|
}
|
|
652
|
-
if (model.notFound) console.log(` ${
|
|
653
|
-
if (model.error) console.log(` ${
|
|
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(
|
|
657
|
-
if (model.apis.length === 0) console.log(
|
|
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(` ${
|
|
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 = `${
|
|
1243
|
+
var HELP = `${pc3.bold(pc3.magenta("vantage"))} \u2014 data dashboard framework for Squadbase
|
|
683
1244
|
|
|
684
|
-
${
|
|
1245
|
+
${pc3.bold("Usage")}
|
|
685
1246
|
vantage <command> [path] [options]
|
|
686
1247
|
vantage <path> Quick dev shortcut (folder or entry file)
|
|
687
1248
|
|
|
688
|
-
${
|
|
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
|
-
${
|
|
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
|
|
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) {
|