@squadbase/vantage 0.3.0 → 0.4.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 +1 -1
- package/dist/add-GQEXRQSI.js +6 -0
- package/dist/add-GQEXRQSI.js.map +1 -0
- package/dist/build-77KHIRWR.js +108 -0
- package/dist/build-77KHIRWR.js.map +1 -0
- package/dist/check-26U4O5UW.js +38 -0
- package/dist/check-26U4O5UW.js.map +1 -0
- package/dist/chunk-2KRCGXBY.js +56 -0
- package/dist/chunk-2KRCGXBY.js.map +1 -0
- package/dist/chunk-BAM33YZ6.js +202 -0
- package/dist/chunk-BAM33YZ6.js.map +1 -0
- package/dist/chunk-C4MQRWXS.js +81 -0
- package/dist/chunk-C4MQRWXS.js.map +1 -0
- package/dist/chunk-D4Y5RWJA.js +189 -0
- package/dist/chunk-D4Y5RWJA.js.map +1 -0
- package/dist/chunk-N6HAGEUA.js +136 -0
- package/dist/chunk-N6HAGEUA.js.map +1 -0
- package/dist/chunk-PSEYFYAP.js +276 -0
- package/dist/chunk-PSEYFYAP.js.map +1 -0
- package/dist/chunk-R2YYVCGS.js +345 -0
- package/dist/chunk-R2YYVCGS.js.map +1 -0
- package/dist/chunk-RA6Z3OX3.js +199 -0
- package/dist/chunk-RA6Z3OX3.js.map +1 -0
- package/dist/chunk-VXAV2435.js +142 -0
- package/dist/chunk-VXAV2435.js.map +1 -0
- package/dist/chunk-ZIM745WE.js +267 -0
- package/dist/chunk-ZIM745WE.js.map +1 -0
- package/dist/cli.js +27 -1677
- package/dist/cli.js.map +1 -1
- package/dist/dev-5K2PNSXT.js +67 -0
- package/dist/dev-5K2PNSXT.js.map +1 -0
- package/dist/docs-XEPM66VI.js +114 -0
- package/dist/docs-XEPM66VI.js.map +1 -0
- package/dist/doctor-6UMWKG6L.js +58 -0
- package/dist/doctor-6UMWKG6L.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/preview-VXERMTHP.js +61 -0
- package/dist/preview-VXERMTHP.js.map +1 -0
- package/dist/routes-3JUXAYQJ.js +119 -0
- package/dist/routes-3JUXAYQJ.js.map +1 -0
- package/dist/search-NJJW4PXG.js +325 -0
- package/dist/search-NJJW4PXG.js.map +1 -0
- package/dist/server/node.d.ts +1 -12
- package/dist/types-De3mo_hv.d.ts +59 -0
- package/dist/upgrade-4XAY447F.js +29 -0
- package/dist/upgrade-4XAY447F.js.map +1 -0
- package/dist/vite/index.d.ts +13 -0
- package/dist/vite/index.js +5 -1
- package/docs/en/changelog.md +71 -0
- package/docs/en/cli-reference.md +60 -0
- package/docs/ja/changelog.md +65 -0
- package/docs/ja/cli-reference.md +60 -0
- package/package.json +7 -4
- package/skills/vantage-app/SKILL.md +1 -1
- package/templates/AGENTS.md +1 -1
- package/dist/chunk-5UGRNXHC.js +0 -802
- package/dist/chunk-5UGRNXHC.js.map +0 -1
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { loadCatalog, isDocLang, DOC_LANGS, DEFAULT_DOC_LANG, docsForLang, readDoc } from './chunk-2KRCGXBY.js';
|
|
2
|
+
import { log, printJson } from './chunk-N6HAGEUA.js';
|
|
3
|
+
import './chunk-C4MQRWXS.js';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
|
|
6
|
+
// @squadbase/vantage — generated build. Do not edit.
|
|
7
|
+
|
|
8
|
+
// src/cli/search-index.ts
|
|
9
|
+
var FIELD_WEIGHTS = { slug: 3, title: 3, description: 2, body: 1 };
|
|
10
|
+
var K1 = 1.2;
|
|
11
|
+
var B = 0.75;
|
|
12
|
+
var TOKEN_RE = /[a-z0-9]+|[-ヿ㐀-䶿一-鿿]+/g;
|
|
13
|
+
var LATIN_RE = /^[a-z0-9]+$/;
|
|
14
|
+
var TOKEN_RE_ANYCASE = /[a-zA-Z0-9]+|[-ヿ㐀-䶿一-鿿]+/g;
|
|
15
|
+
var CJK_RE = /[-ヿ㐀-䶿一-鿿]/;
|
|
16
|
+
var SCRIPT_RE = /[ぁ-ゟ]+|[゠-ヿ]+|[㐀-䶿一-鿿]+/g;
|
|
17
|
+
var HIRAGANA_RE = /^[ぁ-ゟ]$/;
|
|
18
|
+
function singular(word) {
|
|
19
|
+
if (word.length >= 5 && word.endsWith("ies")) return `${word.slice(0, -3)}y`;
|
|
20
|
+
if (word.length >= 4 && word.endsWith("s") && !/(ss|us|is)$/.test(word)) return word.slice(0, -1);
|
|
21
|
+
return word;
|
|
22
|
+
}
|
|
23
|
+
function tokenize(text) {
|
|
24
|
+
const normalized = text.normalize("NFKC").replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase();
|
|
25
|
+
const tokens = [];
|
|
26
|
+
for (const match of normalized.matchAll(TOKEN_RE)) {
|
|
27
|
+
const run = match[0];
|
|
28
|
+
if (LATIN_RE.test(run)) {
|
|
29
|
+
tokens.push(singular(run));
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
for (const segment of run.match(SCRIPT_RE) ?? []) {
|
|
33
|
+
if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue;
|
|
34
|
+
if (segment.length <= 2) {
|
|
35
|
+
tokens.push(segment);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
tokens.push(segment);
|
|
39
|
+
for (let i = 0; i < segment.length - 1; i++) tokens.push(segment.slice(i, i + 2));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return tokens;
|
|
43
|
+
}
|
|
44
|
+
function queryPhrases(query) {
|
|
45
|
+
const phrases = [];
|
|
46
|
+
for (const match of query.normalize("NFKC").matchAll(TOKEN_RE_ANYCASE)) {
|
|
47
|
+
const run = match[0];
|
|
48
|
+
if (!CJK_RE.test(run)) {
|
|
49
|
+
phrases.push(run);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
for (const segment of run.match(SCRIPT_RE) ?? []) {
|
|
53
|
+
if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue;
|
|
54
|
+
phrases.push(segment);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return [...new Set(phrases)];
|
|
58
|
+
}
|
|
59
|
+
function buildIndex(entries) {
|
|
60
|
+
const docs = entries.map((entry) => {
|
|
61
|
+
const body = readDoc(entry);
|
|
62
|
+
const tf = /* @__PURE__ */ new Map();
|
|
63
|
+
let length = 0;
|
|
64
|
+
const add = (text, weight) => {
|
|
65
|
+
for (const token of tokenize(text)) {
|
|
66
|
+
tf.set(token, (tf.get(token) ?? 0) + weight);
|
|
67
|
+
length += weight;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
add(entry.slug, FIELD_WEIGHTS.slug);
|
|
71
|
+
add(entry.title, FIELD_WEIGHTS.title);
|
|
72
|
+
add(entry.description, FIELD_WEIGHTS.description);
|
|
73
|
+
add(body, FIELD_WEIGHTS.body);
|
|
74
|
+
return { entry, body, tf, length };
|
|
75
|
+
});
|
|
76
|
+
const df = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const doc of docs) {
|
|
78
|
+
for (const term of doc.tf.keys()) df.set(term, (df.get(term) ?? 0) + 1);
|
|
79
|
+
}
|
|
80
|
+
const total = docs.length;
|
|
81
|
+
const avgLength = total ? docs.reduce((sum, doc) => sum + doc.length, 0) / total : 1;
|
|
82
|
+
return {
|
|
83
|
+
search(query) {
|
|
84
|
+
const terms = [...new Set(tokenize(query))];
|
|
85
|
+
if (terms.length === 0) return [];
|
|
86
|
+
const hits = [];
|
|
87
|
+
for (const doc of docs) {
|
|
88
|
+
let score = 0;
|
|
89
|
+
for (const term of terms) {
|
|
90
|
+
const tf = doc.tf.get(term);
|
|
91
|
+
if (!tf) continue;
|
|
92
|
+
const n = df.get(term) ?? 0;
|
|
93
|
+
const idf = Math.log(1 + (total - n + 0.5) / (n + 0.5));
|
|
94
|
+
const norm = 1 - B + B * doc.length / avgLength;
|
|
95
|
+
score += idf * (tf * (K1 + 1) / (tf + K1 * norm));
|
|
96
|
+
}
|
|
97
|
+
if (score > 0) hits.push({ entry: doc.entry, score, terms, body: doc.body });
|
|
98
|
+
}
|
|
99
|
+
hits.sort((a, b) => b.score - a.score || a.entry.slug.localeCompare(b.entry.slug));
|
|
100
|
+
return hits;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
var SNIPPET_LENGTH = 150;
|
|
105
|
+
function snippet(body, terms, length = SNIPPET_LENGTH) {
|
|
106
|
+
let best = "";
|
|
107
|
+
let bestHits = 0;
|
|
108
|
+
let bestIndex = 0;
|
|
109
|
+
let bestIsHeading = true;
|
|
110
|
+
for (const raw of body.split("\n").slice(1)) {
|
|
111
|
+
const line = raw.replace(/^\s*[-*]\s+/, "").replace(/\s+/g, " ").trim();
|
|
112
|
+
if (!line || /^(```|~~~|\|\s*-{2,})/.test(line)) continue;
|
|
113
|
+
const haystack = line.toLowerCase();
|
|
114
|
+
const heading = line.startsWith("#");
|
|
115
|
+
let hits = 0;
|
|
116
|
+
let first = -1;
|
|
117
|
+
for (const term of terms) {
|
|
118
|
+
const at = haystack.indexOf(term);
|
|
119
|
+
if (at === -1) continue;
|
|
120
|
+
hits++;
|
|
121
|
+
if (first === -1 || at < first) first = at;
|
|
122
|
+
}
|
|
123
|
+
if (hits > bestHits || hits === bestHits && hits > 0 && bestIsHeading && !heading) {
|
|
124
|
+
best = line;
|
|
125
|
+
bestHits = hits;
|
|
126
|
+
bestIndex = first;
|
|
127
|
+
bestIsHeading = heading;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (!bestHits) return "";
|
|
131
|
+
if (best.length <= length) return best;
|
|
132
|
+
const start = Math.max(0, bestIndex - Math.floor(length / 4));
|
|
133
|
+
const text = best.slice(start, start + length).trim();
|
|
134
|
+
return `${start > 0 ? "\u2026" : ""}${text}${start + length < best.length ? "\u2026" : ""}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/cli/search.ts
|
|
138
|
+
var DEFAULT_LIMIT = 10;
|
|
139
|
+
var MAX_REGEX_LINES = 3;
|
|
140
|
+
function parseLimit(value, fallback) {
|
|
141
|
+
if (typeof value === "string") {
|
|
142
|
+
const n = Number(value);
|
|
143
|
+
if (Number.isInteger(n) && n > 0) return n;
|
|
144
|
+
}
|
|
145
|
+
return fallback;
|
|
146
|
+
}
|
|
147
|
+
function escapeRegExp(value) {
|
|
148
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
149
|
+
}
|
|
150
|
+
function paintMatches(text, re) {
|
|
151
|
+
if (!process.stdout.isTTY) return text;
|
|
152
|
+
let out = "";
|
|
153
|
+
let last = 0;
|
|
154
|
+
for (const match of text.matchAll(re)) {
|
|
155
|
+
const at = match.index ?? 0;
|
|
156
|
+
if (!match[0]) continue;
|
|
157
|
+
out += pc.dim(text.slice(last, at)) + pc.yellow(match[0]);
|
|
158
|
+
last = at + match[0].length;
|
|
159
|
+
}
|
|
160
|
+
return out + pc.dim(text.slice(last));
|
|
161
|
+
}
|
|
162
|
+
function paintTerms(text, words) {
|
|
163
|
+
if (!process.stdout.isTTY) return text;
|
|
164
|
+
if (words.length === 0) return pc.dim(text);
|
|
165
|
+
return paintMatches(text, new RegExp(words.map(escapeRegExp).join("|"), "gi"));
|
|
166
|
+
}
|
|
167
|
+
function header(count, query, lang, mode) {
|
|
168
|
+
const label = `${count} result${count === 1 ? "" : "s"} for "${query}"`;
|
|
169
|
+
console.log("");
|
|
170
|
+
console.log(pc.bold(label) + pc.dim(` ${lang} \xB7 ${mode}`));
|
|
171
|
+
console.log("");
|
|
172
|
+
}
|
|
173
|
+
function footer(total, shown, lines) {
|
|
174
|
+
if (total > shown) {
|
|
175
|
+
console.log("");
|
|
176
|
+
console.log(pc.dim(` ${total - shown} more \u2014 raise --limit to see them`));
|
|
177
|
+
}
|
|
178
|
+
console.log("");
|
|
179
|
+
for (const line of lines) console.log(pc.dim(line));
|
|
180
|
+
}
|
|
181
|
+
function noResults(query) {
|
|
182
|
+
log.warn(`Nothing matches "${query}".`);
|
|
183
|
+
console.log(pc.dim(" Try fewer or more general words, or run `vantage docs --list` to browse every page."));
|
|
184
|
+
}
|
|
185
|
+
function meta(entry) {
|
|
186
|
+
return {
|
|
187
|
+
slug: entry.slug,
|
|
188
|
+
title: entry.title,
|
|
189
|
+
description: entry.description,
|
|
190
|
+
section: entry.section,
|
|
191
|
+
sectionTitle: entry.sectionTitle,
|
|
192
|
+
command: `vantage docs ${entry.slug}`
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function runRanked(entries, query, lang, limit, json) {
|
|
196
|
+
const hits = buildIndex(entries).search(query);
|
|
197
|
+
const shown = hits.slice(0, limit);
|
|
198
|
+
const passage = (hit) => snippet(hit.body, hit.terms);
|
|
199
|
+
if (json) {
|
|
200
|
+
printJson({
|
|
201
|
+
query,
|
|
202
|
+
mode: "bm25",
|
|
203
|
+
lang,
|
|
204
|
+
count: hits.length,
|
|
205
|
+
results: shown.map((hit) => ({
|
|
206
|
+
...meta(hit.entry),
|
|
207
|
+
score: Math.round(hit.score * 1e3) / 1e3,
|
|
208
|
+
snippet: passage(hit)
|
|
209
|
+
}))
|
|
210
|
+
});
|
|
211
|
+
return 0;
|
|
212
|
+
}
|
|
213
|
+
if (hits.length === 0) {
|
|
214
|
+
noResults(query);
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
const words = queryPhrases(query);
|
|
218
|
+
const width = Math.max(...shown.map((hit) => hit.entry.slug.length));
|
|
219
|
+
header(hits.length, query, lang, "bm25");
|
|
220
|
+
for (const hit of shown) {
|
|
221
|
+
const title = `${hit.entry.title}${pc.dim(` \xB7 ${hit.entry.sectionTitle}`)}`;
|
|
222
|
+
console.log(` ${pc.cyan(hit.entry.slug.padEnd(width))} ${title}`);
|
|
223
|
+
const text = passage(hit);
|
|
224
|
+
if (text) console.log(` ${" ".repeat(width)} ${paintTerms(text, words)}`);
|
|
225
|
+
}
|
|
226
|
+
footer(hits.length, shown.length, [
|
|
227
|
+
"vantage docs <name> open one result --regex treat the query as a regular expression",
|
|
228
|
+
"vantage search --json machine-readable --limit max results (default 10)"
|
|
229
|
+
]);
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
function runRegex(entries, query, lang, limit, json) {
|
|
233
|
+
let scan;
|
|
234
|
+
let probe;
|
|
235
|
+
try {
|
|
236
|
+
scan = new RegExp(query, "gi");
|
|
237
|
+
probe = new RegExp(query, "i");
|
|
238
|
+
} catch (err) {
|
|
239
|
+
log.error(err instanceof Error ? err.message : `Invalid regular expression: ${String(err)}`);
|
|
240
|
+
return 1;
|
|
241
|
+
}
|
|
242
|
+
const results = [];
|
|
243
|
+
for (const entry of entries) {
|
|
244
|
+
const lines = readDoc(entry).split("\n");
|
|
245
|
+
const matches = [];
|
|
246
|
+
let matchCount = 0;
|
|
247
|
+
for (let i = 0; i < lines.length; i++) {
|
|
248
|
+
const found = [...lines[i].matchAll(scan)];
|
|
249
|
+
if (found.length === 0) continue;
|
|
250
|
+
matchCount += found.length;
|
|
251
|
+
if (matches.length < MAX_REGEX_LINES) {
|
|
252
|
+
matches.push({ line: i + 1, text: lines[i].replace(/\s+/g, " ").trim() });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const inMeta = probe.test(entry.slug) || probe.test(entry.title) || probe.test(entry.description);
|
|
256
|
+
if (matchCount === 0 && !inMeta) continue;
|
|
257
|
+
results.push({ entry, matchCount, matches });
|
|
258
|
+
}
|
|
259
|
+
results.sort((a, b) => b.matchCount - a.matchCount);
|
|
260
|
+
const shown = results.slice(0, limit);
|
|
261
|
+
if (json) {
|
|
262
|
+
printJson({
|
|
263
|
+
query,
|
|
264
|
+
mode: "regex",
|
|
265
|
+
lang,
|
|
266
|
+
count: results.length,
|
|
267
|
+
results: shown.map((result) => ({
|
|
268
|
+
...meta(result.entry),
|
|
269
|
+
matchCount: result.matchCount,
|
|
270
|
+
matches: result.matches
|
|
271
|
+
}))
|
|
272
|
+
});
|
|
273
|
+
return 0;
|
|
274
|
+
}
|
|
275
|
+
if (results.length === 0) {
|
|
276
|
+
noResults(query);
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
header(results.length, query, lang, "regex");
|
|
280
|
+
for (const result of shown) {
|
|
281
|
+
const count = pc.dim(
|
|
282
|
+
result.matchCount ? ` ${result.matchCount} match${result.matchCount === 1 ? "" : "es"}` : " name match"
|
|
283
|
+
);
|
|
284
|
+
console.log(` ${pc.cyan(result.entry.slug)} ${result.entry.title}${count}`);
|
|
285
|
+
for (const match of result.matches) {
|
|
286
|
+
console.log(` ${pc.dim(String(match.line).padStart(4))} ${paintMatches(match.text, scan)}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
footer(results.length, shown.length, [
|
|
290
|
+
"vantage docs <name> open one result --limit max results (default 10)",
|
|
291
|
+
"vantage search --json machine-readable --lang ja | en"
|
|
292
|
+
]);
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
async function search(_root, args) {
|
|
296
|
+
const query = args.positionals.slice(1).join(" ").trim();
|
|
297
|
+
if (!query) {
|
|
298
|
+
log.error("Usage: vantage search <query> [--regex] [--limit <n>] [--lang ja|en] [--json]");
|
|
299
|
+
return 1;
|
|
300
|
+
}
|
|
301
|
+
const catalog = loadCatalog();
|
|
302
|
+
if (!catalog) {
|
|
303
|
+
log.error("The bundled documentation is missing. Reinstall @squadbase/vantage, or run `pnpm build` in the framework repo.");
|
|
304
|
+
return 1;
|
|
305
|
+
}
|
|
306
|
+
const langFlag = args.flags.lang;
|
|
307
|
+
if (langFlag !== void 0 && !isDocLang(langFlag)) {
|
|
308
|
+
log.error(`Unknown --lang "${String(langFlag)}". Available: ${DOC_LANGS.join(", ")}`);
|
|
309
|
+
return 1;
|
|
310
|
+
}
|
|
311
|
+
const lang = isDocLang(langFlag) ? langFlag : DEFAULT_DOC_LANG;
|
|
312
|
+
const entries = docsForLang(catalog, lang);
|
|
313
|
+
if (entries.length === 0) {
|
|
314
|
+
log.error(`No documentation bundled for "${lang}".`);
|
|
315
|
+
return 1;
|
|
316
|
+
}
|
|
317
|
+
const searchable = entries.filter((entry) => entry.searchable !== false);
|
|
318
|
+
const limit = parseLimit(args.flags.limit, DEFAULT_LIMIT);
|
|
319
|
+
const json = Boolean(args.flags.json);
|
|
320
|
+
return args.flags.regex ? runRegex(searchable, query, lang, limit, json) : runRanked(searchable, query, lang, limit, json);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export { search };
|
|
324
|
+
//# sourceMappingURL=search-NJJW4PXG.js.map
|
|
325
|
+
//# sourceMappingURL=search-NJJW4PXG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/search-index.ts","../src/cli/search.ts"],"names":[],"mappings":"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","file":"search-NJJW4PXG.js","sourcesContent":["import { readDoc, type DocEntry } from \"./docs-catalog\"\n\n/**\n * A tiny BM25F ranker over the bundled documentation. The corpus is the catalog\n * `docs-catalog.ts` exposes — the same one `vantage docs` prints, so search never\n * creates a second source of truth.\n *\n * The index is built at run time: 65 pages per language (~300 KB) tokenize in a\n * few milliseconds, which is cheaper than shipping and version-locking a\n * prebuilt index alongside the docs bundle.\n */\n\n/**\n * Field weights. A name or a title match says far more about relevance than one\n * more occurrence in a long body, and BM25F models that as a weighted term\n * frequency (and a matching weighted document length).\n */\nconst FIELD_WEIGHTS = { slug: 3, title: 3, description: 2, body: 1 } as const\n\n/** Standard BM25 constants: term-frequency saturation and length normalization. */\nconst K1 = 1.2\nconst B = 0.75\n\n/**\n * Latin/digit runs, or runs of Japanese script (kana + CJK ideographs). CJK\n * punctuation (U+3000–U+303F, 。and 、) is deliberately outside the ranges, so\n * runs break at sentence boundaries.\n */\nconst TOKEN_RE = /[a-z0-9]+|[-ヿ㐀-䶿一-鿿]+/g\nconst LATIN_RE = /^[a-z0-9]+$/\n/** `TOKEN_RE`, but before lowercasing — for text that is not being indexed. */\nconst TOKEN_RE_ANYCASE = /[a-zA-Z0-9]+|[-ヿ㐀-䶿一-鿿]+/g\nconst CJK_RE = /[-ヿ㐀-䶿一-鿿]/\n\n/**\n * One run of a single script: hiragana (U+3041–U+309F), katakana (U+30A0–U+30FF,\n * so ー stays inside テーブル), or kanji. Japanese writes content words in\n * katakana and kanji and the grammatical glue between them in hiragana, so\n * cutting at every script change segments 「テーブルにページングを付けたい」into\n * テーブル · に · ページング · を · 付 · けたい without a morphological analyser.\n */\nconst SCRIPT_RE = /[ぁ-ゟ]+|[゠-ヿ]+|[㐀-䶿一-鿿]+/g\nconst HIRAGANA_RE = /^[ぁ-ゟ]$/\n\n/** Plural forms, so `colors` finds `color` and `queries` finds `query`. */\nfunction singular(word: string): string {\n if (word.length >= 5 && word.endsWith(\"ies\")) return `${word.slice(0, -3)}y`\n if (word.length >= 4 && word.endsWith(\"s\") && !/(ss|us|is)$/.test(word)) return word.slice(0, -1)\n return word\n}\n\n/**\n * Split text into index terms. Latin runs become words (`DataTable` splits into\n * `data` + `table`, so a two-word query finds it). Japanese runs are segmented\n * by script change; each segment is indexed whole *and* as character bigrams,\n * so an exact word scores high while a near miss (ページング / ページネーション)\n * still shares enough terms to be found.\n */\nexport function tokenize(text: string): string[] {\n const normalized = text\n .normalize(\"NFKC\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n const tokens: string[] = []\n for (const match of normalized.matchAll(TOKEN_RE)) {\n const run = match[0]!\n if (LATIN_RE.test(run)) {\n tokens.push(singular(run))\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n // A lone hiragana is a particle (を, に, が …): it appears in every page\n // and would make every page a match.\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n // A 2-character segment is its own only bigram — pushing both would\n // double-count it.\n if (segment.length <= 2) {\n tokens.push(segment)\n continue\n }\n tokens.push(segment)\n for (let i = 0; i < segment.length - 1; i++) tokens.push(segment.slice(i, i + 2))\n }\n }\n return tokens\n}\n\n/**\n * The words a snippet should highlight: whole words and whole Japanese\n * segments as the user typed them, without the derived bigrams (highlighting\n * those would paint most of a Japanese line yellow) and without the singular\n * rewrite (which no longer appears verbatim in the text).\n */\nexport function queryPhrases(query: string): string[] {\n const phrases: string[] = []\n for (const match of query.normalize(\"NFKC\").matchAll(TOKEN_RE_ANYCASE)) {\n const run = match[0]!\n if (!CJK_RE.test(run)) {\n phrases.push(run)\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n phrases.push(segment)\n }\n }\n return [...new Set(phrases)]\n}\n\n/** One ranked document, with the body kept for snippet extraction. */\nexport interface SearchHit {\n entry: DocEntry\n score: number\n /** Query terms that were looked up — the input for `snippet()`. */\n terms: string[]\n body: string\n}\n\ninterface IndexedDoc {\n entry: DocEntry\n body: string\n /** Weighted term frequency across all fields. */\n tf: Map<string, number>\n /** Weighted document length. */\n length: number\n}\n\nexport interface SearchIndex {\n /** Every document with a non-zero score, best first. */\n search(query: string): SearchHit[]\n}\n\n/** Build the index for one language's catalog entries. */\nexport function buildIndex(entries: DocEntry[]): SearchIndex {\n const docs: IndexedDoc[] = entries.map((entry) => {\n const body = readDoc(entry)\n const tf = new Map<string, number>()\n let length = 0\n const add = (text: string, weight: number) => {\n for (const token of tokenize(text)) {\n tf.set(token, (tf.get(token) ?? 0) + weight)\n length += weight\n }\n }\n add(entry.slug, FIELD_WEIGHTS.slug)\n add(entry.title, FIELD_WEIGHTS.title)\n add(entry.description, FIELD_WEIGHTS.description)\n add(body, FIELD_WEIGHTS.body)\n return { entry, body, tf, length }\n })\n\n const df = new Map<string, number>()\n for (const doc of docs) {\n for (const term of doc.tf.keys()) df.set(term, (df.get(term) ?? 0) + 1)\n }\n const total = docs.length\n const avgLength = total ? docs.reduce((sum, doc) => sum + doc.length, 0) / total : 1\n\n return {\n search(query: string): SearchHit[] {\n const terms = [...new Set(tokenize(query))]\n if (terms.length === 0) return []\n\n const hits: SearchHit[] = []\n for (const doc of docs) {\n let score = 0\n for (const term of terms) {\n const tf = doc.tf.get(term)\n if (!tf) continue\n const n = df.get(term) ?? 0\n const idf = Math.log(1 + (total - n + 0.5) / (n + 0.5))\n const norm = 1 - B + (B * doc.length) / avgLength\n score += idf * ((tf * (K1 + 1)) / (tf + K1 * norm))\n }\n if (score > 0) hits.push({ entry: doc.entry, score, terms, body: doc.body })\n }\n hits.sort((a, b) => b.score - a.score || a.entry.slug.localeCompare(b.entry.slug))\n return hits\n },\n }\n}\n\n/** How much of a line to show around the first matched term. */\nconst SNIPPET_LENGTH = 150\n\n/**\n * Pick the passage that best covers the query terms. Lines are compared\n * lowercased only (no NFKC, no camelCase splitting) so offsets stay aligned\n * with the text that is printed.\n */\nexport function snippet(body: string, terms: string[], length = SNIPPET_LENGTH): string {\n let best = \"\"\n let bestHits = 0\n let bestIndex = 0\n let bestIsHeading = true\n\n // The first line is the page's own `# Title`, which the caller already shows.\n for (const raw of body.split(\"\\n\").slice(1)) {\n const line = raw.replace(/^\\s*[-*]\\s+/, \"\").replace(/\\s+/g, \" \").trim()\n if (!line || /^(```|~~~|\\|\\s*-{2,})/.test(line)) continue\n const haystack = line.toLowerCase()\n const heading = line.startsWith(\"#\")\n let hits = 0\n let first = -1\n for (const term of terms) {\n const at = haystack.indexOf(term)\n if (at === -1) continue\n hits++\n if (first === -1 || at < first) first = at\n }\n // Equal coverage: prose says more than a heading does.\n if (hits > bestHits || (hits === bestHits && hits > 0 && bestIsHeading && !heading)) {\n best = line\n bestHits = hits\n bestIndex = first\n bestIsHeading = heading\n }\n }\n\n if (!bestHits) return \"\"\n if (best.length <= length) return best\n\n const start = Math.max(0, bestIndex - Math.floor(length / 4))\n const text = best.slice(start, start + length).trim()\n return `${start > 0 ? \"…\" : \"\"}${text}${start + length < best.length ? \"…\" : \"\"}`\n}\n","import pc from \"picocolors\"\nimport {\n DEFAULT_DOC_LANG,\n DOC_LANGS,\n docsForLang,\n isDocLang,\n loadCatalog,\n readDoc,\n type DocEntry,\n type DocLang,\n} from \"./docs-catalog\"\nimport { buildIndex, queryPhrases, snippet, type SearchHit } from \"./search-index\"\nimport { log, printJson, type ParsedArgs } from \"./util\"\n\n/** Results shown when `--limit` is absent. */\nconst DEFAULT_LIMIT = 10\n\n/** Matching lines printed per page in regex mode (the count is always exact). */\nconst MAX_REGEX_LINES = 3\n\n/** Parse `--limit`, falling back silently — an off result list is not a failure. */\nfunction parseLimit(value: string | boolean | undefined, fallback: number): number {\n if (typeof value === \"string\") {\n const n = Number(value)\n if (Number.isInteger(n) && n > 0) return n\n }\n return fallback\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** Dim a line, with every match of `re` picked out. Piped output stays plain. */\nfunction paintMatches(text: string, re: RegExp): string {\n if (!process.stdout.isTTY) return text\n let out = \"\"\n let last = 0\n for (const match of text.matchAll(re)) {\n const at = match.index ?? 0\n if (!match[0]) continue // zero-length match: nothing to highlight\n out += pc.dim(text.slice(last, at)) + pc.yellow(match[0])\n last = at + match[0].length\n }\n return out + pc.dim(text.slice(last))\n}\n\n/** Same, for the words of a natural-language query. */\nfunction paintTerms(text: string, words: string[]): string {\n if (!process.stdout.isTTY) return text\n if (words.length === 0) return pc.dim(text)\n return paintMatches(text, new RegExp(words.map(escapeRegExp).join(\"|\"), \"gi\"))\n}\n\nfunction header(count: number, query: string, lang: DocLang, mode: string): void {\n const label = `${count} result${count === 1 ? \"\" : \"s\"} for \"${query}\"`\n console.log(\"\")\n console.log(pc.bold(label) + pc.dim(` ${lang} · ${mode}`))\n console.log(\"\")\n}\n\nfunction footer(total: number, shown: number, lines: string[]): void {\n if (total > shown) {\n console.log(\"\")\n console.log(pc.dim(` ${total - shown} more — raise --limit to see them`))\n }\n console.log(\"\")\n for (const line of lines) console.log(pc.dim(line))\n}\n\nfunction noResults(query: string): void {\n log.warn(`Nothing matches \"${query}\".`)\n console.log(pc.dim(\" Try fewer or more general words, or run `vantage docs --list` to browse every page.\"))\n}\n\nfunction meta(entry: DocEntry) {\n return {\n slug: entry.slug,\n title: entry.title,\n description: entry.description,\n section: entry.section,\n sectionTitle: entry.sectionTitle,\n command: `vantage docs ${entry.slug}`,\n }\n}\n\n/** Default mode: rank the corpus with BM25 and show the best passage of each hit. */\nfunction runRanked(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n const hits = buildIndex(entries).search(query)\n const shown = hits.slice(0, limit)\n const passage = (hit: SearchHit) => snippet(hit.body, hit.terms)\n\n if (json) {\n printJson({\n query,\n mode: \"bm25\",\n lang,\n count: hits.length,\n results: shown.map((hit) => ({\n ...meta(hit.entry),\n score: Math.round(hit.score * 1000) / 1000,\n snippet: passage(hit),\n })),\n })\n return 0\n }\n\n if (hits.length === 0) {\n noResults(query)\n return 0\n }\n\n const words = queryPhrases(query)\n const width = Math.max(...shown.map((hit) => hit.entry.slug.length))\n header(hits.length, query, lang, \"bm25\")\n for (const hit of shown) {\n const title = `${hit.entry.title}${pc.dim(` · ${hit.entry.sectionTitle}`)}`\n console.log(` ${pc.cyan(hit.entry.slug.padEnd(width))} ${title}`)\n const text = passage(hit)\n if (text) console.log(` ${\" \".repeat(width)} ${paintTerms(text, words)}`)\n }\n footer(hits.length, shown.length, [\n \"vantage docs <name> open one result --regex treat the query as a regular expression\",\n \"vantage search --json machine-readable --limit max results (default 10)\",\n ])\n return 0\n}\n\n/** `--regex` mode: scan names, titles and bodies for a regular expression. */\nfunction runRegex(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n let scan: RegExp\n let probe: RegExp\n try {\n scan = new RegExp(query, \"gi\")\n probe = new RegExp(query, \"i\")\n } catch (err) {\n log.error(err instanceof Error ? err.message : `Invalid regular expression: ${String(err)}`)\n return 1\n }\n\n const results: { entry: DocEntry; matchCount: number; matches: { line: number; text: string }[] }[] = []\n for (const entry of entries) {\n const lines = readDoc(entry).split(\"\\n\")\n const matches: { line: number; text: string }[] = []\n let matchCount = 0\n for (let i = 0; i < lines.length; i++) {\n const found = [...lines[i]!.matchAll(scan)]\n if (found.length === 0) continue\n matchCount += found.length\n if (matches.length < MAX_REGEX_LINES) {\n matches.push({ line: i + 1, text: lines[i]!.replace(/\\s+/g, \" \").trim() })\n }\n }\n const inMeta = probe.test(entry.slug) || probe.test(entry.title) || probe.test(entry.description)\n if (matchCount === 0 && !inMeta) continue\n results.push({ entry, matchCount, matches })\n }\n // Stable sort: pages with more matches first, catalog order within ties.\n results.sort((a, b) => b.matchCount - a.matchCount)\n const shown = results.slice(0, limit)\n\n if (json) {\n printJson({\n query,\n mode: \"regex\",\n lang,\n count: results.length,\n results: shown.map((result) => ({\n ...meta(result.entry),\n matchCount: result.matchCount,\n matches: result.matches,\n })),\n })\n return 0\n }\n\n if (results.length === 0) {\n noResults(query)\n return 0\n }\n\n header(results.length, query, lang, \"regex\")\n for (const result of shown) {\n // A page can match on its name, title or description alone — with no body line to show.\n const count = pc.dim(\n result.matchCount ? ` ${result.matchCount} match${result.matchCount === 1 ? \"\" : \"es\"}` : \" name match\",\n )\n console.log(` ${pc.cyan(result.entry.slug)} ${result.entry.title}${count}`)\n for (const match of result.matches) {\n console.log(` ${pc.dim(String(match.line).padStart(4))} ${paintMatches(match.text, scan)}`)\n }\n }\n footer(results.length, shown.length, [\n \"vantage docs <name> open one result --limit max results (default 10)\",\n \"vantage search --json machine-readable --lang ja | en\",\n ])\n return 0\n}\n\n/** `vantage search <query> [--regex] [--limit n] [--json] [--lang ja|en]` */\nexport async function search(_root: string, args: ParsedArgs): Promise<number> {\n const query = args.positionals.slice(1).join(\" \").trim()\n if (!query) {\n log.error(\"Usage: vantage search <query> [--regex] [--limit <n>] [--lang ja|en] [--json]\")\n return 1\n }\n\n const catalog = loadCatalog()\n if (!catalog) {\n log.error(\"The bundled documentation is missing. Reinstall @squadbase/vantage, or run `pnpm build` in the framework repo.\")\n return 1\n }\n\n const langFlag = args.flags.lang\n if (langFlag !== undefined && !isDocLang(langFlag)) {\n log.error(`Unknown --lang \"${String(langFlag)}\". Available: ${DOC_LANGS.join(\", \")}`)\n return 1\n }\n const lang: DocLang = isDocLang(langFlag) ? langFlag : DEFAULT_DOC_LANG\n\n const entries = docsForLang(catalog, lang)\n if (entries.length === 0) {\n log.error(`No documentation bundled for \"${lang}\".`)\n return 1\n }\n\n // Pages that opted out with `search: false` (e.g. the changelog) are still\n // reachable via `vantage docs` but never surface here.\n const searchable = entries.filter((entry) => entry.searchable !== false)\n\n const limit = parseLimit(args.flags.limit, DEFAULT_LIMIT)\n const json = Boolean(args.flags.json)\n return args.flags.regex\n ? runRegex(searchable, query, lang, limit, json)\n : runRanked(searchable, query, lang, limit, json)\n}\n"]}
|
package/dist/server/node.d.ts
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
|
+
import { S as Segment } from '../types-De3mo_hv.js';
|
|
1
2
|
import { ApiModule } from './index.js';
|
|
2
3
|
|
|
3
|
-
/** A parsed path segment of a page or API route. */
|
|
4
|
-
type Segment = {
|
|
5
|
-
kind: "static";
|
|
6
|
-
value: string;
|
|
7
|
-
} | {
|
|
8
|
-
kind: "param";
|
|
9
|
-
name: string;
|
|
10
|
-
} | {
|
|
11
|
-
kind: "catchall";
|
|
12
|
-
name: string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
4
|
/** A statically-imported API route for the production server. */
|
|
16
5
|
interface ProdApiRoute {
|
|
17
6
|
routePath: string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** A parsed path segment of a page or API route. */
|
|
2
|
+
type Segment = {
|
|
3
|
+
kind: "static";
|
|
4
|
+
value: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "param";
|
|
7
|
+
name: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "catchall";
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
/** A discovered page route. */
|
|
13
|
+
interface PageRoute {
|
|
14
|
+
/** Project-relative POSIX path, e.g. `sales/[customerId].tsx`. */
|
|
15
|
+
file: string;
|
|
16
|
+
/** Absolute filesystem path. */
|
|
17
|
+
absFile: string;
|
|
18
|
+
/** Display route path, e.g. `/sales/:customerId` or `/files/*`. */
|
|
19
|
+
routePath: string;
|
|
20
|
+
/** Parsed segments. */
|
|
21
|
+
segments: Segment[];
|
|
22
|
+
/** Directory (POSIX, relative), e.g. `sales` or "" for root. */
|
|
23
|
+
dir: string;
|
|
24
|
+
/** Whether the file has a dynamic (param/catchall) segment. */
|
|
25
|
+
dynamic: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** A discovered layout module. */
|
|
28
|
+
interface LayoutRoute {
|
|
29
|
+
/** Project-relative POSIX path, e.g. `_layout.tsx` or `sales/_layout.tsx`. */
|
|
30
|
+
file: string;
|
|
31
|
+
absFile: string;
|
|
32
|
+
/** Directory the layout applies to (POSIX, relative), "" for root. */
|
|
33
|
+
dir: string;
|
|
34
|
+
}
|
|
35
|
+
/** A discovered server API route. */
|
|
36
|
+
interface ApiRoute {
|
|
37
|
+
/** Project-relative POSIX path, e.g. `server/api/customers/[id].ts`. */
|
|
38
|
+
file: string;
|
|
39
|
+
absFile: string;
|
|
40
|
+
/** Display route path, e.g. `/api/customers/:id`. */
|
|
41
|
+
routePath: string;
|
|
42
|
+
/** Hono-style match pattern, e.g. `/api/customers/:id` or `/api/files/*`. */
|
|
43
|
+
pattern: string;
|
|
44
|
+
segments: Segment[];
|
|
45
|
+
params: string[];
|
|
46
|
+
}
|
|
47
|
+
/** The full route model derived from a project scan. */
|
|
48
|
+
interface RouteModel {
|
|
49
|
+
pages: PageRoute[];
|
|
50
|
+
layouts: LayoutRoute[];
|
|
51
|
+
notFound: string | null;
|
|
52
|
+
error: string | null;
|
|
53
|
+
apis: ApiRoute[];
|
|
54
|
+
hasServer: boolean;
|
|
55
|
+
/** Page-scan root relative to the project root: `"src"` or `""`. */
|
|
56
|
+
pageDir: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type { RouteModel as R, Segment as S };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { syncAgentsFile } from './chunk-ZIM745WE.js';
|
|
2
|
+
import { generateArtifacts } from './chunk-RA6Z3OX3.js';
|
|
3
|
+
import './chunk-VXAV2435.js';
|
|
4
|
+
import { scanProject } from './chunk-D4Y5RWJA.js';
|
|
5
|
+
import { frameworkVersion, printJson, log } from './chunk-N6HAGEUA.js';
|
|
6
|
+
import './chunk-C4MQRWXS.js';
|
|
7
|
+
|
|
8
|
+
// @squadbase/vantage — generated build. Do not edit.
|
|
9
|
+
|
|
10
|
+
// src/cli/upgrade.ts
|
|
11
|
+
async function upgrade(root, args) {
|
|
12
|
+
const version = frameworkVersion();
|
|
13
|
+
const model = scanProject(root);
|
|
14
|
+
generateArtifacts({ root, model });
|
|
15
|
+
const agents = syncAgentsFile(root);
|
|
16
|
+
if (args.flags.json) {
|
|
17
|
+
printJson({ ok: true, version, transforms: [], regenerated: true, agentsSynced: agents === "updated" });
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
log.brand(`upgrade \u2192 v${version}`);
|
|
21
|
+
log.ok("Regenerated .vantage artifacts.");
|
|
22
|
+
if (agents === "updated") log.ok("Synced AGENTS.md from the framework.");
|
|
23
|
+
log.info("No breaking code transforms required for this version.");
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { upgrade };
|
|
28
|
+
//# sourceMappingURL=upgrade-4XAY447F.js.map
|
|
29
|
+
//# sourceMappingURL=upgrade-4XAY447F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/upgrade.ts"],"names":[],"mappings":";;;;;;;;;;AAWA,eAAsB,OAAA,CAAQ,MAAc,IAAA,EAAmC;AAC7E,EAAA,MAAM,UAAU,gBAAA,EAAiB;AACjC,EAAA,MAAM,KAAA,GAAQ,YAAY,IAAI,CAAA;AAC9B,EAAA,iBAAA,CAAkB,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAIjC,EAAA,MAAM,MAAA,GAAS,eAAe,IAAI,CAAA;AAElC,EAAA,IAAI,IAAA,CAAK,MAAM,IAAA,EAAM;AACnB,IAAA,SAAA,CAAU,EAAE,EAAA,EAAI,IAAA,EAAM,OAAA,EAAS,UAAA,EAAY,EAAC,EAAG,WAAA,EAAa,IAAA,EAAM,YAAA,EAAc,MAAA,KAAW,SAAA,EAAW,CAAA;AACtG,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,GAAA,CAAI,KAAA,CAAM,CAAA,gBAAA,EAAc,OAAO,CAAA,CAAE,CAAA;AACjC,EAAA,GAAA,CAAI,GAAG,iCAAiC,CAAA;AACxC,EAAA,IAAI,MAAA,KAAW,SAAA,EAAW,GAAA,CAAI,EAAA,CAAG,sCAAsC,CAAA;AACvE,EAAA,GAAA,CAAI,KAAK,wDAAwD,CAAA;AACjE,EAAA,OAAO,CAAA;AACT","file":"upgrade-4XAY447F.js","sourcesContent":["import { generateArtifacts } from \"../core/generate\"\nimport { scanProject } from \"../core/scan\"\nimport { syncAgentsFile } from \"./add\"\nimport { frameworkVersion, log, printJson, type ParsedArgs } from \"./util\"\n\n/**\n * `vantage upgrade` — reconcile generated artifacts with the installed\n * framework version and apply any needed code transforms. v0.1 only\n * regenerates artifacts and re-syncs a managed AGENTS.md; the migration hook\n * exists for future major versions.\n */\nexport async function upgrade(root: string, args: ParsedArgs): Promise<number> {\n const version = frameworkVersion()\n const model = scanProject(root)\n generateArtifacts({ root, model })\n\n // Keep an adopted AGENTS.md (the app-author map) in step with the framework's\n // canonical copy. No-op when the app never ran `vantage add agents`.\n const agents = syncAgentsFile(root)\n\n if (args.flags.json) {\n printJson({ ok: true, version, transforms: [], regenerated: true, agentsSynced: agents === \"updated\" })\n return 0\n }\n\n log.brand(`upgrade → v${version}`)\n log.ok(\"Regenerated .vantage artifacts.\")\n if (agents === \"updated\") log.ok(\"Synced AGENTS.md from the framework.\")\n log.info(\"No breaking code transforms required for this version.\")\n return 0\n}\n"]}
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { PluginOption } from 'vite';
|
|
2
|
+
import { R as RouteModel } from '../types-De3mo_hv.js';
|
|
2
3
|
|
|
3
4
|
interface VantagePluginOptions {
|
|
4
5
|
root: string;
|
|
5
6
|
/** Server-side env (process.env + loaded .env), passed to API handlers. */
|
|
6
7
|
env?: Record<string, string | undefined>;
|
|
8
|
+
/**
|
|
9
|
+
* A route model the caller already scanned. `dev`/`build` run diagnostics
|
|
10
|
+
* before starting Vite, so without this the project would be walked a second
|
|
11
|
+
* time for an answer that is milliseconds old.
|
|
12
|
+
*/
|
|
13
|
+
model?: RouteModel;
|
|
14
|
+
/**
|
|
15
|
+
* Set when the caller has already written `.vantage/` for `model`. `build`
|
|
16
|
+
* does, so that the server bundle — which reads `server-routes.gen.ts` — can
|
|
17
|
+
* be produced at the same time as the client instead of after it.
|
|
18
|
+
*/
|
|
19
|
+
artifactsWritten?: boolean;
|
|
7
20
|
}
|
|
8
21
|
/**
|
|
9
22
|
* The single plugin that turns a plain Vite instance into Vantage: file-based
|
package/dist/vite/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
export { vantagePlugin } from '../chunk-
|
|
1
|
+
export { vantagePlugin } from '../chunk-R2YYVCGS.js';
|
|
2
|
+
import '../chunk-RA6Z3OX3.js';
|
|
2
3
|
import '../chunk-46QI6GFC.js';
|
|
4
|
+
import '../chunk-VXAV2435.js';
|
|
5
|
+
import '../chunk-D4Y5RWJA.js';
|
|
6
|
+
import '../chunk-C4MQRWXS.js';
|
|
3
7
|
import '../chunk-B7LLBNLV.js';
|
|
4
8
|
//# sourceMappingURL=index.js.map
|
|
5
9
|
//# sourceMappingURL=index.js.map
|
package/docs/en/changelog.md
CHANGED
|
@@ -9,6 +9,77 @@ What changed in each Vantage release. Newest is on top.
|
|
|
9
9
|
> minor release may include backwards-incompatible changes. A patch is limited to
|
|
10
10
|
> backwards-compatible additions and bug fixes.
|
|
11
11
|
|
|
12
|
+
## v0.4.0
|
|
13
|
+
|
|
14
|
+
An explicit `--port` is now exact. This includes a backwards-incompatible
|
|
15
|
+
change, so the minor goes up, per the 0.x policy.
|
|
16
|
+
|
|
17
|
+
Apps pinned to `"@squadbase/vantage": "^0.3.0"` will not pick up 0.4.0 — bump the
|
|
18
|
+
range to `^0.4.0`.
|
|
19
|
+
|
|
20
|
+
> [!WARNING]
|
|
21
|
+
> **`vantage dev --port 3000` now exits 1 instead of starting when 3000 is taken.**
|
|
22
|
+
> It used to walk quietly to 3001. Pass `--no-strict-port` if you need the old
|
|
23
|
+
> behaviour. Leaving `--port` **off** is unchanged: a busy default (5173 / 4173)
|
|
24
|
+
> still walks to the next free port.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **An explicit `--port` is exact** (→ [CLI reference](cli-reference)) —
|
|
29
|
+
writing `--port 3000` means the port is a contract with something outside the
|
|
30
|
+
process: a reverse proxy, a container port mapping, an OAuth redirect URI.
|
|
31
|
+
Binding 3001 instead is a silent failure, not a recovery — a supervisor that
|
|
32
|
+
only checks "is anything listening on 3000" will happily report a server nobody
|
|
33
|
+
can reach. Without `--port`, a busy default still walks, so running several
|
|
34
|
+
projects side by side is as easy as before.
|
|
35
|
+
- **An invalid `--port` value is an error** — a non-integer, an out-of-range
|
|
36
|
+
number, or a missing value used to start the server on the default port.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- **`--strict-port`** — fail instead of walking, even when the port came from the
|
|
41
|
+
default.
|
|
42
|
+
- **`--no-strict-port`** — walk to the next free port, even when `--port` was
|
|
43
|
+
explicit. Use it where 0.3.x behaviour is required.
|
|
44
|
+
|
|
45
|
+
A fullstack `vantage preview` binds its Node server to exactly one port, so it
|
|
46
|
+
was already always strict; `--no-strict-port` has no effect there (and says so).
|
|
47
|
+
|
|
48
|
+
## v0.3.1
|
|
49
|
+
|
|
50
|
+
CLI startup, dev server boot and builds got faster. Nothing here is meant to
|
|
51
|
+
change behaviour — it is all backwards compatible.
|
|
52
|
+
|
|
53
|
+
### Faster
|
|
54
|
+
|
|
55
|
+
- **`check` / `routes` / `docs` / `search` / `add` / `doctor` are about 3x faster**
|
|
56
|
+
(measured: 205ms → 65–75ms). None of them touch Vite or Tailwind, yet the CLI
|
|
57
|
+
loaded both on every invocation. Each command now loads only what it needs.
|
|
58
|
+
The difference shows most when an agent or CI runs `check` and `routes` in a
|
|
59
|
+
loop.
|
|
60
|
+
- **`vantage dev` starts faster** — it used to scan the project four times at
|
|
61
|
+
startup; now it scans once (and generates once instead of twice).
|
|
62
|
+
- **`vantage build` builds the client and the server in parallel** (projects with
|
|
63
|
+
a `server/` only). The log goes from two lines — "Building client…",
|
|
64
|
+
"Building server…" — to a single "Building client and server…".
|
|
65
|
+
- **`vantage check` no longer re-reads the same files** — page modules were read
|
|
66
|
+
three times over and the project tree was walked twice. The bigger the app, the
|
|
67
|
+
bigger the difference.
|
|
68
|
+
- **The dev server rescans less** — creating any directory used to trigger a full
|
|
69
|
+
rescan; now only directories that could hold pages or API modules do.
|
|
70
|
+
- **Dependency prebundling is declared up front** — the kit's dependencies (Base
|
|
71
|
+
UI, ECharts, TanStack Table, …) are handed to Vite ahead of time, so opening a
|
|
72
|
+
page that uses one of those components for the first time no longer triggers
|
|
73
|
+
"new dependencies optimized" followed by a full page reload (on hoisted
|
|
74
|
+
installs, i.e. npm/yarn).
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- **`VANTAGE_PROFILE=1`** (→ [CLI reference](cli-reference)) — prints how long
|
|
79
|
+
each phase of any `vantage` command took, on **stderr**. A measuring point, so
|
|
80
|
+
"it feels slow" can be checked before it is fixed. Nothing goes to stdout, so it
|
|
81
|
+
composes with `--json`.
|
|
82
|
+
|
|
12
83
|
## v0.3.0
|
|
13
84
|
|
|
14
85
|
Vantage now recognises `src/` as a place to put pages. This carries a
|