dsh-codebase-chat 0.22.0 → 0.24.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 +189 -200
- package/dist/cli.js +369 -62
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +64 -2
- package/dist/index.js +364 -61
- package/dist/index.js.map +1 -1
- package/lib/index.js +96 -20
- package/package.json +12 -10
package/lib/index.js
CHANGED
|
@@ -16,9 +16,12 @@ import {
|
|
|
16
16
|
|
|
17
17
|
let analyzeProject;
|
|
18
18
|
let formatHealthReport;
|
|
19
|
+
let getChangedFiles;
|
|
20
|
+
let analyzeImpact;
|
|
21
|
+
let formatImpactReport;
|
|
19
22
|
try {
|
|
20
|
-
({ analyzeProject, formatHealthReport } = await import("../dist/index.js"));
|
|
21
|
-
} catch { analyzeProject = undefined; formatHealthReport = undefined; }
|
|
23
|
+
({ analyzeProject, formatHealthReport, getChangedFiles, analyzeImpact, formatImpactReport } = await import("../dist/index.js"));
|
|
24
|
+
} catch { analyzeProject = undefined; formatHealthReport = undefined; getChangedFiles = undefined; analyzeImpact = undefined; formatImpactReport = undefined; }
|
|
22
25
|
|
|
23
26
|
let defineTool;
|
|
24
27
|
let createUserMessage;
|
|
@@ -32,14 +35,12 @@ try {
|
|
|
32
35
|
const name = "codebase-chat";
|
|
33
36
|
const inject = ["tools", "commands", "agents", "systemPrompt"];
|
|
34
37
|
|
|
35
|
-
const VERSION = "0.
|
|
38
|
+
const VERSION = "0.23.0";
|
|
36
39
|
const execAsync = promisify(exec);
|
|
37
40
|
|
|
38
|
-
const PROTECTED_PATHS =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"marketing-session-app"
|
|
42
|
-
];
|
|
41
|
+
const PROTECTED_PATHS = process.env.DSH_PROTECTED_PATHS
|
|
42
|
+
? process.env.DSH_PROTECTED_PATHS.split(/[;|]/).map((p) => p.trim()).filter(Boolean)
|
|
43
|
+
: [];
|
|
43
44
|
|
|
44
45
|
// Per-project config: .codebase-chat.json at the project root.
|
|
45
46
|
const projectConfigCache = new Map();
|
|
@@ -646,7 +647,7 @@ function buildFilePart(rel, text) {
|
|
|
646
647
|
}
|
|
647
648
|
|
|
648
649
|
async function collectCodebaseContext(projectPath, options = {}) {
|
|
649
|
-
const { focus = "", filePath = "", searchQuery = "", lang = "fr" } = options;
|
|
650
|
+
const { focus = "", filePath = "", searchQuery = "", lang = "fr", diff = "" } = options;
|
|
650
651
|
const isEn = lang === "en";
|
|
651
652
|
const t = isEn ? {
|
|
652
653
|
project: "Project",
|
|
@@ -673,6 +674,14 @@ async function collectCodebaseContext(projectPath, options = {}) {
|
|
|
673
674
|
const absProject = await resolveProjectPath(projectPath);
|
|
674
675
|
const startDir = await findProjectRoot(absProject);
|
|
675
676
|
|
|
677
|
+
// --diff <ref> — scope the gathered context to files changed vs a git ref.
|
|
678
|
+
let diffSet = null;
|
|
679
|
+
if (diff && !filePath && getChangedFiles) {
|
|
680
|
+
const scope = await getChangedFiles(startDir, diff).catch(() => null);
|
|
681
|
+
if (scope?.ok) diffSet = scope.files;
|
|
682
|
+
}
|
|
683
|
+
const inScope = (rel) => !diffSet || diffSet.has(rel);
|
|
684
|
+
|
|
676
685
|
reportProgress("Construction de l'arborescence...");
|
|
677
686
|
const tree = await buildTree(startDir);
|
|
678
687
|
reportProgress("Lecture des fichiers racine...");
|
|
@@ -681,12 +690,15 @@ async function collectCodebaseContext(projectPath, options = {}) {
|
|
|
681
690
|
const fileParts = [];
|
|
682
691
|
|
|
683
692
|
const focusHint = focus ? `\n${t.focus} : ${focus}` : "";
|
|
693
|
+
const scopeHint = diffSet
|
|
694
|
+
? `\n${isEn ? "Scope" : "Périmètre"} : ${diffSet.size} ${isEn ? "file(s) changed vs" : "fichier(s) modifié(s) vs"} ${diff}`
|
|
695
|
+
: "";
|
|
684
696
|
const productConstraints = await extractProductConstraints(absProject);
|
|
685
697
|
const constraintsText = productConstraints.length
|
|
686
698
|
? `\n== ${t.constraints} ==\n${productConstraints.map((c) => `- ${c}`).join("\n")}\n`
|
|
687
699
|
: `\n== ${t.constraints} ==\n${t.noConstraints}\n`;
|
|
688
700
|
|
|
689
|
-
const head = `${t.project} : ${absProject}${focusHint}\n${constraintsText}\n${t.tree} :\n${tree}\n\n${rootResult.prelude}\n`;
|
|
701
|
+
const head = `${t.project} : ${absProject}${focusHint}${scopeHint}\n${constraintsText}\n${t.tree} :\n${tree}\n\n${rootResult.prelude}\n`;
|
|
690
702
|
const headTokens = estimateTokens(head);
|
|
691
703
|
const maxFileTokens = Math.max(0, MAX_CONTEXT_TOKENS - headTokens - 200);
|
|
692
704
|
let usedFileTokens = 0;
|
|
@@ -703,7 +715,8 @@ async function collectCodebaseContext(projectPath, options = {}) {
|
|
|
703
715
|
// Not a file: treat it as a symbol/term and search for it instead of failing.
|
|
704
716
|
reportProgress(isEn ? `File not found, searching symbol: ${filePath}` : `Fichier introuvable, recherche du symbole : ${filePath}`);
|
|
705
717
|
const matches = await searchFiles(absProject, filePath, 20);
|
|
706
|
-
|
|
718
|
+
const scoped = matches.filter(m => inScope(m.rel));
|
|
719
|
+
for (const m of scoped) {
|
|
707
720
|
if (remainingBytes <= 0) break;
|
|
708
721
|
const entry = `--- ${m.rel} ---\n${m.snippet}\n`;
|
|
709
722
|
if (entry.length > remainingBytes) break;
|
|
@@ -716,7 +729,7 @@ async function collectCodebaseContext(projectPath, options = {}) {
|
|
|
716
729
|
|
|
717
730
|
if (searchQuery && !filePath) {
|
|
718
731
|
const matches = await searchFiles(absProject, searchQuery);
|
|
719
|
-
for (const m of matches) {
|
|
732
|
+
for (const m of matches.filter(m => inScope(m.rel))) {
|
|
720
733
|
if (remainingBytes <= 0) break;
|
|
721
734
|
const entry = `--- ${m.rel} ---\n${m.snippet}\n`;
|
|
722
735
|
if (entry.length > remainingBytes) break;
|
|
@@ -734,6 +747,7 @@ async function collectCodebaseContext(projectPath, options = {}) {
|
|
|
734
747
|
const ext = extname(fullPath).toLowerCase();
|
|
735
748
|
if (!SOURCE_EXTS.has(ext)) continue;
|
|
736
749
|
const rel = relative(startDir, fullPath).split(sep).join("/");
|
|
750
|
+
if (!inScope(rel)) continue;
|
|
737
751
|
|
|
738
752
|
const fstats = await fileStats(fullPath);
|
|
739
753
|
if (!fstats) continue;
|
|
@@ -2138,11 +2152,12 @@ function apply(ctx) {
|
|
|
2138
2152
|
filePath: { type: "string", description: "Optional specific file or symbol to focus on." },
|
|
2139
2153
|
crea: { type: "boolean", description: "If true, append a creative 'Fait avec passion par shinzarou-eng <project>' footer." },
|
|
2140
2154
|
creaTheme: { type: "string", description: "Optional creative theme for the footer." },
|
|
2141
|
-
lang: { type: "string", description: "Response language: 'fr' (default) or 'en'." }
|
|
2155
|
+
lang: { type: "string", description: "Response language: 'fr' (default) or 'en'." },
|
|
2156
|
+
diff: { type: "string", description: "Git ref (e.g. 'main', 'HEAD~5'). Scopes the context to files changed vs that ref." }
|
|
2142
2157
|
},
|
|
2143
2158
|
(value) => buildChatPrompt(value.query, value.context, value.projectName, value.crea, value.creaTheme, value.lang),
|
|
2144
2159
|
async (args, exec) => {
|
|
2145
|
-
const { absProject, context } = await collectCodebaseContext(args.projectPath, { focus: args.question, filePath: args.filePath, lang: args.lang });
|
|
2160
|
+
const { absProject, context } = await collectCodebaseContext(args.projectPath, { focus: args.question, filePath: args.filePath, lang: args.lang, diff: args.diff });
|
|
2146
2161
|
const projectName = await getProjectName(absProject);
|
|
2147
2162
|
return { query: args.question, projectName, crea: args.crea || false, creaTheme: args.creaTheme || "", lang: args.lang || "fr", context };
|
|
2148
2163
|
}
|
|
@@ -2157,11 +2172,12 @@ function apply(ctx) {
|
|
|
2157
2172
|
query: { type: "string", description: "Term, symbol, or pattern to search." },
|
|
2158
2173
|
crea: { type: "boolean", description: "If true, append a creative 'Fait avec passion par shinzarou-eng <project>' footer." },
|
|
2159
2174
|
creaTheme: { type: "string", description: "Optional creative theme for the footer." },
|
|
2160
|
-
lang: { type: "string", description: "Response language: 'fr' (default) or 'en'." }
|
|
2175
|
+
lang: { type: "string", description: "Response language: 'fr' (default) or 'en'." },
|
|
2176
|
+
diff: { type: "string", description: "Git ref (e.g. 'main', 'HEAD~5'). Scopes the search to files changed vs that ref." }
|
|
2161
2177
|
},
|
|
2162
2178
|
(value) => buildSearchPrompt(value.query, value.context, value.projectName, value.crea, value.creaTheme, value.lang),
|
|
2163
2179
|
async (args, exec) => {
|
|
2164
|
-
const { absProject, context } = await collectCodebaseContext(args.projectPath, { focus: args.query, searchQuery: args.query, lang: args.lang });
|
|
2180
|
+
const { absProject, context } = await collectCodebaseContext(args.projectPath, { focus: args.query, searchQuery: args.query, lang: args.lang, diff: args.diff });
|
|
2165
2181
|
const projectName = await getProjectName(absProject);
|
|
2166
2182
|
return { query: args.query, projectName, crea: args.crea || false, creaTheme: args.creaTheme || "", lang: args.lang || "fr", context };
|
|
2167
2183
|
}
|
|
@@ -2229,14 +2245,52 @@ function apply(ctx) {
|
|
|
2229
2245
|
"Run a deterministic static analysis of the codebase — circular dependencies, unused files and exports, duplicated code blocks, complexity hotspots, and a health score. Returns concrete findings directly, no LLM needed. Use for 'health', 'dead code', 'circular deps', 'duplication' or 'complexity' requests.",
|
|
2230
2246
|
{
|
|
2231
2247
|
projectPath: { type: "string", description: "Absolute local path to the project folder. If omitted, the project root is auto-detected from the current working directory." },
|
|
2232
|
-
lang: { type: "string", description: "Report language: 'fr' (default) or 'en'." }
|
|
2248
|
+
lang: { type: "string", description: "Report language: 'fr' (default) or 'en'." },
|
|
2249
|
+
diff: { type: "string", description: "Git ref (e.g. 'main', 'HEAD~5'). Scopes the analysis to files changed vs that ref." }
|
|
2233
2250
|
},
|
|
2234
2251
|
(value) => value.markdown || "No report generated.",
|
|
2235
2252
|
async (args, exec) => {
|
|
2236
2253
|
if (!analyzeProject) throw new Error("Static analysis module not available.");
|
|
2237
2254
|
const projectPath = await resolveProjectPath(args.projectPath);
|
|
2238
|
-
|
|
2239
|
-
|
|
2255
|
+
let scope;
|
|
2256
|
+
let scopeLine = "";
|
|
2257
|
+
if (args.diff && getChangedFiles) {
|
|
2258
|
+
const s = await getChangedFiles(await findProjectRoot(projectPath), String(args.diff)).catch(() => null);
|
|
2259
|
+
if (s?.ok) {
|
|
2260
|
+
scope = { files: s.files };
|
|
2261
|
+
scopeLine = (args.lang === "en"
|
|
2262
|
+
? `Scope: ${s.files.size} file(s) changed vs ${args.diff}\n\n`
|
|
2263
|
+
: `Périmètre : ${s.files.size} fichier(s) modifié(s) vs ${args.diff}\n\n`);
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
const report = await analyzeProject(projectPath, scope);
|
|
2267
|
+
return { projectName: basename(report.projectPath), lang: args.lang || "fr", markdown: scopeLine + formatHealthReport(report, args.lang === "en" ? "en" : "fr") };
|
|
2268
|
+
}
|
|
2269
|
+
);
|
|
2270
|
+
|
|
2271
|
+
registerTool(
|
|
2272
|
+
tools,
|
|
2273
|
+
"codebase_impact",
|
|
2274
|
+
"Blast-radius analysis: which files transitively depend on a target file — what breaks if it changes. Deterministic, returns findings directly, no LLM needed. Use for 'impact', 'what breaks', 'dependents', 'who imports X' requests.",
|
|
2275
|
+
{
|
|
2276
|
+
projectPath: { type: "string", description: "Absolute local path to the project folder. If omitted, the project root is auto-detected from the current working directory." },
|
|
2277
|
+
file: { type: "string", description: "File to analyze — relative path or name (e.g. 'src/store.ts'). Required." },
|
|
2278
|
+
lang: { type: "string", description: "Report language: 'fr' (default) or 'en'." }
|
|
2279
|
+
},
|
|
2280
|
+
(value) => value.markdown || "No report generated.",
|
|
2281
|
+
async (args, exec) => {
|
|
2282
|
+
if (!analyzeImpact) throw new Error("Static analysis module not available.");
|
|
2283
|
+
const projectPath = await resolveProjectPath(args.projectPath);
|
|
2284
|
+
const file = String(args.file || "").trim();
|
|
2285
|
+
if (!file) throw new Error("Missing `file` argument (e.g. 'src/store.ts').");
|
|
2286
|
+
const r = await analyzeImpact(projectPath, file);
|
|
2287
|
+
if (!r.ok) {
|
|
2288
|
+
const msg = r.candidates.length
|
|
2289
|
+
? `Cible ambiguë "${file}" — candidats : ${r.candidates.join(', ')}`
|
|
2290
|
+
: `Aucun fichier de code ne correspond à "${file}".`;
|
|
2291
|
+
return { projectName: basename(projectPath), lang: args.lang || "fr", markdown: msg };
|
|
2292
|
+
}
|
|
2293
|
+
return { projectName: basename(r.report.projectPath), lang: args.lang || "fr", markdown: formatImpactReport(r.report, args.lang === "en" ? "en" : "fr") };
|
|
2240
2294
|
}
|
|
2241
2295
|
);
|
|
2242
2296
|
|
|
@@ -2513,6 +2567,28 @@ function apply(ctx) {
|
|
|
2513
2567
|
}
|
|
2514
2568
|
});
|
|
2515
2569
|
|
|
2570
|
+
commands.register({
|
|
2571
|
+
name: "codebase-impact",
|
|
2572
|
+
description: "Analyse d'impact : quels fichiers dépendent de X (rayon d'impact). /codebase-impact <fichier> --project <chemin> [--lang en|fr]",
|
|
2573
|
+
input: { hint: "<fichier>, --project <chemin>, --lang <en|fr>" },
|
|
2574
|
+
async handler(invocation) {
|
|
2575
|
+
if (!analyzeImpact) return { kind: "error", text: "Module d'analyse statique indisponible (build dist manquant)." };
|
|
2576
|
+
const { rawInput } = invocation;
|
|
2577
|
+
const { projectPath, query, filePath, lang } = parseCodebaseInput(rawInput.trim());
|
|
2578
|
+
const file = (filePath || query || "").trim();
|
|
2579
|
+
if (!file) return { kind: "error", text: "Précise un fichier : /codebase-impact src/store.ts" };
|
|
2580
|
+
const absProject = await resolveProjectPath(projectPath);
|
|
2581
|
+
const r = await analyzeImpact(absProject, file);
|
|
2582
|
+
if (!r.ok) {
|
|
2583
|
+
const msg = r.candidates.length
|
|
2584
|
+
? `Cible ambiguë "${file}" — candidats :\n ${r.candidates.join("\n ")}`
|
|
2585
|
+
: `Aucun fichier de code ne correspond à "${file}".`;
|
|
2586
|
+
return { kind: "error", text: msg };
|
|
2587
|
+
}
|
|
2588
|
+
return { kind: "success", text: formatImpactReport(r.report, lang === "en" ? "en" : "fr") };
|
|
2589
|
+
}
|
|
2590
|
+
});
|
|
2591
|
+
|
|
2516
2592
|
commands.register({
|
|
2517
2593
|
name: "codebase-intel",
|
|
2518
2594
|
description: "Brief d'Intelligence Pro : architecture, graphe de modules, data flow, risques, opportunités et créa. /codebase-intel --project <chemin> [focus] [--style <ouf|punchy|dense|pedagogique|minimal>]",
|
|
@@ -2697,7 +2773,7 @@ function apply(ctx) {
|
|
|
2697
2773
|
systemPrompt?.section?.({
|
|
2698
2774
|
name: "codebase-chat",
|
|
2699
2775
|
order: 130,
|
|
2700
|
-
text: `You have access to a powerful codebase plugin (dsh-codebase-chat v${VERSION}). When the user asks about code, files, project structure, architecture, how something works, where something is, or wants to search/explain/refactor/audit/report on code, use the appropriate tool: codebase_chat, codebase_search, codebase_explain, codebase_refactor, codebase_crea, codebase_intelligence, codebase_audit, codebase_report, codebase_ceo, codebase_tasks, codebase_build, codebase_git, codebase_apply, codebase_health, or codebase_player. codebase_health runs a deterministic static analysis (circular deps, dead code, duplication, complexity, health score) and returns findings directly — prefer it when the user asks for measurable code quality. codebase_intelligence is the premium auto-mode: it builds a structured context and asks for a professional, stylish intelligence brief. codebase_ceo is the one-page executive brief: metrics, score cards, top risks, top opportunities, SWOT, killer move, perfect for a board or investor. codebase_audit is the dedicated non-conformity and tech-debt auditor. codebase_report is the executive strategic report: a beautiful, visual, deep assessment (SWOT, score cards, 90-day roadmap, marketing) perfect for boards or clients. codebase_player is the UX / playthrough / player perspective brief: user journey, onboarding, friction, wow moments, gamification, and score cards from a user's point of view.\n\nIf the user asks for raw tasks, a TASKS.md with Avant/Après code blocks, or uses --raw, call codebase_tasks with raw=true. It writes TASKS.md directly in the project and returns the path/content. If the user asks to apply the plan, run the fixes, or says 'apply tasks', call codebase_apply_tasks. Use dryRun=true only if the user asks for a simulation or dry-run. If the user confirms or says 'apply', 'execute', 'yes', or 'oui', call with dryRun=false and apply the patches.\n\nIf no project path is given, first attempt to auto-detect the project root from the current working directory (cwd). Auto-detection walks up the tree looking for package.json, .git or tsconfig.json. Do NOT fall back to any known project (including the 'Dako' alias) unless the user explicitly mentions it. The only recognized alias is 'Dako' for the path 'D:\\Nouveau dossier'; use it only when the user explicitly says 'Dako' or uses --project Dako. If auto-detection fails and no explicit path is provided, ask the user for the path. Always answer in the same language as the user's message. If the user wants a creative idea at the end, set crea=true or use codebase_crea. Users may also use slash commands /codebase, /codebase-search, /codebase-explain, /codebase-refactor, /codebase-crea, /codebase-intel, /codebase-audit, /codebase-report, /codebase-ceo, /codebase-tasks, /codebase-tasks-raw, /codebase-apply-tasks, /codebase-build, /codebase-git, /codebase-apply, /codebase-player.`
|
|
2776
|
+
text: `You have access to a powerful codebase plugin (dsh-codebase-chat v${VERSION}). When the user asks about code, files, project structure, architecture, how something works, where something is, or wants to search/explain/refactor/audit/report on code, use the appropriate tool: codebase_chat, codebase_search, codebase_explain, codebase_refactor, codebase_crea, codebase_intelligence, codebase_audit, codebase_report, codebase_ceo, codebase_tasks, codebase_build, codebase_git, codebase_apply, codebase_health, codebase_impact, or codebase_player. codebase_health runs a deterministic static analysis (circular deps, dead code, duplication, complexity, health score) and returns findings directly. codebase_impact computes the blast radius of a file — which files transitively depend on it — deterministic, no LLM — prefer it when the user asks for measurable code quality. codebase_intelligence is the premium auto-mode: it builds a structured context and asks for a professional, stylish intelligence brief. codebase_ceo is the one-page executive brief: metrics, score cards, top risks, top opportunities, SWOT, killer move, perfect for a board or investor. codebase_audit is the dedicated non-conformity and tech-debt auditor. codebase_report is the executive strategic report: a beautiful, visual, deep assessment (SWOT, score cards, 90-day roadmap, marketing) perfect for boards or clients. codebase_player is the UX / playthrough / player perspective brief: user journey, onboarding, friction, wow moments, gamification, and score cards from a user's point of view.\n\nIf the user asks for raw tasks, a TASKS.md with Avant/Après code blocks, or uses --raw, call codebase_tasks with raw=true. It writes TASKS.md directly in the project and returns the path/content. If the user asks to apply the plan, run the fixes, or says 'apply tasks', call codebase_apply_tasks. Use dryRun=true only if the user asks for a simulation or dry-run. If the user confirms or says 'apply', 'execute', 'yes', or 'oui', call with dryRun=false and apply the patches.\n\nIf no project path is given, first attempt to auto-detect the project root from the current working directory (cwd). Auto-detection walks up the tree looking for package.json, .git or tsconfig.json. Do NOT fall back to any known project (including the 'Dako' alias) unless the user explicitly mentions it. The only recognized alias is 'Dako' for the path 'D:\\Nouveau dossier'; use it only when the user explicitly says 'Dako' or uses --project Dako. If auto-detection fails and no explicit path is provided, ask the user for the path. Always answer in the same language as the user's message. If the user wants a creative idea at the end, set crea=true or use codebase_crea. Users may also use slash commands /codebase, /codebase-search, /codebase-explain, /codebase-refactor, /codebase-crea, /codebase-intel, /codebase-audit, /codebase-report, /codebase-ceo, /codebase-tasks, /codebase-tasks-raw, /codebase-apply-tasks, /codebase-build, /codebase-git, /codebase-apply, /codebase-impact, /codebase-player.`
|
|
2701
2777
|
});
|
|
2702
2778
|
|
|
2703
2779
|
function sameOrigin(req) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codebase-chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Multi-language codebase intelligence for DeepSeek Harness and MCP-compatible IDEs: chat, search, audit, refactor, and board-ready reports from local code.",
|
|
5
5
|
"homepage": "https://shinzarou-eng.github.io/dsh-codebase-chat",
|
|
6
6
|
"repository": {
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"url": "https://github.com/shinzarou-eng/dsh-codebase-chat/issues"
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=20"
|
|
16
|
+
},
|
|
14
17
|
"main": "./dist/index.js",
|
|
15
18
|
"types": "./dist/index.d.ts",
|
|
16
19
|
"bin": {
|
|
@@ -35,14 +38,6 @@
|
|
|
35
38
|
"LICENSE",
|
|
36
39
|
"package.json"
|
|
37
40
|
],
|
|
38
|
-
"scripts": {
|
|
39
|
-
"build": "tsup",
|
|
40
|
-
"dev": "tsup --watch",
|
|
41
|
-
"typecheck": "tsc --noEmit",
|
|
42
|
-
"test": "vitest run",
|
|
43
|
-
"test:watch": "vitest",
|
|
44
|
-
"prepublishOnly": "pnpm build && pnpm test"
|
|
45
|
-
},
|
|
46
41
|
"dsh": {
|
|
47
42
|
"bundle": {
|
|
48
43
|
"patch": "./cordis.patch.yml"
|
|
@@ -91,5 +86,12 @@
|
|
|
91
86
|
"tsup": "^8.5.1",
|
|
92
87
|
"typescript": "5.7.3",
|
|
93
88
|
"vitest": "^5.0.0"
|
|
89
|
+
},
|
|
90
|
+
"scripts": {
|
|
91
|
+
"build": "tsup",
|
|
92
|
+
"dev": "tsup --watch",
|
|
93
|
+
"typecheck": "tsc --noEmit",
|
|
94
|
+
"test": "vitest run",
|
|
95
|
+
"test:watch": "vitest"
|
|
94
96
|
}
|
|
95
|
-
}
|
|
97
|
+
}
|