@chamba/mcp 0.3.1 → 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 (2) hide show
  1. package/dist/main.js +81 -22
  2. package/package.json +3 -3
package/dist/main.js CHANGED
@@ -401,10 +401,11 @@ function registerLoadContext(server, logger, services) {
401
401
  description: DESCRIPTION8,
402
402
  inputSchema: {
403
403
  task: z7.string().describe("The task you are about to work on."),
404
- includeObsidian: z7.boolean().optional().describe("Search the Obsidian vault for relevant notes (default true).")
404
+ includeObsidian: z7.boolean().optional().describe("Search the Obsidian vault for relevant notes (default true)."),
405
+ includeRules: z7.boolean().optional().describe("Include each repo's coding rules across editors (default true).")
405
406
  }
406
407
  },
407
- async ({ task, includeObsidian }) => {
408
+ async ({ task, includeObsidian, includeRules }) => {
408
409
  const workspace = await new WorkspaceScanner2(services.fs).scan(services.cwd);
409
410
  let vaultPath;
410
411
  if (includeObsidian !== false) {
@@ -414,7 +415,12 @@ function registerLoadContext(server, logger, services) {
414
415
  });
415
416
  if (detection.found) vaultPath = detection.path;
416
417
  }
417
- const built = await new ContextBuilder(services.fs).build({ workspace, task, vaultPath });
418
+ const built = await new ContextBuilder(services.fs).build({
419
+ workspace,
420
+ task,
421
+ vaultPath,
422
+ includeRules
423
+ });
418
424
  logger.info(
419
425
  { tool: TOOL_NAME8, vault: vaultPath ?? null, notes: built.relevantNotes.length },
420
426
  "context built"
@@ -585,6 +591,58 @@ function registerSummarizeToVault(server, logger, services) {
585
591
  );
586
592
  }
587
593
 
594
+ // src/tools/vault-status.ts
595
+ import { listVaultNotes, ObsidianDetector as ObsidianDetector3 } from "@chamba/core";
596
+ var TOOL_NAME13 = "chamba_vault_status";
597
+ var DESCRIPTION13 = "Diagnose the Obsidian vault connection: the resolved vault path, whether it was found, and the markdown notes chamba can actually see (the same set `chamba_load_context` searches). Use this to confirm the vault points at the vault root (the folder containing `.obsidian`), not at `.obsidian` itself.";
598
+ var MAX_LISTED = 50;
599
+ function registerVaultStatus(server, logger, services) {
600
+ server.registerTool(
601
+ TOOL_NAME13,
602
+ {
603
+ title: "Vault status",
604
+ description: DESCRIPTION13,
605
+ inputSchema: {}
606
+ },
607
+ async () => {
608
+ const detection = await new ObsidianDetector3(services.fs).detect({
609
+ explicitPath: services.obsidianVaultPath,
610
+ searchRoots: obsidianSearchRoots(services)
611
+ });
612
+ if (!detection.found || !detection.path) {
613
+ const text2 = `No Obsidian vault found.
614
+ Set CHAMBA_OBSIDIAN_VAULT_PATH to your vault root (the folder containing .obsidian), or place the vault under a common location. Searched: ${obsidianSearchRoots(services).join(", ")}.`;
615
+ logger.info({ tool: TOOL_NAME13, found: false }, "vault-status");
616
+ return {
617
+ content: [{ type: "text", text: text2 }],
618
+ structuredContent: { found: false }
619
+ };
620
+ }
621
+ const paths = await listVaultNotes(services.fs, detection.path);
622
+ const names = paths.map((p) => p.slice(detection.path?.length ?? 0).replace(/^\/+/, ""));
623
+ const source = services.obsidianVaultPath ? "CHAMBA_OBSIDIAN_VAULT_PATH" : "autodetected";
624
+ logger.info({ tool: TOOL_NAME13, vault: detection.path, notes: names.length }, "vault-status");
625
+ const shown = names.slice(0, MAX_LISTED);
626
+ const more = names.length > MAX_LISTED ? `
627
+ \u2026and ${names.length - MAX_LISTED} more` : "";
628
+ const text = `Vault: ${detection.path} (${source})
629
+ Notes chamba can see: ${names.length}
630
+
631
+ ${shown.map((n) => `- ${n}`).join("\n")}${more}` + (names.length === 0 ? "\n\n\u26A0\uFE0F No notes found. If your path ends in `.obsidian`, point it at the parent folder instead." : "");
632
+ return {
633
+ content: [{ type: "text", text }],
634
+ structuredContent: {
635
+ found: true,
636
+ vaultPath: detection.path,
637
+ source,
638
+ noteCount: names.length,
639
+ notes: shown
640
+ }
641
+ };
642
+ }
643
+ );
644
+ }
645
+
588
646
  // src/tools/workspace-init.ts
589
647
  import {
590
648
  joinPath as joinPath4,
@@ -594,14 +652,14 @@ import {
594
652
  WorkspaceScanner as WorkspaceScanner4
595
653
  } from "@chamba/core";
596
654
  import { z as z12 } from "zod";
597
- var TOOL_NAME13 = "chamba_workspace_init";
598
- var DESCRIPTION13 = "Scan the workspace and generate `.chamba/workspace.md` (description, languages, framework, conventions, active projects, folder map). Respects .gitignore/.dockerignore and never reads node_modules or binaries. If the file already exists it is NOT overwritten \u2014 its current contents are returned so the model/user decides what to do.";
655
+ var TOOL_NAME14 = "chamba_workspace_init";
656
+ var DESCRIPTION14 = "Scan the workspace and generate `.chamba/workspace.md` (description, languages, framework, conventions, active projects, folder map). Respects .gitignore/.dockerignore and never reads node_modules or binaries. If the file already exists it is NOT overwritten \u2014 its current contents are returned so the model/user decides what to do.";
599
657
  function registerWorkspaceInit(server, logger, services) {
600
658
  server.registerTool(
601
- TOOL_NAME13,
659
+ TOOL_NAME14,
602
660
  {
603
661
  title: "Init workspace",
604
- description: DESCRIPTION13,
662
+ description: DESCRIPTION14,
605
663
  inputSchema: {
606
664
  root: z12.string().optional().describe("Workspace root to scan. Defaults to the directory chamba runs in.")
607
665
  }
@@ -611,7 +669,7 @@ function registerWorkspaceInit(server, logger, services) {
611
669
  const wsPath = joinPath4(workspaceRoot, WORKSPACE_RELATIVE_PATH);
612
670
  if (await services.fs.exists(wsPath)) {
613
671
  const currentContents = await services.fs.readFile(wsPath);
614
- logger.info({ tool: TOOL_NAME13, wsPath }, "workspace.md already exists, not overwriting");
672
+ logger.info({ tool: TOOL_NAME14, wsPath }, "workspace.md already exists, not overwriting");
615
673
  return {
616
674
  content: [
617
675
  {
@@ -631,7 +689,7 @@ ${currentContents}`
631
689
  await services.fs.mkdir(joinPath4(workspaceRoot, WORKSPACE_DIR4));
632
690
  await services.fs.writeFile(wsPath, markdown);
633
691
  logger.info(
634
- { tool: TOOL_NAME13, wsPath, projects: workspace.projects.length },
692
+ { tool: TOOL_NAME14, wsPath, projects: workspace.projects.length },
635
693
  "workspace.md created"
636
694
  );
637
695
  return {
@@ -657,20 +715,20 @@ import {
657
715
  WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH2,
658
716
  WorkspaceScanner as WorkspaceScanner5
659
717
  } from "@chamba/core";
660
- var TOOL_NAME14 = "chamba_workspace_reload";
661
- var DESCRIPTION14 = "Re-scan the workspace and return a diff against the current `.chamba/workspace.md`. NEVER overwrites the file \u2014 the user may have hand-edited it. The model decides whether to apply changes.";
718
+ var TOOL_NAME15 = "chamba_workspace_reload";
719
+ var DESCRIPTION15 = "Re-scan the workspace and return a diff against the current `.chamba/workspace.md`. NEVER overwrites the file \u2014 the user may have hand-edited it. The model decides whether to apply changes.";
662
720
  function registerWorkspaceReload(server, logger, services) {
663
721
  server.registerTool(
664
- TOOL_NAME14,
722
+ TOOL_NAME15,
665
723
  {
666
724
  title: "Reload workspace",
667
- description: DESCRIPTION14,
725
+ description: DESCRIPTION15,
668
726
  inputSchema: {}
669
727
  },
670
728
  async () => {
671
729
  const wsPath = joinPath5(services.cwd, WORKSPACE_RELATIVE_PATH2);
672
730
  if (!await services.fs.exists(wsPath)) {
673
- logger.info({ tool: TOOL_NAME14, wsPath }, "no workspace.md to reload");
731
+ logger.info({ tool: TOOL_NAME15, wsPath }, "no workspace.md to reload");
674
732
  return {
675
733
  content: [
676
734
  {
@@ -684,7 +742,7 @@ function registerWorkspaceReload(server, logger, services) {
684
742
  const scanner = new WorkspaceScanner5(services.fs);
685
743
  const rescanned = renderWorkspaceMarkdown2(await scanner.scan(services.cwd));
686
744
  if (textsEqual(current, rescanned)) {
687
- logger.info({ tool: TOOL_NAME14, wsPath }, "workspace.md up to date");
745
+ logger.info({ tool: TOOL_NAME15, wsPath }, "workspace.md up to date");
688
746
  return {
689
747
  content: [
690
748
  {
@@ -694,7 +752,7 @@ function registerWorkspaceReload(server, logger, services) {
694
752
  ]
695
753
  };
696
754
  }
697
- logger.info({ tool: TOOL_NAME14, wsPath }, "workspace.md differs from re-scan");
755
+ logger.info({ tool: TOOL_NAME15, wsPath }, "workspace.md differs from re-scan");
698
756
  return {
699
757
  content: [
700
758
  {
@@ -713,24 +771,24 @@ ${diffLines(current, rescanned)}
713
771
 
714
772
  // src/tools/workspace-show.ts
715
773
  import { joinPath as joinPath6, WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH3 } from "@chamba/core";
716
- var TOOL_NAME15 = "chamba_workspace_show";
717
- var DESCRIPTION15 = "Show the current workspace map. Reads `.chamba/workspace.md` from the workspace root and returns its contents. If no workspace file exists yet, says so \u2014 the model can then run chamba_workspace_init to create one.";
774
+ var TOOL_NAME16 = "chamba_workspace_show";
775
+ var DESCRIPTION16 = "Show the current workspace map. Reads `.chamba/workspace.md` from the workspace root and returns its contents. If no workspace file exists yet, says so \u2014 the model can then run chamba_workspace_init to create one.";
718
776
  function registerWorkspaceShow(server, logger, services) {
719
777
  server.registerTool(
720
- TOOL_NAME15,
778
+ TOOL_NAME16,
721
779
  {
722
780
  title: "Show workspace",
723
- description: DESCRIPTION15,
781
+ description: DESCRIPTION16,
724
782
  inputSchema: {}
725
783
  },
726
784
  async () => {
727
785
  const path = joinPath6(services.cwd, WORKSPACE_RELATIVE_PATH3);
728
786
  try {
729
787
  const contents = await services.fs.readFile(path);
730
- logger.info({ tool: TOOL_NAME15, path }, "workspace.md read");
788
+ logger.info({ tool: TOOL_NAME16, path }, "workspace.md read");
731
789
  return { content: [{ type: "text", text: contents }] };
732
790
  } catch {
733
- logger.info({ tool: TOOL_NAME15, path }, "no workspace.md found");
791
+ logger.info({ tool: TOOL_NAME16, path }, "no workspace.md found");
734
792
  return {
735
793
  content: [
736
794
  {
@@ -754,6 +812,7 @@ function createServer(logger, services = createNodeServices()) {
754
812
  registerWorkspaceReload(server, logger, services);
755
813
  registerLoadContext(server, logger, services);
756
814
  registerSummarizeToVault(server, logger, services);
815
+ registerVaultStatus(server, logger, services);
757
816
  registerGeneratePlan(server, logger, services);
758
817
  registerReviewPlan(server, logger, services);
759
818
  registerCreateWorktree(server, logger, services);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chamba/mcp",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "chamba MCP server — orchestration, workspace, worktree and Obsidian tools for any MCP-capable editor",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,8 +36,8 @@
36
36
  "@modelcontextprotocol/sdk": "^1.12.0",
37
37
  "pino": "^9.0.0",
38
38
  "zod": "^3.23.0",
39
- "@chamba/adapters": "0.3.1",
40
- "@chamba/core": "0.3.1"
39
+ "@chamba/adapters": "0.4.0",
40
+ "@chamba/core": "0.4.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^22.0.0",