@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.
Files changed (140) hide show
  1. package/README.md +73 -1
  2. package/binary-digests.json +4 -4
  3. package/dist/SKILL.md +63 -1
  4. package/dist/cli/adr.d.ts +37 -0
  5. package/dist/cli/adr.js +231 -0
  6. package/dist/cli/adr.js.map +1 -0
  7. package/dist/cli/agentAdapters.d.ts +68 -0
  8. package/dist/cli/agentAdapters.js +223 -0
  9. package/dist/cli/agentAdapters.js.map +1 -0
  10. package/dist/cli/ansi.d.ts +24 -0
  11. package/dist/cli/ansi.js +40 -0
  12. package/dist/cli/ansi.js.map +1 -0
  13. package/dist/cli/doctor.d.ts +34 -2
  14. package/dist/cli/doctor.js +53 -5
  15. package/dist/cli/doctor.js.map +1 -1
  16. package/dist/cli/doctorDecisions.d.ts +5 -0
  17. package/dist/cli/doctorDecisions.js +83 -0
  18. package/dist/cli/doctorDecisions.js.map +1 -0
  19. package/dist/cli/doctorFreshness.d.ts +43 -0
  20. package/dist/cli/doctorFreshness.js +111 -0
  21. package/dist/cli/doctorFreshness.js.map +1 -0
  22. package/dist/cli/doctorSummaries.d.ts +2 -0
  23. package/dist/cli/doctorSummaries.js +95 -0
  24. package/dist/cli/doctorSummaries.js.map +1 -0
  25. package/dist/cli/federatedDiscovery.d.ts +16 -0
  26. package/dist/cli/federatedDiscovery.js +75 -0
  27. package/dist/cli/federatedDiscovery.js.map +1 -0
  28. package/dist/cli/init.d.ts +69 -6
  29. package/dist/cli/init.js +194 -28
  30. package/dist/cli/init.js.map +1 -1
  31. package/dist/cli/sourceSlices.d.ts +17 -0
  32. package/dist/cli/sourceSlices.js +59 -0
  33. package/dist/cli/sourceSlices.js.map +1 -0
  34. package/dist/cli/stats.d.ts +29 -0
  35. package/dist/cli/stats.js +180 -0
  36. package/dist/cli/stats.js.map +1 -0
  37. package/dist/cli/view.d.ts +71 -3
  38. package/dist/cli/view.js +147 -12
  39. package/dist/cli/view.js.map +1 -1
  40. package/dist/guard/decisionValidation.d.ts +29 -0
  41. package/dist/guard/decisionValidation.js +51 -0
  42. package/dist/guard/decisionValidation.js.map +1 -0
  43. package/dist/guard/summaryValidation.d.ts +3 -0
  44. package/dist/guard/summaryValidation.js +5 -3
  45. package/dist/guard/summaryValidation.js.map +1 -1
  46. package/dist/index.d.ts +48 -0
  47. package/dist/index.js +355 -78
  48. package/dist/index.js.map +1 -1
  49. package/dist/indexer/decisionsAffected.d.ts +42 -0
  50. package/dist/indexer/decisionsAffected.js +149 -0
  51. package/dist/indexer/decisionsAffected.js.map +1 -0
  52. package/dist/indexer/fetchBinary.d.ts +14 -0
  53. package/dist/indexer/fetchBinary.js +81 -40
  54. package/dist/indexer/fetchBinary.js.map +1 -1
  55. package/dist/indexer/runIndexer.d.ts +3 -2
  56. package/dist/indexer/runIndexer.js +8 -4
  57. package/dist/indexer/runIndexer.js.map +1 -1
  58. package/dist/profile/decisions.d.ts +37 -0
  59. package/dist/profile/decisions.js +112 -0
  60. package/dist/profile/decisions.js.map +1 -0
  61. package/dist/profile/types.d.ts +8 -0
  62. package/dist/store/GraphStore.d.ts +5 -0
  63. package/dist/store/JsonlGraphStore.d.ts +14 -3
  64. package/dist/store/JsonlGraphStore.js +66 -19
  65. package/dist/store/JsonlGraphStore.js.map +1 -1
  66. package/dist/store/decisions.d.ts +131 -0
  67. package/dist/store/decisions.js +321 -0
  68. package/dist/store/decisions.js.map +1 -0
  69. package/dist/store/indexedAt.d.ts +18 -0
  70. package/dist/store/indexedAt.js +56 -0
  71. package/dist/store/indexedAt.js.map +1 -0
  72. package/dist/store/instrumentTool.d.ts +40 -0
  73. package/dist/store/instrumentTool.js +82 -0
  74. package/dist/store/instrumentTool.js.map +1 -0
  75. package/dist/store/repoContextCache.d.ts +15 -0
  76. package/dist/store/repoContextCache.js +26 -0
  77. package/dist/store/repoContextCache.js.map +1 -0
  78. package/dist/store/repoSession.d.ts +63 -0
  79. package/dist/store/repoSession.js +123 -0
  80. package/dist/store/repoSession.js.map +1 -0
  81. package/dist/store/resolveRepoPath.d.ts +31 -0
  82. package/dist/store/resolveRepoPath.js +85 -0
  83. package/dist/store/resolveRepoPath.js.map +1 -0
  84. package/dist/store/sessionLog.d.ts +98 -0
  85. package/dist/store/sessionLog.js +216 -0
  86. package/dist/store/sessionLog.js.map +1 -0
  87. package/dist/store/sessionStats.d.ts +55 -0
  88. package/dist/store/sessionStats.js +140 -0
  89. package/dist/store/sessionStats.js.map +1 -0
  90. package/dist/store/sidecar.d.ts +39 -3
  91. package/dist/store/sidecar.js +89 -5
  92. package/dist/store/sidecar.js.map +1 -1
  93. package/dist/store/summaryShards.d.ts +117 -0
  94. package/dist/store/summaryShards.js +291 -0
  95. package/dist/store/summaryShards.js.map +1 -0
  96. package/dist/store/teamConfig.d.ts +13 -0
  97. package/dist/store/teamConfig.js +49 -0
  98. package/dist/store/teamConfig.js.map +1 -0
  99. package/dist/tools/getContextProfile.d.ts +1 -1
  100. package/dist/tools/getContextProfile.js +9 -1
  101. package/dist/tools/getContextProfile.js.map +1 -1
  102. package/dist/tools/getDecision.d.ts +6 -0
  103. package/dist/tools/getDecision.js +59 -0
  104. package/dist/tools/getDecision.js.map +1 -0
  105. package/dist/tools/impact.d.ts +1 -1
  106. package/dist/tools/impact.js +13 -1
  107. package/dist/tools/impact.js.map +1 -1
  108. package/dist/tools/indexerTools.d.ts +16 -2
  109. package/dist/tools/indexerTools.js +44 -5
  110. package/dist/tools/indexerTools.js.map +1 -1
  111. package/dist/tools/listDecisions.d.ts +19 -0
  112. package/dist/tools/listDecisions.js +93 -0
  113. package/dist/tools/listDecisions.js.map +1 -0
  114. package/dist/tools/reaffirmDecision.d.ts +11 -0
  115. package/dist/tools/reaffirmDecision.js +55 -0
  116. package/dist/tools/reaffirmDecision.js.map +1 -0
  117. package/dist/tools/recordDecision.d.ts +24 -0
  118. package/dist/tools/recordDecision.js +135 -0
  119. package/dist/tools/recordDecision.js.map +1 -0
  120. package/dist/tools/semanticFind.d.ts +9 -2
  121. package/dist/tools/semanticFind.js +44 -2
  122. package/dist/tools/semanticFind.js.map +1 -1
  123. package/dist/tools/setDecisionStatus.d.ts +8 -0
  124. package/dist/tools/setDecisionStatus.js +34 -0
  125. package/dist/tools/setDecisionStatus.js.map +1 -0
  126. package/dist/viz/assets/{graph.worker-CC7BeE-8.js → graph.worker-DkH6-lMU.js} +1 -1
  127. package/dist/viz/assets/index-CxqeGuRS.css +1 -0
  128. package/dist/viz/assets/index-DiNZyrXx.js +9 -0
  129. package/dist/viz/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  130. package/dist/viz/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  131. package/dist/viz/assets/jetbrains-mono-latin-700-normal-BYuf6tUa.woff2 +0 -0
  132. package/dist/viz/assets/r3f-BZY3QR6_.js +336 -0
  133. package/dist/viz/assets/tanstack-CjXr-L-s.js +62 -0
  134. package/dist/viz/assets/three-Cpu5RUEM.js +4116 -0
  135. package/dist/viz/index.html +5 -4
  136. package/package.json +5 -4
  137. package/dist/viz/assets/index-C_8UkiJ8.js +0 -9
  138. package/dist/viz/assets/r3f-Cku1OhB-.js +0 -277
  139. package/dist/viz/assets/tanstack-DyXcNRWk.js +0 -77
  140. package/dist/viz/assets/three-Z8XaLGmf.js +0 -3839
