@splicr/mcp-server 0.11.0 → 0.11.2

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/dist/cli.js CHANGED
@@ -404,30 +404,50 @@ async function runHook() {
404
404
  // Gather env signals + fuse with user's prompt
405
405
  const { gatherSignals } = await import('./lib/signal-gatherer.js');
406
406
  const { fuseSignals } = await import('./lib/signal-fusion.js');
407
- const { getRelevantContext } = await import('./lib/api-client.js');
407
+ const { getRelevantContext, getProjectContext } = await import('./lib/api-client.js');
408
+ const { detectProject } = await import('./lib/project-detector.js');
408
409
  const envSignals = gatherSignals(process.cwd());
409
410
  const fused = fuseSignals({ task: userPrompt }, envSignals);
410
411
  if (fused.queries.length === 0) {
411
412
  process.exit(0);
412
413
  return;
413
414
  }
414
- // Call Splicr API always global, relevance handles filtering
415
- const { results } = await getRelevantContext({
415
+ // Check if this is the first message of the session (patterns not yet injected)
416
+ const sessionState = loadSessionState(sessionId);
417
+ const isFirstMessage = !loadSessionMeta(sessionId).patterns_injected;
418
+ // Fetch relevant context + patterns in parallel (patterns only on first message)
419
+ const contextPromise = getRelevantContext({
416
420
  queries: fused.queries,
417
421
  tech_stack: fused.tech_stack,
418
- limit: 5, // fetch extra to allow for dedup filtering
422
+ limit: 5,
419
423
  });
420
- if (!results || results.length === 0) {
421
- process.exit(0);
422
- return;
424
+ let patternsPromise = Promise.resolve({});
425
+ if (isFirstMessage) {
426
+ const detected = await detectProject(process.cwd()).catch(() => null);
427
+ if (detected?.name) {
428
+ patternsPromise = getProjectContext({
429
+ project_name: detected.name,
430
+ project_id: detected.id,
431
+ limit: 1, // we only need patterns, not captures
432
+ }).catch(() => ({}));
433
+ }
423
434
  }
424
- // Session-aware dedup: don't inject same captures twice in one session
425
- const injectedIds = loadSessionState(sessionId);
426
- const freshResults = results.filter((r) => !injectedIds.has(r.id));
427
- if (freshResults.length === 0) {
435
+ const [{ results }, patternData] = await Promise.all([contextPromise, patternsPromise]);
436
+ // Build patterns section (first message only, deterministic enforcement)
437
+ let patternsSection = '';
438
+ if (isFirstMessage && patternData.patterns && patternData.patterns.length > 0) {
439
+ const patternLines = patternData.patterns.map((p, i) => `${i + 1}. **${p.name}** — ${p.description}`).join('\n');
440
+ patternsSection = `ACTIVE TEAM PATTERNS for ${patternData.project_name || 'this project'}:\n${patternLines}\n\nThese patterns are established by your team. Follow them unless explicitly asked to deviate.\n\n---\n\n`;
441
+ // Mark patterns as injected for this session
442
+ saveSessionMeta(sessionId, { patterns_injected: true });
443
+ }
444
+ if ((!results || results.length === 0) && !patternsSection) {
428
445
  process.exit(0);
429
446
  return;
430
447
  }
448
+ // Session-aware dedup: don't inject same captures twice in one session
449
+ const injectedIds = sessionState;
450
+ const freshResults = (results || []).filter((r) => !injectedIds.has(r.id));
431
451
  // Take top 3 fresh results
432
452
  const topResults = freshResults.slice(0, 3);
433
453
  // Track what we injected (IDs + titles for context-aware gate)
@@ -435,14 +455,22 @@ async function runHook() {
435
455
  for (const r of topResults)
436
456
  injectedIds.add(r.id);
437
457
  saveSessionState(sessionId, injectedIds, titles);
438
- // Format as actionable decision-support context (12-factor style: own your context window)
439
- const contextLines = topResults.map((r, i) => {
440
- const why = r.why_relevant || 'Semantically similar to your work context';
441
- const tags = r.tags?.length ? r.tags.slice(0, 5).join(', ') : '';
442
- const source = r.source_type || 'unknown';
443
- return `${i + 1}. "${r.title}" [${source}]${tags ? ` (${tags})` : ''}\n → ${r.insight}\n WHY RELEVANT: ${why}\n DEEP DIVE: get_full_content("${r.id}")`;
444
- }).join('\n\n');
445
- const context = `SPLICR CONTEXT — The user's saved research matched this task. Use these findings to inform your response:\n\n${contextLines}\n\nACTION: Review above before answering. Call get_full_content(id) for complete articles. Fall back to web search only if these don't cover the question.`;
458
+ // Format knowledge context
459
+ let contextSection = '';
460
+ if (topResults.length > 0) {
461
+ const contextLines = topResults.map((r, i) => {
462
+ const why = r.why_relevant || 'Semantically similar to your work context';
463
+ const tags = r.tags?.length ? r.tags.slice(0, 5).join(', ') : '';
464
+ const source = r.source_type || 'unknown';
465
+ return `${i + 1}. "${r.title}" [${source}]${tags ? ` (${tags})` : ''}\n${r.insight}\n WHY RELEVANT: ${why}\n DEEP DIVE: get_full_content("${r.id}")`;
466
+ }).join('\n\n');
467
+ contextSection = `SPLICR CONTEXT — The user's saved research matched this task. Use these findings to inform your response:\n\n${contextLines}\n\nACTION: Review above before answering. Call get_full_content(id) for complete articles. Fall back to web search only if these don't cover the question.`;
468
+ }
469
+ const context = patternsSection + contextSection;
470
+ if (!context.trim()) {
471
+ process.exit(0);
472
+ return;
473
+ }
446
474
  // Output JSON that Claude Code's hook system understands
447
475
  const output = JSON.stringify({
448
476
  hookSpecificOutput: {
@@ -773,6 +801,37 @@ function saveSessionState(sessionId, injectedIds, titles) {
773
801
  }
774
802
  catch { /* non-critical */ }
775
803
  }
804
+ function loadSessionMeta(sessionId) {
805
+ if (!sessionId)
806
+ return {};
807
+ try {
808
+ const file = join(SESSION_STATE_DIR, `${sessionId}.json`);
809
+ if (existsSync(file)) {
810
+ const data = JSON.parse(readFileSync(file, 'utf-8'));
811
+ return { patterns_injected: data.patterns_injected || false };
812
+ }
813
+ }
814
+ catch { /* ignore */ }
815
+ return {};
816
+ }
817
+ function saveSessionMeta(sessionId, meta) {
818
+ if (!sessionId)
819
+ return;
820
+ try {
821
+ if (!existsSync(SESSION_STATE_DIR))
822
+ mkdirSync(SESSION_STATE_DIR, { recursive: true });
823
+ const file = join(SESSION_STATE_DIR, `${sessionId}.json`);
824
+ let existing = {};
825
+ if (existsSync(file)) {
826
+ try {
827
+ existing = JSON.parse(readFileSync(file, 'utf-8'));
828
+ }
829
+ catch { }
830
+ }
831
+ writeFileSync(file, JSON.stringify({ ...existing, ...meta, updated: Date.now() }));
832
+ }
833
+ catch { /* non-critical */ }
834
+ }
776
835
  function readStdin() {
777
836
  return new Promise((resolve) => {
778
837
  let data = '';
@@ -783,26 +842,26 @@ function readStdin() {
783
842
  setTimeout(() => resolve(data), 500);
784
843
  });
785
844
  }
786
- const SPLICR_INSTRUCTION = `Call get_relevant_context (Splicr MCP) at the START of any task. Pass your understanding of the task (the user's message), any files you're reading/modifying, and any errors you've encountered. It automatically searches the user's knowledge base using full context awareness — your task, git branch, recent commits, changed files, and more.
787
-
788
- For follow-up or narrow searches during the same task, use search_knowledge with a specific query.
789
-
790
- When results have high relevance (>50%), call get_full_content(id) to get the complete saved content before responding.
791
-
792
- Splicr is the user's personal knowledge base. They save articles, tweets, code snippets, and research. Your job is to use it — not ignore it and rely on training data alone.
793
-
794
- ## Auto-save learnings
795
- At the END of significant sessions (not trivial ones), review what you learned and save decisions/discoveries to Splicr using save_from_agent. Include the context field for attribution.
796
-
797
- Save ONLY: decisions (chose X over Y because...), discoveries (undocumented behavior), workarounds (non-obvious fixes), synthesis (combined multiple insights into a new approach).
798
- Do NOT save: file edits, routine commands, anything derivable from git log or reading the current code.
799
-
800
- Ask yourself: "Would a developer starting a new session benefit from knowing this?" If yes, save it.
801
-
802
- ## Failure modes
803
- - Splicr returns no results → fall back to web search or training data
804
- - Splicr returns results but they don't answer the question → supplement with web search
805
- - Splicr API is unreachable → proceed without it, don't block the session
845
+ const SPLICR_INSTRUCTION = `Call get_relevant_context (Splicr MCP) at the START of any task. Pass your understanding of the task (the user's message), any files you're reading/modifying, and any errors you've encountered. It automatically searches the user's knowledge base using full context awareness — your task, git branch, recent commits, changed files, and more.
846
+
847
+ For follow-up or narrow searches during the same task, use search_knowledge with a specific query.
848
+
849
+ When results have high relevance (>50%), call get_full_content(id) to get the complete saved content before responding.
850
+
851
+ Splicr is the user's personal knowledge base. They save articles, tweets, code snippets, and research. Your job is to use it — not ignore it and rely on training data alone.
852
+
853
+ ## Auto-save learnings
854
+ At the END of significant sessions (not trivial ones), review what you learned and save decisions/discoveries to Splicr using save_from_agent. Include the context field for attribution.
855
+
856
+ Save ONLY: decisions (chose X over Y because...), discoveries (undocumented behavior), workarounds (non-obvious fixes), synthesis (combined multiple insights into a new approach).
857
+ Do NOT save: file edits, routine commands, anything derivable from git log or reading the current code.
858
+
859
+ Ask yourself: "Would a developer starting a new session benefit from knowing this?" If yes, save it.
860
+
861
+ ## Failure modes
862
+ - Splicr returns no results → fall back to web search or training data
863
+ - Splicr returns results but they don't answer the question → supplement with web search
864
+ - Splicr API is unreachable → proceed without it, don't block the session
806
865
  - You forgot to save learnings → the Stop hook will remind you`;
807
866
  const SPLICR_MARKER = '# Splicr';
808
867
  function getInstructionFiles() {
@@ -1052,17 +1111,17 @@ async function teamCommand() {
1052
1111
  break;
1053
1112
  }
1054
1113
  default:
1055
- console.error(`
1056
- Splicr Teams
1057
-
1058
- Commands:
1059
- team create "Name" Create a new team
1060
- team list List your teams
1061
- team invite Show invite link for your team
1062
- team join <code> Join a team by invite code
1063
-
1064
- Or use setup --join:
1065
- setup --join <code> Sign up + join team + configure agents (one command)
1114
+ console.error(`
1115
+ Splicr Teams
1116
+
1117
+ Commands:
1118
+ team create "Name" Create a new team
1119
+ team list List your teams
1120
+ team invite Show invite link for your team
1121
+ team join <code> Join a team by invite code
1122
+
1123
+ Or use setup --join:
1124
+ setup --join <code> Sign up + join team + configure agents (one command)
1066
1125
  `);
1067
1126
  break;
1068
1127
  }
@@ -1079,34 +1138,34 @@ function printManualConfig() {
1079
1138
  console.error(' }\n');
1080
1139
  }
1081
1140
  function printHelp() {
1082
- console.error(`
1083
- Splicr — route what you read to what you're building
1084
-
1085
- Getting started:
1086
- npx @splicr/mcp-server setup Sign up + configure all agents (one command)
1087
- npx @splicr/mcp-server setup --join <code> Sign up + join team + configure agents
1088
-
1089
- Commands:
1090
- setup One-time setup: authenticate + configure agents + hooks
1091
- login Re-authenticate
1092
- team create "Name" Create a new team
1093
- team list List your teams
1094
- team invite Show invite link for your team
1095
- team join <code> Join a team by invite code
1096
- dashboard Open knowledge dashboard in browser
1097
- uninstall Remove Splicr from all coding agents
1098
-
1099
- Supported agents (auto-detected):
1100
- Claude Code, Codex, Cursor, Cline, Antigravity
1101
-
1102
- Quick start:
1103
- 1. Run: npx @splicr/mcp-server setup
1104
- 2. Save knowledge from anywhere:
1105
- - Telegram: t.me/SplicrBot (send links from your phone)
1106
- - Extension: chromewebstore.google.com/detail/dllhofjfmkmbdadilbdgojapfbmlhnla
1107
- - Agent: save_from_agent tool (agents save learnings)
1108
- 3. Open any coding agent — your saves show up when relevant
1109
- 4. Dashboard: splicr.dev/dashboard
1141
+ console.error(`
1142
+ Splicr — route what you read to what you're building
1143
+
1144
+ Getting started:
1145
+ npx @splicr/mcp-server setup Sign up + configure all agents (one command)
1146
+ npx @splicr/mcp-server setup --join <code> Sign up + join team + configure agents
1147
+
1148
+ Commands:
1149
+ setup One-time setup: authenticate + configure agents + hooks
1150
+ login Re-authenticate
1151
+ team create "Name" Create a new team
1152
+ team list List your teams
1153
+ team invite Show invite link for your team
1154
+ team join <code> Join a team by invite code
1155
+ dashboard Open knowledge dashboard in browser
1156
+ uninstall Remove Splicr from all coding agents
1157
+
1158
+ Supported agents (auto-detected):
1159
+ Claude Code, Codex, Cursor, Cline, Antigravity
1160
+
1161
+ Quick start:
1162
+ 1. Run: npx @splicr/mcp-server setup
1163
+ 2. Save knowledge from anywhere:
1164
+ - Telegram: t.me/SplicrBot (send links from your phone)
1165
+ - Extension: chromewebstore.google.com/detail/dllhofjfmkmbdadilbdgojapfbmlhnla
1166
+ - Agent: save_from_agent tool (agents save learnings)
1167
+ 3. Open any coding agent — your saves show up when relevant
1168
+ 4. Dashboard: splicr.dev/dashboard
1110
1169
  `);
1111
1170
  }
1112
1171
  main().catch(err => {
package/dist/index.js CHANGED
@@ -35,18 +35,18 @@ for (const signal of ['SIGTERM', 'SIGINT']) {
35
35
  }
36
36
  const server = new Server({ name: 'splicr', version: '0.1.0' }, {
37
37
  capabilities: { tools: {} },
38
- instructions: `Splicr is the user's personal knowledge base — articles, tweets, code snippets, GitHub repos, and agent learnings saved from across the web. It is your PRIMARY source of context. Using it is not optional.
39
-
40
- CONTRACTS (you must follow these):
41
- 1. BEFORE answering any question, BEFORE web searching, BEFORE relying on training data — call get_relevant_context with the user's task. This is not a suggestion. The user saved knowledge specifically for moments like this.
42
- 2. When results have relevance >50%, call get_full_content(id) to get the complete saved content. Use it to ground your response.
43
- 2b. When results include a compiled_page field, prefer get_compiled_page(id) — it's a synthesized wiki page merging multiple related sources into one structured document. More useful than reading individual captures.
44
- 3. Only fall back to web search or training data if Splicr returns no results or results don't cover the question.
45
- 4. At the END of significant sessions, call save_from_agent with decisions, discoveries, or workarounds you made. Include the context field for attribution.
46
-
47
- FAILURE MODES:
48
- - Splicr returns no results → proceed with web search or training data
49
- - Splicr API is unreachable → proceed without it, don't block the session
38
+ instructions: `Splicr is the user's personal knowledge base — articles, tweets, code snippets, GitHub repos, and agent learnings saved from across the web. It is your PRIMARY source of context. Using it is not optional.
39
+
40
+ CONTRACTS (you must follow these):
41
+ 1. BEFORE answering any question, BEFORE web searching, BEFORE relying on training data — call get_relevant_context with the user's task. This is not a suggestion. The user saved knowledge specifically for moments like this.
42
+ 2. When results have relevance >50%, call get_full_content(id) to get the complete saved content. Use it to ground your response.
43
+ 2b. When results include a compiled_page field, prefer get_compiled_page(id) — it's a synthesized wiki page merging multiple related sources into one structured document. More useful than reading individual captures.
44
+ 3. Only fall back to web search or training data if Splicr returns no results or results don't cover the question.
45
+ 4. At the END of significant sessions, call save_from_agent with decisions, discoveries, or workarounds you made. Include the context field for attribution.
46
+
47
+ FAILURE MODES:
48
+ - Splicr returns no results → proceed with web search or training data
49
+ - Splicr API is unreachable → proceed without it, don't block the session
50
50
  - Results don't match the question → supplement with other sources`,
51
51
  });
52
52
  // List tools
@@ -146,7 +146,4 @@ export declare function getDecisions(params: {
146
146
  }): Promise<{
147
147
  results: any[];
148
148
  }>;
149
- export declare function getTeamStatus(params: {
150
- project?: string;
151
- }): Promise<any>;
152
149
  export { API_URL };
@@ -104,8 +104,4 @@ export async function getDecisions(params) {
104
104
  const data = await apiRequest('POST', '/mcp/decisions', params);
105
105
  return { results: data.results ?? [] };
106
106
  }
107
- export async function getTeamStatus(params) {
108
- const query = params.project ? `?project=${encodeURIComponent(params.project)}` : '';
109
- return await apiRequest('GET', `/mcp/team-status${query}`);
110
- }
111
107
  export { API_URL };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Local GitHub Status - uses `gh` CLI instead of stored token.
3
+ * Zero onboarding friction: if the user has `gh auth login` done, this just works.
4
+ */
5
+ export interface TeamStatus {
6
+ repo: string;
7
+ open_prs: Array<{
8
+ number: number;
9
+ title: string;
10
+ author: string;
11
+ branch: string;
12
+ updated: string;
13
+ draft: boolean;
14
+ }>;
15
+ recent_merges: Array<{
16
+ title: string;
17
+ author: string;
18
+ merged_at: string;
19
+ }>;
20
+ active_branches: Array<{
21
+ name: string;
22
+ }>;
23
+ error?: string;
24
+ }
25
+ export declare function getLocalGitHubStatus(cwd: string): Promise<TeamStatus>;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Local GitHub Status - uses `gh` CLI instead of stored token.
3
+ * Zero onboarding friction: if the user has `gh auth login` done, this just works.
4
+ */
5
+ import { execSync } from 'child_process';
6
+ import { getGitRemoteUrl, normalizeGitUrl } from './project-detector.js';
7
+ /** Check if `gh` CLI is available and authenticated */
8
+ function isGhAvailable() {
9
+ try {
10
+ execSync('gh auth status', { encoding: 'utf-8', stdio: 'pipe' });
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ /** Extract owner/repo from a git remote URL */
18
+ function extractRepoFullName(cwd) {
19
+ const remote = getGitRemoteUrl(cwd);
20
+ if (!remote)
21
+ return null;
22
+ const normalized = normalizeGitUrl(remote);
23
+ // https://github.com/owner/repo -> owner/repo
24
+ const match = normalized.match(/github\.com\/([^/]+\/[^/]+)/);
25
+ return match ? match[1] : null;
26
+ }
27
+ /** Run a gh api command and parse JSON result */
28
+ function ghApi(endpoint) {
29
+ try {
30
+ const result = execSync(`gh api "${endpoint}" --paginate`, {
31
+ encoding: 'utf-8',
32
+ stdio: ['pipe', 'pipe', 'pipe'],
33
+ timeout: 10000,
34
+ });
35
+ return JSON.parse(result);
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ export async function getLocalGitHubStatus(cwd) {
42
+ const repoFullName = extractRepoFullName(cwd);
43
+ if (!repoFullName) {
44
+ return { repo: 'unknown', open_prs: [], recent_merges: [], active_branches: [], error: 'No GitHub remote found in this directory.' };
45
+ }
46
+ if (!isGhAvailable()) {
47
+ return { repo: repoFullName, open_prs: [], recent_merges: [], active_branches: [], error: 'GitHub CLI (gh) not authenticated. Run `gh auth login` to enable team status.' };
48
+ }
49
+ const status = {
50
+ repo: repoFullName,
51
+ open_prs: [],
52
+ recent_merges: [],
53
+ active_branches: [],
54
+ };
55
+ // Fetch open PRs
56
+ const openPRs = ghApi(`repos/${repoFullName}/pulls?state=open&sort=updated&direction=desc&per_page=10`);
57
+ if (openPRs) {
58
+ status.open_prs = openPRs.map(pr => ({
59
+ number: pr.number,
60
+ title: pr.title,
61
+ author: pr.user.login,
62
+ branch: pr.head?.ref || pr.headRefName || '',
63
+ updated: pr.updated_at || pr.updatedAt || '',
64
+ draft: pr.draft ?? pr.isDraft ?? false,
65
+ }));
66
+ }
67
+ // Fetch recently merged PRs
68
+ const mergedPRs = ghApi(`repos/${repoFullName}/pulls?state=closed&sort=updated&direction=desc&per_page=10`);
69
+ if (mergedPRs) {
70
+ const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
71
+ status.recent_merges = mergedPRs
72
+ .filter(pr => {
73
+ const mergedDate = pr.merged_at || pr.mergedAt || pr.updated_at || pr.updatedAt;
74
+ return mergedDate && new Date(mergedDate) >= sevenDaysAgo;
75
+ })
76
+ .map(pr => ({
77
+ title: pr.title,
78
+ author: pr.user.login,
79
+ merged_at: pr.merged_at || pr.mergedAt || pr.updated_at || pr.updatedAt || '',
80
+ }));
81
+ }
82
+ // Fetch branches
83
+ const branches = ghApi(`repos/${repoFullName}/branches?per_page=20`);
84
+ if (branches) {
85
+ const skipBranches = new Set(['main', 'master', 'develop', 'dev', 'staging', 'production']);
86
+ status.active_branches = branches
87
+ .filter(b => !skipBranches.has(b.name))
88
+ .slice(0, 10)
89
+ .map(b => ({ name: b.name }));
90
+ }
91
+ return status;
92
+ }
@@ -3,14 +3,14 @@ import { detectProject } from '../lib/project-detector.js';
3
3
  import * as session from '../lib/session-state.js';
4
4
  export const getDecisionsSchema = {
5
5
  name: 'get_decisions',
6
- description: `Query the team's decision log - technical decisions, patterns, discoveries, and failures recorded during agent sessions.
7
-
8
- Use when:
9
- - Before making an architecture or technology choice (see what the team decided before)
10
- - When someone asks "why did we do X this way?"
11
- - When evaluating alternatives for a new approach
12
- - To check if something was tried before and failed
13
-
6
+ description: `Query the team's decision log - technical decisions, patterns, discoveries, and failures recorded during agent sessions.
7
+
8
+ Use when:
9
+ - Before making an architecture or technology choice (see what the team decided before)
10
+ - When someone asks "why did we do X this way?"
11
+ - When evaluating alternatives for a new approach
12
+ - To check if something was tried before and failed
13
+
14
14
  Returns structured decisions with rationale, alternatives considered, and anti-pattern warnings.`,
15
15
  inputSchema: {
16
16
  type: 'object',
@@ -4,8 +4,8 @@ import { gatherSignals } from '../lib/signal-gatherer.js';
4
4
  import { fuseSignals } from '../lib/signal-fusion.js';
5
5
  export const getProjectContextSchema = {
6
6
  name: 'get_project_context',
7
- description: `Show what's new in a project's knowledge feed from Splicr. Only call this when the user explicitly asks to see new saves, recent context, or "what's new." Do NOT call this proactively at session start.
8
-
7
+ description: `Show what's new in a project's knowledge feed from Splicr. Only call this when the user explicitly asks to see new saves, recent context, or "what's new." Do NOT call this proactively at session start.
8
+
9
9
  Uses a watermark system — only returns captures saved since the last time context was served for this project. Safe to call repeatedly; it will return empty if nothing is new.`,
10
10
  inputSchema: {
11
11
  type: 'object',
@@ -3,12 +3,7 @@ export declare const getTeamStatusSchema: {
3
3
  description: string;
4
4
  inputSchema: {
5
5
  type: "object";
6
- properties: {
7
- project: {
8
- type: "string";
9
- description: string;
10
- };
11
- };
6
+ properties: {};
12
7
  };
13
8
  };
14
9
  export declare function handleGetTeamStatus(args: Record<string, unknown>): Promise<string>;
@@ -1,34 +1,22 @@
1
- import { getTeamStatus } from '../lib/api-client.js';
2
- import { detectProject } from '../lib/project-detector.js';
1
+ import { getLocalGitHubStatus } from '../lib/github-local.js';
3
2
  import * as session from '../lib/session-state.js';
4
3
  export const getTeamStatusSchema = {
5
4
  name: 'get_team_status',
6
- description: `Get a brief on what the team is working on right now. Shows open PRs, active branches, and recent merges from GitHub.
7
-
8
- Use when:
9
- - Starting a session and want to know what's in flight
10
- - Before starting work on a feature (check if someone else is already on it)
11
- - To understand recent changes to the codebase
12
-
13
- Requires GitHub integration (connected via Splicr dashboard).`,
5
+ description: `Get a brief on what the team is working on right now. Shows open PRs, active branches, and recent merges from GitHub.
6
+
7
+ Use when:
8
+ - Starting a session and want to know what's in flight
9
+ - Before starting work on a feature (check if someone else is already on it)
10
+ - To understand recent changes to the codebase
11
+
12
+ Requires GitHub CLI (gh) to be authenticated. Run \`gh auth login\` if not set up.`,
14
13
  inputSchema: {
15
14
  type: 'object',
16
- properties: {
17
- project: { type: 'string', description: 'Project name or "auto" (default: auto)' },
18
- },
15
+ properties: {},
19
16
  },
20
17
  };
21
18
  export async function handleGetTeamStatus(args) {
22
- const projectArg = args.project || 'auto';
23
- let projectName;
24
- if (projectArg === 'auto') {
25
- const detected = await detectProject(process.cwd());
26
- projectName = detected?.name;
27
- }
28
- else {
29
- projectName = projectArg;
30
- }
31
- const data = await getTeamStatus({ project: projectName });
19
+ const data = await getLocalGitHubStatus(process.cwd());
32
20
  session.recordToolCall();
33
21
  if (data.error) {
34
22
  return data.error;
@@ -3,20 +3,20 @@ import { detectProject } from '../lib/project-detector.js';
3
3
  import * as session from '../lib/session-state.js';
4
4
  export const saveFromAgentSchema = {
5
5
  name: 'save_from_agent',
6
- description: `Save knowledge to Splicr. Call this in two scenarios:
7
-
8
- 1. When the user explicitly asks to save/remember something
9
- 2. At the end of significant sessions — save decisions, discoveries, and workarounds (NOT routine actions)
10
-
11
- For auto-save at session end, include the "context" field with attribution metadata.
12
-
13
- **Memory types** (use memory_type to categorize):
14
- - "fact" — permanent knowledge (API uses X pattern, team decided Y). Default if omitted.
15
- - "procedural" — reusable how-to (deploy steps, workarounds, setup instructions)
16
- - "episodic" — session-level context (what happened this session, investigation results)
17
- - "scratchpad" — short-lived working memory (temp notes, in-progress thinking)
18
-
19
- What to save: decisions (chose X over Y because...), discoveries (found undocumented behavior), workarounds (non-obvious fix), synthesis (combined multiple insights).
6
+ description: `Save knowledge to Splicr. Call this in two scenarios:
7
+
8
+ 1. When the user explicitly asks to save/remember something
9
+ 2. At the end of significant sessions — save decisions, discoveries, and workarounds (NOT routine actions)
10
+
11
+ For auto-save at session end, include the "context" field with attribution metadata.
12
+
13
+ **Memory types** (use memory_type to categorize):
14
+ - "fact" — permanent knowledge (API uses X pattern, team decided Y). Default if omitted.
15
+ - "procedural" — reusable how-to (deploy steps, workarounds, setup instructions)
16
+ - "episodic" — session-level context (what happened this session, investigation results)
17
+ - "scratchpad" — short-lived working memory (temp notes, in-progress thinking)
18
+
19
+ What to save: decisions (chose X over Y because...), discoveries (found undocumented behavior), workarounds (non-obvious fix), synthesis (combined multiple insights).
20
20
  What NOT to save: file edits (git has those), routine commands, anything derivable from reading the code.`,
21
21
  inputSchema: {
22
22
  type: 'object',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splicr/mcp-server",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "Splicr MCP server — route what you read to what you're building",
5
5
  "type": "module",
6
6
  "bin": "./dist/cli.js",