@reposkein/mcp 0.2.7 → 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 +73 -1
- package/binary-digests.json +4 -4
- package/dist/SKILL.md +63 -1
- package/dist/cli/adr.d.ts +37 -0
- package/dist/cli/adr.js +231 -0
- package/dist/cli/adr.js.map +1 -0
- package/dist/cli/agentAdapters.d.ts +68 -0
- package/dist/cli/agentAdapters.js +223 -0
- package/dist/cli/agentAdapters.js.map +1 -0
- package/dist/cli/ansi.d.ts +24 -0
- package/dist/cli/ansi.js +40 -0
- package/dist/cli/ansi.js.map +1 -0
- package/dist/cli/doctor.d.ts +34 -2
- package/dist/cli/doctor.js +53 -5
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/doctorDecisions.d.ts +5 -0
- package/dist/cli/doctorDecisions.js +83 -0
- package/dist/cli/doctorDecisions.js.map +1 -0
- package/dist/cli/doctorFreshness.d.ts +43 -0
- package/dist/cli/doctorFreshness.js +111 -0
- package/dist/cli/doctorFreshness.js.map +1 -0
- package/dist/cli/doctorSummaries.d.ts +2 -0
- package/dist/cli/doctorSummaries.js +95 -0
- package/dist/cli/doctorSummaries.js.map +1 -0
- package/dist/cli/federatedDiscovery.d.ts +16 -0
- package/dist/cli/federatedDiscovery.js +75 -0
- package/dist/cli/federatedDiscovery.js.map +1 -0
- package/dist/cli/init.d.ts +69 -6
- package/dist/cli/init.js +194 -28
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/sourceSlices.d.ts +17 -0
- package/dist/cli/sourceSlices.js +59 -0
- package/dist/cli/sourceSlices.js.map +1 -0
- package/dist/cli/stats.d.ts +29 -0
- package/dist/cli/stats.js +180 -0
- package/dist/cli/stats.js.map +1 -0
- package/dist/cli/view.d.ts +71 -3
- package/dist/cli/view.js +147 -12
- package/dist/cli/view.js.map +1 -1
- package/dist/guard/decisionValidation.d.ts +29 -0
- package/dist/guard/decisionValidation.js +51 -0
- package/dist/guard/decisionValidation.js.map +1 -0
- package/dist/guard/summaryValidation.d.ts +3 -0
- package/dist/guard/summaryValidation.js +5 -3
- package/dist/guard/summaryValidation.js.map +1 -1
- package/dist/index.d.ts +48 -0
- package/dist/index.js +355 -78
- package/dist/index.js.map +1 -1
- package/dist/indexer/decisionsAffected.d.ts +42 -0
- package/dist/indexer/decisionsAffected.js +149 -0
- package/dist/indexer/decisionsAffected.js.map +1 -0
- package/dist/indexer/fetchBinary.d.ts +14 -0
- package/dist/indexer/fetchBinary.js +81 -40
- package/dist/indexer/fetchBinary.js.map +1 -1
- package/dist/indexer/runIndexer.d.ts +3 -2
- package/dist/indexer/runIndexer.js +8 -4
- package/dist/indexer/runIndexer.js.map +1 -1
- package/dist/profile/decisions.d.ts +37 -0
- package/dist/profile/decisions.js +112 -0
- package/dist/profile/decisions.js.map +1 -0
- package/dist/profile/types.d.ts +8 -0
- package/dist/store/GraphStore.d.ts +5 -0
- package/dist/store/JsonlGraphStore.d.ts +14 -3
- package/dist/store/JsonlGraphStore.js +66 -19
- package/dist/store/JsonlGraphStore.js.map +1 -1
- package/dist/store/decisions.d.ts +131 -0
- package/dist/store/decisions.js +321 -0
- package/dist/store/decisions.js.map +1 -0
- package/dist/store/indexedAt.d.ts +18 -0
- package/dist/store/indexedAt.js +56 -0
- package/dist/store/indexedAt.js.map +1 -0
- package/dist/store/instrumentTool.d.ts +40 -0
- package/dist/store/instrumentTool.js +82 -0
- package/dist/store/instrumentTool.js.map +1 -0
- package/dist/store/repoContextCache.d.ts +15 -0
- package/dist/store/repoContextCache.js +26 -0
- package/dist/store/repoContextCache.js.map +1 -0
- package/dist/store/repoSession.d.ts +63 -0
- package/dist/store/repoSession.js +123 -0
- package/dist/store/repoSession.js.map +1 -0
- package/dist/store/resolveRepoPath.d.ts +31 -0
- package/dist/store/resolveRepoPath.js +85 -0
- package/dist/store/resolveRepoPath.js.map +1 -0
- package/dist/store/sessionLog.d.ts +98 -0
- package/dist/store/sessionLog.js +216 -0
- package/dist/store/sessionLog.js.map +1 -0
- package/dist/store/sessionStats.d.ts +55 -0
- package/dist/store/sessionStats.js +140 -0
- package/dist/store/sessionStats.js.map +1 -0
- package/dist/store/sidecar.d.ts +39 -3
- package/dist/store/sidecar.js +89 -5
- package/dist/store/sidecar.js.map +1 -1
- package/dist/store/summaryShards.d.ts +117 -0
- package/dist/store/summaryShards.js +291 -0
- package/dist/store/summaryShards.js.map +1 -0
- package/dist/store/teamConfig.d.ts +13 -0
- package/dist/store/teamConfig.js +49 -0
- package/dist/store/teamConfig.js.map +1 -0
- package/dist/tools/getContextProfile.d.ts +1 -1
- package/dist/tools/getContextProfile.js +9 -1
- package/dist/tools/getContextProfile.js.map +1 -1
- package/dist/tools/getDecision.d.ts +6 -0
- package/dist/tools/getDecision.js +59 -0
- package/dist/tools/getDecision.js.map +1 -0
- package/dist/tools/impact.d.ts +1 -1
- package/dist/tools/impact.js +13 -1
- package/dist/tools/impact.js.map +1 -1
- package/dist/tools/indexerTools.d.ts +16 -2
- package/dist/tools/indexerTools.js +44 -5
- package/dist/tools/indexerTools.js.map +1 -1
- package/dist/tools/listDecisions.d.ts +19 -0
- package/dist/tools/listDecisions.js +93 -0
- package/dist/tools/listDecisions.js.map +1 -0
- package/dist/tools/reaffirmDecision.d.ts +11 -0
- package/dist/tools/reaffirmDecision.js +55 -0
- package/dist/tools/reaffirmDecision.js.map +1 -0
- package/dist/tools/recordDecision.d.ts +24 -0
- package/dist/tools/recordDecision.js +135 -0
- package/dist/tools/recordDecision.js.map +1 -0
- package/dist/tools/semanticFind.d.ts +9 -2
- package/dist/tools/semanticFind.js +44 -2
- package/dist/tools/semanticFind.js.map +1 -1
- package/dist/tools/setDecisionStatus.d.ts +8 -0
- package/dist/tools/setDecisionStatus.js +34 -0
- package/dist/tools/setDecisionStatus.js.map +1 -0
- package/dist/viz/assets/{graph.worker-CC7BeE-8.js → graph.worker-DkH6-lMU.js} +1 -1
- package/dist/viz/assets/index-CxqeGuRS.css +1 -0
- package/dist/viz/assets/index-DiNZyrXx.js +9 -0
- package/dist/viz/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/viz/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/dist/viz/assets/jetbrains-mono-latin-700-normal-BYuf6tUa.woff2 +0 -0
- package/dist/viz/assets/r3f-BZY3QR6_.js +336 -0
- package/dist/viz/assets/tanstack-CjXr-L-s.js +62 -0
- package/dist/viz/assets/three-Cpu5RUEM.js +4116 -0
- package/dist/viz/index.html +5 -4
- package/package.json +5 -4
- package/dist/viz/assets/index-C_8UkiJ8.js +0 -9
- package/dist/viz/assets/r3f-Cku1OhB-.js +0 -277
- package/dist/viz/assets/tanstack-DyXcNRWk.js +0 -77
- package/dist/viz/assets/three-Z8XaLGmf.js +0 -3839
package/dist/cli/init.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { mkdirSync, copyFileSync, existsSync, readFileSync, appendFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, copyFileSync, existsSync, readFileSync, appendFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
2
3
|
import { join } from "node:path";
|
|
3
|
-
import { ensureIndexerBinary, packageRoot } from "../indexer/fetchBinary.js";
|
|
4
|
+
import { ensureIndexerBinary, packageRoot, platformKey, cargoInstallFallbackMessage } from "../indexer/fetchBinary.js";
|
|
4
5
|
import { spawnIndexer } from "../indexer/runIndexer.js";
|
|
6
|
+
import { writeAgentConfigs, formatAdapterResult } from "./agentAdapters.js";
|
|
7
|
+
import { runChecks, renderDoctorReport } from "./doctor.js";
|
|
8
|
+
import { writeIndexedAtMarker } from "../store/indexedAt.js";
|
|
5
9
|
/** Where the navigation skill is installed for a repo (Claude project skills). */
|
|
6
10
|
export function skillTargetPath(repoPath) {
|
|
7
11
|
return join(repoPath, ".claude", "skills", "reposkein-graph-rag", "SKILL.md");
|
|
@@ -22,8 +26,9 @@ export function mcpConfigSnippet(repoPath) {
|
|
|
22
26
|
}, null, 2);
|
|
23
27
|
}
|
|
24
28
|
/** Per-machine MCP config files setup writes to a repo root: they hold absolute
|
|
25
|
-
* paths and a local backend password, so they must never be committed.
|
|
26
|
-
|
|
29
|
+
* paths and a local backend password, so they must never be committed.
|
|
30
|
+
* Written as gitignore patterns (always forward-slash, regardless of OS). */
|
|
31
|
+
const LOCAL_MCP_CONFIG_FILES = [".mcp.json", "opencode.json", ".cursor/mcp.json"];
|
|
27
32
|
/** Idempotently add the per-machine MCP config files to the repo's .gitignore
|
|
28
33
|
* (creating it if absent), so `reposkein-mcp init` never leaves them tracked. */
|
|
29
34
|
export function ensureLocalConfigGitignored(repoPath) {
|
|
@@ -41,9 +46,99 @@ export function ensureLocalConfigGitignored(repoPath) {
|
|
|
41
46
|
appendFileSync(gitignorePath, block);
|
|
42
47
|
console.error(`reposkein: gitignored ${missing.join(", ")} (per-machine config, never commit)`);
|
|
43
48
|
}
|
|
49
|
+
/** True when `.reposkein/meta.json` is tracked by git — this clone joined a
|
|
50
|
+
* repo that already has RepoSkein set up (someone else ran `init` and
|
|
51
|
+
* committed it), rather than being the first machine to set it up (whose
|
|
52
|
+
* meta.json exists on disk but isn't committed yet). Join mode skips
|
|
53
|
+
* first-time scaffolding entirely and instead wires up the local agent(s)
|
|
54
|
+
* automatically (REP-16 T5) — see `runInit`.
|
|
55
|
+
*
|
|
56
|
+
* Falls back to plain existence when git itself is unavailable (no `git`
|
|
57
|
+
* binary, or `repoPath` isn't a git repo yet) so `init` still behaves
|
|
58
|
+
* sensibly outside a git repo rather than throwing. */
|
|
59
|
+
export function detectJoinMode(repoPath) {
|
|
60
|
+
if (!existsSync(join(repoPath, ".reposkein", "meta.json")))
|
|
61
|
+
return false;
|
|
62
|
+
try {
|
|
63
|
+
execFileSync("git", ["ls-files", "--error-unmatch", ".reposkein/meta.json"], {
|
|
64
|
+
cwd: repoPath,
|
|
65
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
66
|
+
});
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Where `init --ci` writes the Pages-publish workflow in the target repo. */
|
|
74
|
+
export function ciWorkflowTargetPath(repoPath) {
|
|
75
|
+
return join(repoPath, ".github", "workflows", "reposkein-pages.yml");
|
|
76
|
+
}
|
|
77
|
+
/** Template written by `reposkein-mcp init --ci`: a thin caller of RepoSkein's
|
|
78
|
+
* reusable publish workflow (see docs/HOSTING.md). Consumers get released
|
|
79
|
+
* indexer binaries (no Rust toolchain) + a self-contained static export
|
|
80
|
+
* published to GitHub Pages. Repo owners must still flip Settings → Pages →
|
|
81
|
+
* "Build and deployment: GitHub Actions" once. */
|
|
82
|
+
export function ciWorkflowTemplate() {
|
|
83
|
+
return `name: Publish RepoSkein constellation (GitHub Pages)
|
|
84
|
+
|
|
85
|
+
# Generated by \`reposkein-mcp init --ci\`. See docs/HOSTING.md — "Host your
|
|
86
|
+
# constellation" — before enabling: GitHub Pages is PUBLIC by default unless
|
|
87
|
+
# you're on GitHub Enterprise with private Pages enabled.
|
|
88
|
+
#
|
|
89
|
+
# ONE-TIME SETUP (repo owner): Settings → Pages → Build and deployment →
|
|
90
|
+
# Source: "GitHub Actions".
|
|
91
|
+
|
|
92
|
+
on:
|
|
93
|
+
push:
|
|
94
|
+
branches: [main]
|
|
95
|
+
workflow_dispatch: {}
|
|
96
|
+
|
|
97
|
+
concurrency:
|
|
98
|
+
group: pages
|
|
99
|
+
cancel-in-progress: false
|
|
100
|
+
|
|
101
|
+
permissions:
|
|
102
|
+
contents: read
|
|
103
|
+
pages: write
|
|
104
|
+
id-token: write
|
|
105
|
+
|
|
106
|
+
jobs:
|
|
107
|
+
publish:
|
|
108
|
+
uses: reposkein/reposkein/.github/workflows/publish-pages.yml@main
|
|
109
|
+
permissions:
|
|
110
|
+
contents: read
|
|
111
|
+
pages: write
|
|
112
|
+
id-token: write
|
|
113
|
+
with:
|
|
114
|
+
repo-path: "."
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
/** `reposkein-mcp init --ci`: writes the Pages-publish workflow template into
|
|
118
|
+
* the target repo's `.github/workflows/`. Non-destructive: skips (with a
|
|
119
|
+
* message) if the file already exists, so a re-run never clobbers a repo
|
|
120
|
+
* owner's edits. Returns whether it wrote the file. */
|
|
121
|
+
export function writeCiWorkflow(repoPath) {
|
|
122
|
+
const path = ciWorkflowTargetPath(repoPath);
|
|
123
|
+
if (existsSync(path)) {
|
|
124
|
+
console.error(`reposkein: ${path} already exists — leaving it untouched.`);
|
|
125
|
+
return { written: false, path };
|
|
126
|
+
}
|
|
127
|
+
mkdirSync(join(path, ".."), { recursive: true });
|
|
128
|
+
writeFileSync(path, ciWorkflowTemplate(), "utf8");
|
|
129
|
+
console.error(`reposkein: wrote ${path} (see docs/HOSTING.md before enabling GitHub Pages).`);
|
|
130
|
+
return { written: true, path };
|
|
131
|
+
}
|
|
44
132
|
/** `reposkein-mcp index [path]`: (re)build the code graph at `repoPath` using the
|
|
45
133
|
* native indexer. The package-friendly way to index — the `reposkein-indexer`
|
|
46
|
-
* binary is fetched into the package (not on PATH), so end users run this.
|
|
134
|
+
* binary is fetched into the package (not on PATH), so end users run this.
|
|
135
|
+
* On success, also records the current git HEAD to `.reposkein/local/indexed-at`
|
|
136
|
+
* — `doctor --ci`'s `graph_stale` check reads it back (see doctorFreshness.ts).
|
|
137
|
+
* The installed git hooks maintain the same marker themselves (`post-commit`
|
|
138
|
+
* after every commit, `post-merge`/`post-checkout` — which also re-index —
|
|
139
|
+
* after a merge/pull/branch switch; see the hook templates in
|
|
140
|
+
* indexer/crates/cli/src/main.rs), so this mcp-side write is the "manual
|
|
141
|
+
* index" case, not the only path that keeps the marker current. */
|
|
47
142
|
export async function runIndex(repoPath = ".") {
|
|
48
143
|
const bin = await ensureIndexerBinary();
|
|
49
144
|
const r = await spawnIndexer(bin, ["index", repoPath]);
|
|
@@ -52,26 +147,74 @@ export async function runIndex(repoPath = ".") {
|
|
|
52
147
|
if (r.code !== 0) {
|
|
53
148
|
console.error(`reposkein: index failed: ${r.stderr || r.stdout}`);
|
|
54
149
|
}
|
|
150
|
+
else {
|
|
151
|
+
writeIndexedAtMarker(repoPath);
|
|
152
|
+
}
|
|
55
153
|
return r.code;
|
|
56
154
|
}
|
|
57
|
-
/** `reposkein-mcp init [path] [--no-index]
|
|
58
|
-
*
|
|
59
|
-
*
|
|
155
|
+
/** `reposkein-mcp init [path] [--no-index] [--ci] [--agents <list>] [--dry-run]`:
|
|
156
|
+
* ensure the indexer, install git hooks, build the initial graph, install
|
|
157
|
+
* the navigation skill, then either (join mode) auto-write the local
|
|
158
|
+
* agent(s) MCP config, or (first-time) print the config snippet to paste in
|
|
159
|
+
* by hand. Pass `index: false` to skip the initial index; `ci: true` to
|
|
160
|
+
* also write the GitHub Pages publish workflow (see docs/HOSTING.md).
|
|
161
|
+
*
|
|
162
|
+
* Join mode (REP-16 T5): auto-detected when `.reposkein/meta.json` is
|
|
163
|
+
* already committed (`detectJoinMode`) — i.e. someone cloned a repo that
|
|
164
|
+
* already has RepoSkein set up. Skips nothing structural (hooks/index/skill
|
|
165
|
+
* still run so a stale local checkout gets caught up) but additionally
|
|
166
|
+
* writes `.mcp.json` / `opencode.json` / `.cursor/mcp.json` for whichever
|
|
167
|
+
* agent(s) are detected present (or `opts.agents`), then prints a doctor
|
|
168
|
+
* summary instead of a config snippet to copy by hand.
|
|
169
|
+
*
|
|
170
|
+
* Unsupported platform (darwin-x64, win32-arm64, no REPOSKEIN_INDEXER_BIN):
|
|
171
|
+
* prints cargo-install fallback instructions and CONTINUES instead of
|
|
172
|
+
* crashing — hooks + the initial index are skipped (nothing to run them
|
|
173
|
+
* with), but the skill, CI workflow, and (in join mode) agent config are
|
|
174
|
+
* still written, and the function returns 0. */
|
|
60
175
|
export async function runInit(repoPath = ".", opts = {}) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
176
|
+
const joinMode = opts.join ?? detectJoinMode(repoPath);
|
|
177
|
+
if (joinMode) {
|
|
178
|
+
console.error("reposkein: found a committed .reposkein/meta.json — joining an existing repo " +
|
|
179
|
+
"(skipping first-time scaffolding; wiring up your agent(s) automatically).");
|
|
180
|
+
}
|
|
181
|
+
// 1) Indexer binary — but only attempt it on a platform that has one (or
|
|
182
|
+
// with an explicit offline override). Everything binary-dependent below
|
|
183
|
+
// degrades to a warning instead of crashing when neither is true.
|
|
184
|
+
const platformSupported = platformKey() !== null || !!process.env.REPOSKEIN_INDEXER_BIN;
|
|
185
|
+
let bin = null;
|
|
186
|
+
if (!platformSupported) {
|
|
187
|
+
console.error(cargoInstallFallbackMessage());
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
bin = await ensureIndexerBinary();
|
|
191
|
+
}
|
|
192
|
+
// 2) Git hooks (needs the indexer binary + a git repo). Also strips any
|
|
193
|
+
// merge declaration an older RepoSkein left behind for the derived
|
|
194
|
+
// JSONL, which is no longer committed.
|
|
195
|
+
let hooksOk = false;
|
|
196
|
+
if (bin) {
|
|
197
|
+
try {
|
|
198
|
+
const r = await spawnIndexer(bin, ["init", "--hooks", repoPath]);
|
|
199
|
+
if (r.code !== 0) {
|
|
200
|
+
console.error(`reposkein: indexer init failed: ${r.stderr || r.stdout}`);
|
|
201
|
+
console.error(" (is this a git repository? run `git init` first.)");
|
|
202
|
+
return 1;
|
|
203
|
+
}
|
|
204
|
+
hooksOk = true;
|
|
205
|
+
// 2b) Keep the per-machine MCP config out of git; only .reposkein/ is shared.
|
|
206
|
+
ensureLocalConfigGitignored(repoPath);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
console.error(`reposkein: could not run the indexer binary (${err instanceof Error ? err.message : String(err)}).\n` +
|
|
210
|
+
" Set REPOSKEIN_INDEXER_BIN to a working `reposkein-indexer` path and re-run.");
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
console.error("reposkein: skipping git hook install and the initial index — no indexer binary for this platform.");
|
|
70
215
|
}
|
|
71
|
-
// 2b) Keep the per-machine MCP config out of git; only .reposkein/ is shared.
|
|
72
|
-
ensureLocalConfigGitignored(repoPath);
|
|
73
216
|
// 3) Build the initial code graph (the whole point of setup) unless opted out.
|
|
74
|
-
if (opts.index !== false) {
|
|
217
|
+
if (bin && hooksOk && opts.index !== false) {
|
|
75
218
|
console.error("reposkein: building the initial code graph…");
|
|
76
219
|
const ic = await runIndex(repoPath);
|
|
77
220
|
if (ic !== 0) {
|
|
@@ -89,14 +232,37 @@ export async function runInit(repoPath = ".", opts = {}) {
|
|
|
89
232
|
else {
|
|
90
233
|
console.error("reposkein: bundled SKILL.md not found; skipping skill install.");
|
|
91
234
|
}
|
|
92
|
-
// 5)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"\
|
|
99
|
-
|
|
235
|
+
// 5) Optionally write the GitHub Pages publish workflow.
|
|
236
|
+
if (opts.ci)
|
|
237
|
+
writeCiWorkflow(repoPath);
|
|
238
|
+
// 6) Join mode: auto-write agent MCP config + a doctor summary. First-time
|
|
239
|
+
// setup: print the config snippet for the user to paste in by hand.
|
|
240
|
+
if (joinMode) {
|
|
241
|
+
console.error("\nreposkein: wiring up local agent MCP config…");
|
|
242
|
+
const results = writeAgentConfigs(repoPath, {
|
|
243
|
+
agents: opts.agents,
|
|
244
|
+
dryRun: opts.dryRun,
|
|
245
|
+
...opts.agentWriteOpts,
|
|
246
|
+
});
|
|
247
|
+
for (const r of results)
|
|
248
|
+
console.error(formatAdapterResult(r));
|
|
249
|
+
if (opts.dryRun) {
|
|
250
|
+
console.error("\nreposkein: --dry-run — no config files were written. Re-run without --dry-run to apply.");
|
|
251
|
+
}
|
|
252
|
+
console.error("\nreposkein: doctor summary\n");
|
|
253
|
+
console.error(renderDoctorReport(await runChecks(repoPath)));
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
console.error("\nreposkein: ready. Add this MCP server to your client config:\n");
|
|
257
|
+
console.error(mcpConfigSnippet(repoPath));
|
|
258
|
+
console.error("\nCommit .reposkein/meta.json, config.toml, .gitignore, .gitattributes and summaries/. " +
|
|
259
|
+
"nodes.jsonl and edges.jsonl are derived from your working tree and git-ignored: every clone " +
|
|
260
|
+
"rebuilds them in seconds, and committing them would conflict on every branch that touches code. " +
|
|
261
|
+
"Authored summaries live in .reposkein/summaries/<xx>.jsonl — one small file per hash bucket, so " +
|
|
262
|
+
"two branches summarising different code never touch the same file." +
|
|
263
|
+
"\nVerify anytime with `reposkein-mcp doctor`; re-index after big changes with `reposkein-mcp index` " +
|
|
264
|
+
"(or the agent's reindex_file / init_cpg_skeleton tools).");
|
|
265
|
+
}
|
|
100
266
|
return 0;
|
|
101
267
|
}
|
|
102
268
|
//# sourceMappingURL=init.js.map
|
package/dist/cli/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface SourceSliceEntry {
|
|
2
|
+
path: string;
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
lines: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface CollectSourceSlicesDeps {
|
|
8
|
+
/** Reads a file's text given its absolute path. Injected for testability. */
|
|
9
|
+
readFile?: (absPath: string) => string;
|
|
10
|
+
}
|
|
11
|
+
/** Reads `nodesText` (JSONL) and, for every node carrying a file_path/path plus
|
|
12
|
+
* start_line/end_line, slices that range out of the source file — keyed by
|
|
13
|
+
* node id. Stops as soon as the running byte total would exceed `maxBytes`
|
|
14
|
+
* (deterministic: first-in-file-order nodes win, so a fixed input always
|
|
15
|
+
* bakes the same slice set). Best-effort per-file: a file that can't be read
|
|
16
|
+
* is skipped, not fatal. Pure aside from the injected `readFile`. */
|
|
17
|
+
export declare function collectSourceSlices(repoPath: string, nodesText: string, maxBytes: number, deps?: CollectSourceSlicesDeps): Record<string, SourceSliceEntry>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** Reads `nodesText` (JSONL) and, for every node carrying a file_path/path plus
|
|
4
|
+
* start_line/end_line, slices that range out of the source file — keyed by
|
|
5
|
+
* node id. Stops as soon as the running byte total would exceed `maxBytes`
|
|
6
|
+
* (deterministic: first-in-file-order nodes win, so a fixed input always
|
|
7
|
+
* bakes the same slice set). Best-effort per-file: a file that can't be read
|
|
8
|
+
* is skipped, not fatal. Pure aside from the injected `readFile`. */
|
|
9
|
+
export function collectSourceSlices(repoPath, nodesText, maxBytes, deps = {}) {
|
|
10
|
+
const readFile = deps.readFile ?? ((p) => readFileSync(p, "utf8"));
|
|
11
|
+
const out = {};
|
|
12
|
+
const fileCache = new Map();
|
|
13
|
+
let used = 0;
|
|
14
|
+
for (const line of nodesText.split("\n")) {
|
|
15
|
+
if (!line.trim())
|
|
16
|
+
continue;
|
|
17
|
+
let node;
|
|
18
|
+
try {
|
|
19
|
+
node = JSON.parse(line);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const id = node.id;
|
|
25
|
+
const props = node.props ?? {};
|
|
26
|
+
const filePath = props["file_path"] ?? props["path"];
|
|
27
|
+
const start = props["start_line"];
|
|
28
|
+
const end = props["end_line"];
|
|
29
|
+
if (typeof id !== "string" ||
|
|
30
|
+
typeof filePath !== "string" ||
|
|
31
|
+
typeof start !== "number" ||
|
|
32
|
+
typeof end !== "number" ||
|
|
33
|
+
end < start ||
|
|
34
|
+
start < 1) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
let fileLines = fileCache.get(filePath);
|
|
38
|
+
if (fileLines === undefined) {
|
|
39
|
+
try {
|
|
40
|
+
fileLines = readFile(join(repoPath, filePath)).split("\n");
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
fileLines = null;
|
|
44
|
+
}
|
|
45
|
+
fileCache.set(filePath, fileLines);
|
|
46
|
+
}
|
|
47
|
+
if (fileLines === null)
|
|
48
|
+
continue;
|
|
49
|
+
const lines = fileLines.slice(start - 1, end);
|
|
50
|
+
const entry = { path: filePath, start, end, lines };
|
|
51
|
+
const size = Buffer.byteLength(JSON.stringify(entry), "utf8");
|
|
52
|
+
if (used + size > maxBytes)
|
|
53
|
+
break; // deterministic cap: stop at the first node that overflows
|
|
54
|
+
used += size;
|
|
55
|
+
out[id] = entry;
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=sourceSlices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourceSlices.js","sourceRoot":"","sources":["../../src/cli/sourceSlices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAcjC;;;;;sEAKsE;AACtE,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,SAAiB,EACjB,QAAgB,EAChB,OAAgC,EAAE;IAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3E,MAAM,GAAG,GAAqC,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,IAAI,GAAG,EAA2B,CAAC;IACrD,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,IAAuD,CAAC;QAC5D,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAsD,CAAC;QAC/E,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9B,IACE,OAAO,EAAE,KAAK,QAAQ;YACtB,OAAO,QAAQ,KAAK,QAAQ;YAC5B,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,GAAG,KAAK,QAAQ;YACvB,GAAG,GAAG,KAAK;YACX,KAAK,GAAG,CAAC,EACT,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC7D,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,GAAG,IAAI,CAAC;YACnB,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACrC,CAAC;QACD,IAAI,SAAS,KAAK,IAAI;YAAE,SAAS;QAEjC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAqB,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;QAC9D,IAAI,IAAI,GAAG,IAAI,GAAG,QAAQ;YAAE,MAAM,CAAC,2DAA2D;QAC9F,IAAI,IAAI,IAAI,CAAC;QACb,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;IAClB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type SessionSummary } from "../store/sessionStats.js";
|
|
2
|
+
export interface StatsSelection {
|
|
3
|
+
mode: "last" | "session" | "all";
|
|
4
|
+
sessionId?: string;
|
|
5
|
+
}
|
|
6
|
+
/** Parses `reposkein-mcp stats [path] [--last | --session <id> | --all] [--json]`.
|
|
7
|
+
* Exactly one of `--last` / `--session` / `--all` may be given; defaults to
|
|
8
|
+
* `--last` (the useful default for a Stop-hook running right after a
|
|
9
|
+
* session ends). */
|
|
10
|
+
export declare function parseStatsArgs(argv: string[]): {
|
|
11
|
+
path?: string;
|
|
12
|
+
selection: StatsSelection;
|
|
13
|
+
json: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
};
|
|
16
|
+
/** Resolves which session(s) `selection` refers to and aggregates them.
|
|
17
|
+
* Returns null (with `error` populated) when nothing was found — a repo
|
|
18
|
+
* with no `.reposkein/local/sessions/` yet, an unknown `--session` id, etc. */
|
|
19
|
+
export declare function resolveStats(repoPath: string, selection: StatsSelection): {
|
|
20
|
+
summary?: SessionSummary;
|
|
21
|
+
error?: string;
|
|
22
|
+
};
|
|
23
|
+
/** Renders the terminal report for one summary. `color` selects styled vs.
|
|
24
|
+
* plain output — callers pass `colorEnabled()`'s result (TTY + no NO_COLOR). */
|
|
25
|
+
export declare function renderStatsReport(summary: SessionSummary, color: boolean): string;
|
|
26
|
+
export declare function renderStatsJson(summary: SessionSummary): string;
|
|
27
|
+
/** Entry point for `reposkein-mcp stats [path] [--last | --session <id> | --all] [--json]`.
|
|
28
|
+
* Returns the process exit code. */
|
|
29
|
+
export declare function runStats(argv: string[], cwd: string, envRepoPath: string | undefined): number;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { resolveRepoPath } from "../store/resolveRepoPath.js";
|
|
2
|
+
import { GREP_BASELINE_MULTIPLIER, listSessionFiles, readSessionLog, summarizeSession, summarizeSessions } from "../store/sessionStats.js";
|
|
3
|
+
import { colorEnabled, styler } from "./ansi.js";
|
|
4
|
+
/** Parses `reposkein-mcp stats [path] [--last | --session <id> | --all] [--json]`.
|
|
5
|
+
* Exactly one of `--last` / `--session` / `--all` may be given; defaults to
|
|
6
|
+
* `--last` (the useful default for a Stop-hook running right after a
|
|
7
|
+
* session ends). */
|
|
8
|
+
export function parseStatsArgs(argv) {
|
|
9
|
+
let path;
|
|
10
|
+
let json = false;
|
|
11
|
+
let selection;
|
|
12
|
+
for (let i = 0; i < argv.length; i++) {
|
|
13
|
+
const arg = argv[i];
|
|
14
|
+
if (arg === "--json") {
|
|
15
|
+
json = true;
|
|
16
|
+
}
|
|
17
|
+
else if (arg === "--last") {
|
|
18
|
+
if (selection)
|
|
19
|
+
return { selection: { mode: "last" }, json, error: "pass only one of --last / --session / --all" };
|
|
20
|
+
selection = { mode: "last" };
|
|
21
|
+
}
|
|
22
|
+
else if (arg === "--all") {
|
|
23
|
+
if (selection)
|
|
24
|
+
return { selection: { mode: "all" }, json, error: "pass only one of --last / --session / --all" };
|
|
25
|
+
selection = { mode: "all" };
|
|
26
|
+
}
|
|
27
|
+
else if (arg === "--session") {
|
|
28
|
+
if (selection)
|
|
29
|
+
return { selection: { mode: "session" }, json, error: "pass only one of --last / --session / --all" };
|
|
30
|
+
const id = argv[i + 1];
|
|
31
|
+
if (!id || id.startsWith("-"))
|
|
32
|
+
return { selection: { mode: "session" }, json, error: "--session requires a session id" };
|
|
33
|
+
selection = { mode: "session", sessionId: id };
|
|
34
|
+
i++;
|
|
35
|
+
}
|
|
36
|
+
else if (arg && !arg.startsWith("-")) {
|
|
37
|
+
path = arg;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { path, selection: selection ?? { mode: "last" }, json };
|
|
41
|
+
}
|
|
42
|
+
/** Resolves which session(s) `selection` refers to and aggregates them.
|
|
43
|
+
* Returns null (with `error` populated) when nothing was found — a repo
|
|
44
|
+
* with no `.reposkein/local/sessions/` yet, an unknown `--session` id, etc. */
|
|
45
|
+
export function resolveStats(repoPath, selection) {
|
|
46
|
+
const files = listSessionFiles(repoPath);
|
|
47
|
+
if (selection.mode === "all") {
|
|
48
|
+
if (files.length === 0)
|
|
49
|
+
return { error: `no session logs found under ${repoPath}/.reposkein/local/sessions/` };
|
|
50
|
+
return { summary: summarizeSessions(files) };
|
|
51
|
+
}
|
|
52
|
+
if (selection.mode === "session") {
|
|
53
|
+
const hit = files.find((f) => f.sessionId === selection.sessionId);
|
|
54
|
+
if (!hit) {
|
|
55
|
+
return {
|
|
56
|
+
error: `no session "${selection.sessionId}" found under ${repoPath}/.reposkein/local/sessions/` +
|
|
57
|
+
(files.length ? ` (known: ${files.map((f) => f.sessionId).join(", ")})` : ""),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return { summary: summarizeSession(hit.sessionId, hit.file, readSessionLog(hit.file)) };
|
|
61
|
+
}
|
|
62
|
+
// "last"
|
|
63
|
+
if (files.length === 0)
|
|
64
|
+
return { error: `no session logs found under ${repoPath}/.reposkein/local/sessions/` };
|
|
65
|
+
const hit = files[0];
|
|
66
|
+
return { summary: summarizeSession(hit.sessionId, hit.file, readSessionLog(hit.file)) };
|
|
67
|
+
}
|
|
68
|
+
function formatDuration(ms) {
|
|
69
|
+
if (ms <= 0)
|
|
70
|
+
return "< 1s";
|
|
71
|
+
const totalSec = Math.round(ms / 1000);
|
|
72
|
+
const h = Math.floor(totalSec / 3600);
|
|
73
|
+
const m = Math.floor((totalSec % 3600) / 60);
|
|
74
|
+
const s = totalSec % 60;
|
|
75
|
+
const parts = [];
|
|
76
|
+
if (h)
|
|
77
|
+
parts.push(`${h}h`);
|
|
78
|
+
if (m)
|
|
79
|
+
parts.push(`${m}m`);
|
|
80
|
+
if (s || parts.length === 0)
|
|
81
|
+
parts.push(`${s}s`);
|
|
82
|
+
return parts.join(" ");
|
|
83
|
+
}
|
|
84
|
+
function formatBytes(n) {
|
|
85
|
+
if (n < 1024)
|
|
86
|
+
return `${n} B`;
|
|
87
|
+
if (n < 1024 * 1024)
|
|
88
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
89
|
+
return `${(n / (1024 * 1024)).toFixed(1)} MB`;
|
|
90
|
+
}
|
|
91
|
+
/** Renders the terminal report for one summary. `color` selects styled vs.
|
|
92
|
+
* plain output — callers pass `colorEnabled()`'s result (TTY + no NO_COLOR). */
|
|
93
|
+
export function renderStatsReport(summary, color) {
|
|
94
|
+
const c = styler(color);
|
|
95
|
+
const lines = [];
|
|
96
|
+
lines.push(c.bold(c.teal(`reposkein stats — session ${summary.sessionId}`)));
|
|
97
|
+
lines.push("");
|
|
98
|
+
lines.push(c.bold("Calls by tool"));
|
|
99
|
+
const tools = Object.entries(summary.callsByTool).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
100
|
+
if (tools.length === 0) {
|
|
101
|
+
lines.push(" (none)");
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
for (const [tool, count] of tools)
|
|
105
|
+
lines.push(` ${String(count).padStart(4)} ${tool}`);
|
|
106
|
+
}
|
|
107
|
+
lines.push("");
|
|
108
|
+
lines.push(c.bold("Top queried nodes/files"));
|
|
109
|
+
if (summary.topTouched.length === 0) {
|
|
110
|
+
lines.push(" (none recorded)");
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
for (const { id, count } of summary.topTouched)
|
|
114
|
+
lines.push(` ${String(count).padStart(4)} ${id}`);
|
|
115
|
+
}
|
|
116
|
+
lines.push("");
|
|
117
|
+
lines.push(c.bold("Written this session"));
|
|
118
|
+
lines.push(` ${summary.decisionsWritten} ADR${summary.decisionsWritten === 1 ? "" : "s"} (record_decision)`);
|
|
119
|
+
lines.push(` ${summary.summariesWritten} summar${summary.summariesWritten === 1 ? "y" : "ies"} (write_semantic_summary)`);
|
|
120
|
+
lines.push("");
|
|
121
|
+
lines.push(c.bold("Session"));
|
|
122
|
+
lines.push(` ${summary.recordCount} call${summary.recordCount === 1 ? "" : "s"}, duration ${formatDuration(summary.durationMs)}`);
|
|
123
|
+
if (summary.failedCalls > 0)
|
|
124
|
+
lines.push(` ${c.amber(`${summary.failedCalls} failed call${summary.failedCalls === 1 ? "" : "s"}`)}`);
|
|
125
|
+
lines.push("");
|
|
126
|
+
lines.push(c.bold(c.amber("Estimated context tokens saved vs. grep")));
|
|
127
|
+
lines.push(` ~${summary.estimatedRepoSkeinTokens.toLocaleString()} tokens returned` +
|
|
128
|
+
` (${formatBytes(summary.totalResultBytes)}) · ` +
|
|
129
|
+
`an equivalent grep-based agent would cost an ESTIMATED ~${summary.estimatedGrepTokens.toLocaleString()} tokens` +
|
|
130
|
+
` (${GREP_BASELINE_MULTIPLIER}x, mcp/bench Track 1 mean) · ` +
|
|
131
|
+
`~${summary.estimatedTokensSaved.toLocaleString()} tokens saved (estimate, not measured this session)`);
|
|
132
|
+
return lines.join("\n");
|
|
133
|
+
}
|
|
134
|
+
export function renderStatsJson(summary) {
|
|
135
|
+
return JSON.stringify({
|
|
136
|
+
sessionId: summary.sessionId,
|
|
137
|
+
recordCount: summary.recordCount,
|
|
138
|
+
callsByTool: summary.callsByTool,
|
|
139
|
+
topTouched: summary.topTouched,
|
|
140
|
+
decisionsWritten: summary.decisionsWritten,
|
|
141
|
+
summariesWritten: summary.summariesWritten,
|
|
142
|
+
durationMs: summary.durationMs,
|
|
143
|
+
failedCalls: summary.failedCalls,
|
|
144
|
+
totalResultBytes: summary.totalResultBytes,
|
|
145
|
+
grepBaselineMultiplier: GREP_BASELINE_MULTIPLIER,
|
|
146
|
+
estimatedRepoSkeinTokens: summary.estimatedRepoSkeinTokens,
|
|
147
|
+
estimatedGrepTokens: summary.estimatedGrepTokens,
|
|
148
|
+
estimatedTokensSaved: summary.estimatedTokensSaved,
|
|
149
|
+
estimate: true,
|
|
150
|
+
}, null, 2);
|
|
151
|
+
}
|
|
152
|
+
/** Entry point for `reposkein-mcp stats [path] [--last | --session <id> | --all] [--json]`.
|
|
153
|
+
* Returns the process exit code. */
|
|
154
|
+
export function runStats(argv, cwd, envRepoPath) {
|
|
155
|
+
const { path, selection, json, error: argError } = parseStatsArgs(argv);
|
|
156
|
+
if (argError) {
|
|
157
|
+
console.error(`reposkein stats: ${argError}`);
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
const resolution = resolveRepoPath({ cwd, envRepoPath, explicit: path });
|
|
161
|
+
if (!resolution.repoPath) {
|
|
162
|
+
console.error(resolution.candidates && resolution.candidates.length > 0
|
|
163
|
+
? `reposkein stats: multiple repos found under ${cwd}: ${resolution.candidates.join(", ")}. Pass one explicitly.`
|
|
164
|
+
: `reposkein stats: no RepoSkein repo found under ${cwd}. Run \`reposkein-mcp init\`, or pass a path / set REPOSKEIN_REPO_PATH.`);
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
167
|
+
const { summary, error } = resolveStats(resolution.repoPath, selection);
|
|
168
|
+
if (!summary) {
|
|
169
|
+
console.error(`reposkein stats: ${error}`);
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
172
|
+
if (json) {
|
|
173
|
+
console.log(renderStatsJson(summary));
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log(renderStatsReport(summary, colorEnabled()));
|
|
177
|
+
}
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/cli/stats.ts"],"names":[],"mappings":"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"}
|