@@ -0,0 +1,111 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { readIndexedAtSha } from "../store/indexedAt.js";
5
+ /** Marker `init --hooks` (the Rust indexer) writes into every hook it
6
+ * installs — see indexer/crates/cli/src/main.rs `write_hook`. Doctor uses
7
+ * the same marker to tell "RepoSkein installed this hook" from "the user
8
+ * has their own pre-commit hook and never ran `reposkein-mcp init`". */
9
+ const HOOK_MARKER = "# reposkein-managed";
10
+ const warn = (id, label, ok, detail, fix) => ({
11
+ id,
12
+ label,
13
+ ok,
14
+ critical: false, // these checks degrade the workflow; they never block startup
15
+ detail,
16
+ fix: ok ? undefined : fix,
17
+ });
18
+ /** Non-critical by default: a repo can be perfectly usable without hooks
19
+ * (an agent can always run `reposkein-mcp index` by hand). `doctor --ci`
20
+ * promotes this id to a failing exit code — see CI_FAIL_IDS in doctor.ts. */
21
+ export function hooksCheck(repoPath) {
22
+ const hookPath = join(repoPath, ".git", "hooks", "pre-commit");
23
+ if (!existsSync(hookPath)) {
24
+ return warn("hooks_installed", "git hooks installed", false, "no .git/hooks/pre-commit", "run `reposkein-mcp init` to install the pre-commit/post-merge hooks");
25
+ }
26
+ let content = "";
27
+ try {
28
+ content = readFileSync(hookPath, "utf8");
29
+ }
30
+ catch {
31
+ /* unreadable — treat like missing below */
32
+ }
33
+ const managed = content.includes(HOOK_MARKER);
34
+ return warn("hooks_installed", "git hooks installed", managed, managed
35
+ ? "pre-commit hook installed"
36
+ : ".git/hooks/pre-commit exists but was not installed by RepoSkein", managed ? undefined : "run `reposkein-mcp init` to install the pre-commit/post-merge hooks");
37
+ }
38
+ /** `git -C repoPath rev-parse HEAD`, or null on any failure (no git, not a
39
+ * repo, no commits yet). */
40
+ function currentHeadSha(repoPath) {
41
+ try {
42
+ const out = execFileSync("git", ["-C", repoPath, "rev-parse", "HEAD"], {
43
+ encoding: "utf8",
44
+ stdio: ["ignore", "pipe", "ignore"],
45
+ }).trim();
46
+ return out || null;
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ /** Content-based staleness: the committed graph is fresh iff the commit SHA
53
+ * recorded the last time it was (re)built (`.reposkein/local/indexed-at` —
54
+ * see mcp/src/store/indexedAt.ts) equals the current git HEAD. The marker
55
+ * is kept current two ways: the installed git hooks maintain it on their
56
+ * own (`post-commit` after every commit, `post-merge`/`post-checkout` —
57
+ * which also re-index — after a merge/pull/branch switch), and
58
+ * `reposkein-mcp index`/`init` write it directly. A mismatch therefore
59
+ * means one of: the hooks were never installed (or were removed), or
60
+ * nobody's indexed this repo at all yet.
61
+ *
62
+ * Replaces an earlier mtime-based heuristic (mtime(nodes.jsonl) vs. the last
63
+ * commit's timestamp) that turned out to be structurally blind after any
64
+ * fresh checkout: `git clone`/`checkout` — or a CI cache restoring
65
+ * `.reposkein/` from a prior run — stamps every file it writes with
66
+ * "now", which is always ≥ any past commit's timestamp, so
67
+ * `mtime < lastCommitMs` could never be true right when it mattered most.
68
+ * A recorded SHA has no such blind spot: it's compared by value, not by
69
+ * filesystem timestamp.
70
+ *
71
+ * Deliberately a **plain SHA mismatch**, not a diff filtered to
72
+ * indexed-language extensions: filtering would need to stay in sync with
73
+ * `config.toml`'s `[languages] enabled` list and the indexer's own
74
+ * extension→language table, which is one more thing to drift. The cost of
75
+ * getting it wrong is asymmetric — a false "stale" just costs a redundant
76
+ * `reposkein-mcp index` (cheap), while a false "fresh" is exactly the bug
77
+ * being fixed — so the simpler, conservative rule wins here.
78
+ *
79
+ * Two distinct failure shapes, both reported under the same check id:
80
+ * - no recorded SHA at all → never indexed via a hook or the mcp-side path
81
+ * (a fresh clone's local/ never carries over, since it's gitignored) —
82
+ * FAIL.
83
+ * - a recorded SHA that doesn't match HEAD → the hooks are missing (or
84
+ * were bypassed, e.g. `git commit --no-verify`) and nobody's re-indexed
85
+ * by hand either — FAIL.
86
+ *
87
+ * Non-critical by default; `doctor --ci` promotes it (CI_FAIL_IDS in
88
+ * doctor.ts). */
89
+ export function graphStaleCheck(repoPath) {
90
+ const nodesFile = join(repoPath, ".reposkein", "nodes.jsonl");
91
+ if (!existsSync(nodesFile)) {
92
+ return warn("graph_stale", "graph freshness", false, "no .reposkein/nodes.jsonl (never indexed)", "run `reposkein-mcp index`");
93
+ }
94
+ const recordedSha = readIndexedAtSha(repoPath);
95
+ if (!recordedSha) {
96
+ return warn("graph_stale", "graph freshness", false, "nodes.jsonl exists but no recorded indexed-at commit (.reposkein/local/indexed-at) — " +
97
+ "the post-commit/post-merge/post-checkout hooks maintain this automatically, so its " +
98
+ "absence means the hooks aren't installed (or local/ never carried over a clone) and " +
99
+ "nobody's run `reposkein-mcp index`/`init` by hand either", "run `reposkein-mcp index`");
100
+ }
101
+ const headSha = currentHeadSha(repoPath);
102
+ if (headSha === null) {
103
+ return warn("graph_stale", "graph freshness", true, "no git HEAD to compare against (skipped)");
104
+ }
105
+ if (recordedSha === headSha) {
106
+ return warn("graph_stale", "graph freshness", true, `graph matches HEAD (${headSha.slice(0, 7)})`);
107
+ }
108
+ return warn("graph_stale", "graph freshness", false, `graph was indexed at ${recordedSha.slice(0, 7)}, but HEAD is now ${headSha.slice(0, 7)} — commits landed since ` +
109
+ "the last index without the marker advancing (hooks missing/bypassed, or the graph was never re-indexed)", "run `reposkein-mcp index`");
110
+ }
111
+ //# sourceMappingURL=doctorFreshness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctorFreshness.js","sourceRoot":"","sources":["../../src/cli/doctorFreshness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Check } from "./doctor.js";
2
+ export declare function summaryChecks(repoPath: string): Check[];
@@ -0,0 +1,95 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, readdirSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { countRecordedConflicts, isShardFileName, loadSummaryShards, summariesDir, } from "../store/summaryShards.js";
5
+ /** Health of the committed authored summaries, `.reposkein/summaries/<xx>.jsonl`.
6
+ *
7
+ * Every check is non-critical. Summaries are the one part of `.reposkein/`
8
+ * nothing can regenerate, so the failure mode that matters is *silent* loss:
9
+ * prose that exists on disk but will never be committed, or a merge that
10
+ * dropped a record. Each check below names one way that happens.
11
+ *
12
+ * Returns [] when the repo has no committed summaries and no legacy file —
13
+ * a repo that has never had an agent write one has nothing to report. */
14
+ const warn = (id, label, ok, detail, fix) => ({
15
+ id,
16
+ label,
17
+ ok,
18
+ critical: false,
19
+ detail,
20
+ fix: ok ? undefined : fix,
21
+ });
22
+ /** `git check-ignore -v <path>`, or null when the path is not ignored (or git
23
+ * is unavailable / this is not a repo). The verbose form names the source:
24
+ * `<file>:<line>:<pattern>\t<path>`. */
25
+ function checkIgnoreSource(repoPath, relPath) {
26
+ try {
27
+ const out = execFileSync("git", ["-C", repoPath, "check-ignore", "-v", "--no-index", relPath], {
28
+ encoding: "utf8",
29
+ stdio: ["ignore", "pipe", "ignore"],
30
+ });
31
+ const first = out.split("\n")[0]?.trim();
32
+ return first ? first.split("\t")[0] : null;
33
+ }
34
+ catch {
35
+ // exit 1 = not ignored; anything else = no git. Both mean "no finding".
36
+ return null;
37
+ }
38
+ }
39
+ export function summaryChecks(repoPath) {
40
+ const dir = summariesDir(repoPath);
41
+ let shardCount = 0;
42
+ try {
43
+ shardCount = readdirSync(dir).filter(isShardFileName).length;
44
+ }
45
+ catch {
46
+ shardCount = 0;
47
+ }
48
+ const legacyPresent = existsSync(join(repoPath, ".reposkein", "summaries.jsonl"));
49
+ if (shardCount === 0 && !legacyPresent)
50
+ return [];
51
+ const checks = [];
52
+ const loaded = loadSummaryShards(repoPath);
53
+ // 1) The pre-sharding single file is still there.
54
+ //
55
+ // One committed summaries.jsonl is exactly the artifact that made every
56
+ // branch conflict — the #35 lesson. It is read for one release so nothing
57
+ // is stranded, but leaving it is a conflict waiting to happen.
58
+ checks.push(warn("summaries_unsplit", "summaries sharded", !legacyPresent, legacyPresent
59
+ ? `.reposkein/summaries.jsonl is still present (${loaded.summaries.size} record(s) readable); every branch that writes a summary will conflict on it`
60
+ : `${shardCount} shard(s), ${loaded.summaries.size} summar${loaded.summaries.size === 1 ? "y" : "ies"}`, "run `reposkein-indexer index .` — it folds the file into .reposkein/summaries/<xx>.jsonl and retires it; commit the result"));
61
+ // 2) A .gitignore pattern is masking the shards.
62
+ //
63
+ // A repo-root rule like `.reposkein/*` (or a blanket `*.jsonl`) silently
64
+ // keeps the shards out of every commit. Nothing errors — the summaries
65
+ // simply never reach a teammate, and are lost with the machine.
66
+ const probe = shardCount > 0 ? firstShardRelPath(repoPath) : ".reposkein/summaries/00.jsonl";
67
+ const ignoredBy = checkIgnoreSource(repoPath, probe);
68
+ checks.push(warn("summaries_committable", "summary shards committable", ignoredBy === null, ignoredBy === null
69
+ ? "not git-ignored"
70
+ : `${probe} is ignored by ${ignoredBy} — authored summaries would never be committed`, "add a negation after that rule, e.g. `!**/.reposkein/summaries/`, then `git add .reposkein/summaries`"));
71
+ // 3) Damaged shard content: conflict markers or unparseable lines.
72
+ checks.push(warn("summaries_readable", "summary shards parse", loaded.warnings.length === 0, loaded.warnings.length === 0
73
+ ? `${loaded.summaries.size} record(s) read cleanly`
74
+ : loaded.warnings.join("; "), "run `reposkein-indexer index .` to rewrite the shards canonically, then commit them"));
75
+ // 4) Divergent records preserved from a merge. Not an error — the resolution
76
+ // is deterministic — but a human should read the loser before it is
77
+ // forgotten, because nothing can regenerate it.
78
+ const conflicts = countRecordedConflicts(repoPath);
79
+ checks.push(warn("summaries_conflicts", "summary merge conflicts", conflicts === 0, conflicts === 0
80
+ ? "none recorded"
81
+ : `${conflicts} record(s) lost a merge tiebreak and were preserved in .reposkein/local/conflicts.jsonl`, "read .reposkein/local/conflicts.jsonl; re-write any summary worth keeping, then delete the file"));
82
+ return checks;
83
+ }
84
+ function firstShardRelPath(repoPath) {
85
+ try {
86
+ const names = readdirSync(summariesDir(repoPath)).filter(isShardFileName).sort();
87
+ if (names[0])
88
+ return `.reposkein/summaries/${names[0]}`;
89
+ }
90
+ catch {
91
+ // fall through
92
+ }
93
+ return ".reposkein/summaries/00.jsonl";
94
+ }
95
+ //# sourceMappingURL=doctorSummaries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctorSummaries.js","sourceRoot":"","sources":["../../src/cli/doctorSummaries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface FederatedRepo {
2
+ /** repo_id from the nested repo's meta.json (or its directory name if the
3
+ * meta.json is missing/unreadable). */
4
+ repoId: string;
5
+ /** Path of the nested repo root, relative to the scanned root (posix-style). */
6
+ rootPath: string;
7
+ /** Absolute path of the nested repo root. */
8
+ absPath: string;
9
+ }
10
+ /** Scans descendants of `repoPath` for nested repos (directories containing a
11
+ * `.reposkein/` marker), excluding `repoPath` itself. Does not recurse past a
12
+ * hit — a repo nested inside another nested repo is out of scope for a single
13
+ * export pass. Bounded to `maxDepth` levels (default 6) so a pathological
14
+ * tree can't cause an unbounded scan. Deterministic (sorted by rootPath).
15
+ * Best-effort: unreadable directories are skipped, never thrown. */
16
+ export declare function discoverFederatedRepos(repoPath: string, maxDepth?: number): FederatedRepo[];
@@ -0,0 +1,75 @@
1
+ import { readdirSync, existsSync, readFileSync, statSync } from "node:fs";
2
+ import { join, relative, resolve } from "node:path";
3
+ /** Directories never descended into while scanning for nested repos: build
4
+ * output, VCS internals, other worktrees/tool state — mirrors the skip set
5
+ * used by store/resolveRepoPath.ts's walk-down discovery. */
6
+ const SKIP_DIR_NAMES = new Set([
7
+ "node_modules",
8
+ ".git",
9
+ "target",
10
+ "dist",
11
+ ".worktrees",
12
+ ".claude",
13
+ ]);
14
+ /** Scans descendants of `repoPath` for nested repos (directories containing a
15
+ * `.reposkein/` marker), excluding `repoPath` itself. Does not recurse past a
16
+ * hit — a repo nested inside another nested repo is out of scope for a single
17
+ * export pass. Bounded to `maxDepth` levels (default 6) so a pathological
18
+ * tree can't cause an unbounded scan. Deterministic (sorted by rootPath).
19
+ * Best-effort: unreadable directories are skipped, never thrown. */
20
+ export function discoverFederatedRepos(repoPath, maxDepth = 6) {
21
+ const root = resolve(repoPath);
22
+ const hits = [];
23
+ function isReposkeinDir(dir) {
24
+ try {
25
+ return statSync(join(dir, ".reposkein")).isDirectory();
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ function recurse(dir, depth) {
32
+ if (depth > maxDepth)
33
+ return;
34
+ let entries;
35
+ try {
36
+ entries = readdirSync(dir, { withFileTypes: true });
37
+ }
38
+ catch {
39
+ return; // unreadable dir — skip, don't fail the export
40
+ }
41
+ for (const entry of entries) {
42
+ if (!entry.isDirectory())
43
+ continue;
44
+ if (SKIP_DIR_NAMES.has(entry.name))
45
+ continue;
46
+ if (entry.name === ".reposkein")
47
+ continue;
48
+ const full = join(dir, entry.name);
49
+ if (isReposkeinDir(full)) {
50
+ let repoId = entry.name;
51
+ const metaPath = join(full, ".reposkein", "meta.json");
52
+ if (existsSync(metaPath)) {
53
+ try {
54
+ const meta = JSON.parse(readFileSync(metaPath, "utf8"));
55
+ if (typeof meta.repo_id === "string" && meta.repo_id)
56
+ repoId = meta.repo_id;
57
+ }
58
+ catch {
59
+ // fall back to the directory name
60
+ }
61
+ }
62
+ hits.push({
63
+ repoId,
64
+ rootPath: relative(root, full).split("\\").join("/") || ".",
65
+ absPath: full,
66
+ });
67
+ continue; // don't descend further into a hit
68
+ }
69
+ recurse(full, depth + 1);
70
+ }
71
+ }
72
+ recurse(root, 1);
73
+ return hits.sort((a, b) => (a.rootPath < b.rootPath ? -1 : a.rootPath > b.rootPath ? 1 : 0));
74
+ }
75
+ //# sourceMappingURL=federatedDiscovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federatedDiscovery.js","sourceRoot":"","sources":["../../src/cli/federatedDiscovery.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { type AgentId, type WriteAgentConfigsOptions } from "./agentAdapters.js";
1
2
  /** Where the navigation skill is installed for a repo (Claude project skills). */
2
3
  export declare function skillTargetPath(repoPath: string): string;
3
4
  /** The bundled SKILL.md inside the installed package (dist/SKILL.md). */
@@ -7,13 +8,75 @@ export declare function mcpConfigSnippet(repoPath: string): string;
7
8
  /** Idempotently add the per-machine MCP config files to the repo's .gitignore
8
9
  * (creating it if absent), so `reposkein-mcp init` never leaves them tracked. */
9
10
  export declare function ensureLocalConfigGitignored(repoPath: string): void;
11
+ /** True when `.reposkein/meta.json` is tracked by git — this clone joined a
12
+ * repo that already has RepoSkein set up (someone else ran `init` and
13
+ * committed it), rather than being the first machine to set it up (whose
14
+ * meta.json exists on disk but isn't committed yet). Join mode skips
15
+ * first-time scaffolding entirely and instead wires up the local agent(s)
16
+ * automatically (REP-16 T5) — see `runInit`.
17
+ *
18
+ * Falls back to plain existence when git itself is unavailable (no `git`
19
+ * binary, or `repoPath` isn't a git repo yet) so `init` still behaves
20
+ * sensibly outside a git repo rather than throwing. */
21
+ export declare function detectJoinMode(repoPath: string): boolean;
22
+ /** Where `init --ci` writes the Pages-publish workflow in the target repo. */
23
+ export declare function ciWorkflowTargetPath(repoPath: string): string;
24
+ /** Template written by `reposkein-mcp init --ci`: a thin caller of RepoSkein's
25
+ * reusable publish workflow (see docs/HOSTING.md). Consumers get released
26
+ * indexer binaries (no Rust toolchain) + a self-contained static export
27
+ * published to GitHub Pages. Repo owners must still flip Settings → Pages →
28
+ * "Build and deployment: GitHub Actions" once. */
29
+ export declare function ciWorkflowTemplate(): string;
30
+ /** `reposkein-mcp init --ci`: writes the Pages-publish workflow template into
31
+ * the target repo's `.github/workflows/`. Non-destructive: skips (with a
32
+ * message) if the file already exists, so a re-run never clobbers a repo
33
+ * owner's edits. Returns whether it wrote the file. */
34
+ export declare function writeCiWorkflow(repoPath: string): {
35
+ written: boolean;
36
+ path: string;
37
+ };
10
38
  /** `reposkein-mcp index [path]`: (re)build the code graph at `repoPath` using the
11
39
  * native indexer. The package-friendly way to index — the `reposkein-indexer`
12
- * binary is fetched into the package (not on PATH), so end users run this. */
40
+ * binary is fetched into the package (not on PATH), so end users run this.
41
+ * On success, also records the current git HEAD to `.reposkein/local/indexed-at`
42
+ * — `doctor --ci`'s `graph_stale` check reads it back (see doctorFreshness.ts).
43
+ * The installed git hooks maintain the same marker themselves (`post-commit`
44
+ * after every commit, `post-merge`/`post-checkout` — which also re-index —
45
+ * after a merge/pull/branch switch; see the hook templates in
46
+ * indexer/crates/cli/src/main.rs), so this mcp-side write is the "manual
47
+ * index" case, not the only path that keeps the marker current. */
13
48
  export declare function runIndex(repoPath?: string): Promise<number>;
14
- /** `reposkein-mcp init [path] [--no-index]`: ensure the indexer, install git hooks,
15
- * build the initial graph, install the navigation skill, and print the MCP config +
16
- * next steps. Pass `index: false` to skip the initial index. */
17
- export declare function runInit(repoPath?: string, opts?: {
49
+ export interface RunInitOptions {
18
50
  index?: boolean;
19
- }): Promise<number>;
51
+ ci?: boolean;
52
+ /** Explicit `--agents` override for join mode; detected when omitted. */
53
+ agents?: AgentId[];
54
+ /** `--dry-run`: plan agent config writes without touching disk. */
55
+ dryRun?: boolean;
56
+ /** Force join-mode on/off; auto-detected (committed .reposkein/meta.json)
57
+ * when omitted — see `detectJoinMode`. */
58
+ join?: boolean;
59
+ /** Test-only injection point for the agent-adapter step (fake `exec`/`now`). */
60
+ agentWriteOpts?: Pick<WriteAgentConfigsOptions, "exec" | "now">;
61
+ }
62
+ /** `reposkein-mcp init [path] [--no-index] [--ci] [--agents <list>] [--dry-run]`:
63
+ * ensure the indexer, install git hooks, build the initial graph, install
64
+ * the navigation skill, then either (join mode) auto-write the local
65
+ * agent(s) MCP config, or (first-time) print the config snippet to paste in
66
+ * by hand. Pass `index: false` to skip the initial index; `ci: true` to
67
+ * also write the GitHub Pages publish workflow (see docs/HOSTING.md).
68
+ *
69
+ * Join mode (REP-16 T5): auto-detected when `.reposkein/meta.json` is
70
+ * already committed (`detectJoinMode`) — i.e. someone cloned a repo that
71
+ * already has RepoSkein set up. Skips nothing structural (hooks/index/skill
72
+ * still run so a stale local checkout gets caught up) but additionally
73
+ * writes `.mcp.json` / `opencode.json` / `.cursor/mcp.json` for whichever
74
+ * agent(s) are detected present (or `opts.agents`), then prints a doctor
75
+ * summary instead of a config snippet to copy by hand.
76
+ *
77
+ * Unsupported platform (darwin-x64, win32-arm64, no REPOSKEIN_INDEXER_BIN):
78
+ * prints cargo-install fallback instructions and CONTINUES instead of
79
+ * crashing — hooks + the initial index are skipped (nothing to run them
80
+ * with), but the skill, CI workflow, and (in join mode) agent config are
81
+ * still written, and the function returns 0. */
82
+ export declare function runInit(repoPath?: string, opts?: RunInitOptions): Promise<number>;