@splicr/mcp-server 0.1.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 (53) hide show
  1. package/dist/auth.d.ts +18 -0
  2. package/dist/auth.d.ts.map +1 -0
  3. package/dist/auth.js +115 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/cli.d.ts +11 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +80 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/config.d.ts +10 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +34 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +93 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/lib/auto-register.d.ts +7 -0
  18. package/dist/lib/auto-register.d.ts.map +1 -0
  19. package/dist/lib/auto-register.js +204 -0
  20. package/dist/lib/auto-register.js.map +1 -0
  21. package/dist/lib/project-detector.d.ts +12 -0
  22. package/dist/lib/project-detector.d.ts.map +1 -0
  23. package/dist/lib/project-detector.js +68 -0
  24. package/dist/lib/project-detector.js.map +1 -0
  25. package/dist/lib/supabase.d.ts +14 -0
  26. package/dist/lib/supabase.d.ts.map +1 -0
  27. package/dist/lib/supabase.js +50 -0
  28. package/dist/lib/supabase.js.map +1 -0
  29. package/dist/login-cli.d.ts +3 -0
  30. package/dist/login-cli.d.ts.map +1 -0
  31. package/dist/login-cli.js +7 -0
  32. package/dist/login-cli.js.map +1 -0
  33. package/dist/tools/get-project-context.d.ts +20 -0
  34. package/dist/tools/get-project-context.d.ts.map +1 -0
  35. package/dist/tools/get-project-context.js +59 -0
  36. package/dist/tools/get-project-context.js.map +1 -0
  37. package/dist/tools/get-recent-insights.d.ts +19 -0
  38. package/dist/tools/get-recent-insights.d.ts.map +1 -0
  39. package/dist/tools/get-recent-insights.js +55 -0
  40. package/dist/tools/get-recent-insights.js.map +1 -0
  41. package/dist/tools/retry-failed.d.ts +10 -0
  42. package/dist/tools/retry-failed.d.ts.map +1 -0
  43. package/dist/tools/retry-failed.js +53 -0
  44. package/dist/tools/retry-failed.js.map +1 -0
  45. package/dist/tools/save-from-agent.d.ts +31 -0
  46. package/dist/tools/save-from-agent.d.ts.map +1 -0
  47. package/dist/tools/save-from-agent.js +84 -0
  48. package/dist/tools/save-from-agent.js.map +1 -0
  49. package/dist/tools/search-knowledge.d.ts +24 -0
  50. package/dist/tools/search-knowledge.d.ts.map +1 -0
  51. package/dist/tools/search-knowledge.js +160 -0
  52. package/dist/tools/search-knowledge.js.map +1 -0
  53. package/package.json +29 -0
@@ -0,0 +1,12 @@
1
+ interface DetectedProject {
2
+ id: string;
3
+ name: string;
4
+ confidence: 'exact' | 'inferred';
5
+ }
6
+ /** Normalize path for consistent DB lookups across Windows/WSL/Mac */
7
+ export declare function normalizePath(p: string): string;
8
+ export declare function detectProject(cwd: string): Promise<DetectedProject | null>;
9
+ export declare function getGitRemoteUrl(cwd: string): string | null;
10
+ export declare function normalizeGitUrl(url: string): string;
11
+ export {};
12
+ //# sourceMappingURL=project-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-detector.d.ts","sourceRoot":"","sources":["../../src/lib/project-detector.ts"],"names":[],"mappings":"AAIA,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC;CAClC;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA2ChF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO1D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAInD"}
@@ -0,0 +1,68 @@
1
+ import { execSync } from 'child_process';
2
+ import { getSupabase } from './supabase.js';
3
+ import { autoRegisterProject } from './auto-register.js';
4
+ /** Normalize path for consistent DB lookups across Windows/WSL/Mac */
5
+ export function normalizePath(p) {
6
+ return p
7
+ .replace(/\\/g, '/') // backslash → forward slash
8
+ .replace(/\/+$/, '') // strip trailing slash
9
+ .replace(/^([A-Z]):/, (_, d) => `${d.toLowerCase()}:`); // C: → c:
10
+ }
11
+ export async function detectProject(cwd) {
12
+ const { supabase, userId } = await getSupabase();
13
+ const normalizedCwd = normalizePath(cwd);
14
+ // 1. Direct path match (try both raw and normalized)
15
+ const { data: byPath } = await supabase
16
+ .from('projects')
17
+ .select('id, name')
18
+ .eq('user_id', userId)
19
+ .eq('local_path', normalizedCwd)
20
+ .single();
21
+ if (byPath)
22
+ return { ...byPath, confidence: 'exact' };
23
+ // 2. Git remote match
24
+ const gitRemote = getGitRemoteUrl(cwd);
25
+ if (gitRemote) {
26
+ const normalized = normalizeGitUrl(gitRemote);
27
+ const { data: byRepo } = await supabase
28
+ .from('projects')
29
+ .select('id, name')
30
+ .eq('user_id', userId)
31
+ .eq('github_repo_url', normalized)
32
+ .single();
33
+ if (byRepo)
34
+ return { ...byRepo, confidence: 'exact' };
35
+ }
36
+ // 3. Fuzzy match by directory name
37
+ const dirName = normalizedCwd.split('/').pop()?.toLowerCase();
38
+ if (dirName) {
39
+ const { data: projects } = await supabase
40
+ .from('projects')
41
+ .select('id, name')
42
+ .eq('user_id', userId)
43
+ .eq('status', 'active');
44
+ const match = projects?.find(p => p.name.toLowerCase() === dirName);
45
+ if (match)
46
+ return { ...match, confidence: 'inferred' };
47
+ }
48
+ // 4. Auto-register from local files
49
+ const registered = await autoRegisterProject(cwd);
50
+ if (registered)
51
+ return { ...registered, confidence: 'inferred' };
52
+ return null;
53
+ }
54
+ export function getGitRemoteUrl(cwd) {
55
+ try {
56
+ const result = execSync('git config --get remote.origin.url', { cwd, encoding: 'utf-8' });
57
+ return result.trim();
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ }
63
+ export function normalizeGitUrl(url) {
64
+ return url
65
+ .replace(/^git@github\.com:/, 'https://github.com/')
66
+ .replace(/\.git$/, '');
67
+ }
68
+ //# sourceMappingURL=project-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-detector.js","sourceRoot":"","sources":["../../src/lib/project-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { SupabaseClient } from '@supabase/supabase-js';
2
+ /**
3
+ * Get an authenticated Supabase client.
4
+ * - If auth.json exists: uses anon key + user JWT (RLS enforced)
5
+ * - Fallback: uses service role key + hardcoded userId (legacy, deprecated)
6
+ */
7
+ export declare function getSupabase(): Promise<{
8
+ supabase: SupabaseClient;
9
+ userId: string;
10
+ }>;
11
+ export declare const geminiApiKey: string;
12
+ export declare const supabase: SupabaseClient<any, "public", "public", any, any>;
13
+ export declare const userId: string;
14
+ //# sourceMappingURL=supabase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAYrE;;;;GAIG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCzF;AAGD,eAAO,MAAM,YAAY,QAAsB,CAAC;AAIhD,eAAO,MAAM,QAAQ,mDAAkE,CAAC;AACxF,eAAO,MAAM,MAAM,QAAgB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+ import { loadConfig } from '../config.js';
3
+ import { loadAuth, hasAuth } from '../auth.js';
4
+ const config = loadConfig();
5
+ // Cached client and user
6
+ let _client = null;
7
+ let _userId = null;
8
+ let _mode = null;
9
+ let _lastToken = null;
10
+ /**
11
+ * Get an authenticated Supabase client.
12
+ * - If auth.json exists: uses anon key + user JWT (RLS enforced)
13
+ * - Fallback: uses service role key + hardcoded userId (legacy, deprecated)
14
+ */
15
+ export async function getSupabase() {
16
+ if (hasAuth() && config.supabaseAnonKey) {
17
+ // JWT auth mode — RLS enforced
18
+ const auth = await loadAuth();
19
+ // Only recreate client if token actually changed
20
+ if (_mode !== 'jwt' || _userId !== auth.userId || _lastToken !== auth.accessToken) {
21
+ _client = createClient(config.supabaseUrl, config.supabaseAnonKey, {
22
+ global: {
23
+ headers: { Authorization: `Bearer ${auth.accessToken}` },
24
+ },
25
+ });
26
+ _userId = auth.userId;
27
+ _mode = 'jwt';
28
+ _lastToken = auth.accessToken;
29
+ }
30
+ return { supabase: _client, userId: auth.userId };
31
+ }
32
+ // Legacy fallback — service role key bypasses RLS
33
+ if (!_client || _mode !== 'legacy') {
34
+ if (!config.userId) {
35
+ throw new Error('Not authenticated. Run `splicr login` or set SPLICR_USER_ID env var.');
36
+ }
37
+ console.error('[Splicr MCP] WARNING: Using legacy service role key auth. Run `splicr login` to switch to user-scoped auth.');
38
+ _client = createClient(config.supabaseUrl, config.supabaseServiceRoleKey);
39
+ _userId = config.userId;
40
+ _mode = 'legacy';
41
+ }
42
+ return { supabase: _client, userId: _userId };
43
+ }
44
+ // Gemini API key (unchanged — not auth-related)
45
+ export const geminiApiKey = config.geminiApiKey;
46
+ // Legacy exports for backward compat during transition
47
+ // TODO: Remove after all tool files are migrated to getSupabase()
48
+ export const supabase = createClient(config.supabaseUrl, config.supabaseServiceRoleKey);
49
+ export const userId = config.userId;
50
+ //# sourceMappingURL=supabase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkB,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAE5B,yBAAyB;AACzB,IAAI,OAAO,GAA0B,IAAI,CAAC;AAC1C,IAAI,OAAO,GAAkB,IAAI,CAAC;AAClC,IAAI,KAAK,GAA4B,IAAI,CAAC;AAC1C,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,OAAO,EAAE,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QACxC,+BAA+B;QAC/B,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;QAE9B,iDAAiD;QACjD,IAAI,KAAK,KAAK,KAAK,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,UAAU,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YAClF,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,eAAe,EAAE;gBACjE,MAAM,EAAE;oBACN,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,WAAW,EAAE,EAAE;iBACzD;aACF,CAAC,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;YACtB,KAAK,GAAG,KAAK,CAAC;YACd,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC;QAChC,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,OAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IACrD,CAAC;IAED,kDAAkD;IAClD,IAAI,CAAC,OAAO,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,6GAA6G,CAAC,CAAC;QAC7H,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAC1E,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;QACxB,KAAK,GAAG,QAAQ,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAQ,EAAE,MAAM,EAAE,OAAQ,EAAE,CAAC;AAClD,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;AAEhD,uDAAuD;AACvD,kEAAkE;AAClE,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,sBAAsB,CAAC,CAAC;AACxF,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=login-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-cli.d.ts","sourceRoot":"","sources":["../src/login-cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { login } from './auth.js';
3
+ login().catch(err => {
4
+ console.error('Login error:', err.message);
5
+ process.exit(1);
6
+ });
7
+ //# sourceMappingURL=login-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-cli.js","sourceRoot":"","sources":["../src/login-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;IAClB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ export declare const getProjectContextSchema: {
2
+ name: "get_project_context";
3
+ description: string;
4
+ inputSchema: {
5
+ type: "object";
6
+ properties: {
7
+ project: {
8
+ type: "string";
9
+ description: string;
10
+ };
11
+ limit: {
12
+ type: "number";
13
+ description: string;
14
+ };
15
+ };
16
+ required: "project"[];
17
+ };
18
+ };
19
+ export declare function handleGetProjectContext(args: Record<string, unknown>): Promise<string>;
20
+ //# sourceMappingURL=get-project-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-project-context.d.ts","sourceRoot":"","sources":["../../src/tools/get-project-context.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;CAanC,CAAC;AAEF,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA6C5F"}
@@ -0,0 +1,59 @@
1
+ import { getSupabase } from '../lib/supabase.js';
2
+ import { detectProject } from '../lib/project-detector.js';
3
+ export const getProjectContextSchema = {
4
+ name: 'get_project_context',
5
+ 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.
6
+
7
+ 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.`,
8
+ inputSchema: {
9
+ type: 'object',
10
+ properties: {
11
+ project: { type: 'string', description: 'Project name or "auto" to detect from cwd' },
12
+ limit: { type: 'number', description: 'Max results (default: 10)' },
13
+ },
14
+ required: ['project'],
15
+ },
16
+ };
17
+ export async function handleGetProjectContext(args) {
18
+ const { supabase, userId } = await getSupabase();
19
+ const projectArg = args.project;
20
+ const limit = Math.min(Math.max(1, Number(args.limit) || 20), 100);
21
+ // Resolve project
22
+ let projectId;
23
+ let projectName;
24
+ if (projectArg === 'auto') {
25
+ const detected = await detectProject(process.cwd());
26
+ if (!detected)
27
+ return 'Could not auto-detect project from current directory. Specify a project name.';
28
+ projectId = detected.id;
29
+ projectName = detected.name;
30
+ }
31
+ else {
32
+ const { data, error: lookupError } = await supabase
33
+ .from('projects')
34
+ .select('id, name')
35
+ .eq('user_id', userId)
36
+ .ilike('name', projectArg)
37
+ .limit(1);
38
+ if (lookupError || !data?.[0]?.id) {
39
+ return `Project "${projectArg}" not found.`;
40
+ }
41
+ projectId = data[0].id;
42
+ projectName = data[0].name;
43
+ }
44
+ // Call DB function (reads watermark, updates it, returns only new captures)
45
+ const { data, error } = await supabase.rpc('get_project_context', {
46
+ p_user_id: userId,
47
+ p_project_id: projectId,
48
+ p_limit: limit,
49
+ });
50
+ if (error)
51
+ return `Error: ${error.message}`;
52
+ if (!data || data.length === 0)
53
+ return `No new saves for ${projectName} since last check.`;
54
+ const items = data.map((r, i) => `${i + 1}. **${r.title || 'Untitled'}** · splicr [${r.relevance}]\n` +
55
+ ` ${r.insight}\n` +
56
+ ` Tags: ${r.tags?.join(', ') || 'none'}${r.source_url ? ` | ${r.source_url}` : ''}`).join('\n\n');
57
+ return `*From Splicr — ${data.length} new save(s) for ${projectName}:*\n\n${items}`;
58
+ }
59
+ //# sourceMappingURL=get-project-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-project-context.js","sourceRoot":"","sources":["../../src/tools/get-project-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export declare const getRecentInsightsSchema: {
2
+ name: "get_recent_insights";
3
+ description: string;
4
+ inputSchema: {
5
+ type: "object";
6
+ properties: {
7
+ days: {
8
+ type: "number";
9
+ description: string;
10
+ };
11
+ limit: {
12
+ type: "number";
13
+ description: string;
14
+ };
15
+ };
16
+ };
17
+ };
18
+ export declare function handleGetRecentInsights(args: Record<string, unknown>): Promise<string>;
19
+ //# sourceMappingURL=get-recent-insights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-recent-insights.d.ts","sourceRoot":"","sources":["../../src/tools/get-recent-insights.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;CAUnC,CAAC;AAEF,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA6C5F"}
@@ -0,0 +1,55 @@
1
+ import { getSupabase } from '../lib/supabase.js';
2
+ export const getRecentInsightsSchema = {
3
+ name: 'get_recent_insights',
4
+ description: `Show everything the user saved recently across all projects in Splicr. Only call when the user explicitly asks to see their recent saves or wants a cross-project overview.`,
5
+ inputSchema: {
6
+ type: 'object',
7
+ properties: {
8
+ days: { type: 'number', description: 'Last N days (default: 3)' },
9
+ limit: { type: 'number', description: 'Max results (default: 15)' },
10
+ },
11
+ },
12
+ };
13
+ export async function handleGetRecentInsights(args) {
14
+ const { supabase, userId } = await getSupabase();
15
+ const days = Math.min(Math.max(1, Number(args.days) || 3), 365);
16
+ const limit = Math.min(Math.max(1, Number(args.limit) || 15), 100);
17
+ const since = new Date();
18
+ since.setDate(since.getDate() - days);
19
+ const { data, error } = await supabase
20
+ .from('captures')
21
+ .select(`
22
+ id, title, insight, source_url, source_type, content_category, tags, created_at,
23
+ project_captures ( project_id, relevance, projects:project_id ( name ) )
24
+ `)
25
+ .eq('user_id', userId)
26
+ .eq('status', 'complete')
27
+ .gte('created_at', since.toISOString())
28
+ .order('created_at', { ascending: false })
29
+ .limit(limit);
30
+ if (error)
31
+ return `Error: ${error.message}`;
32
+ if (!data || data.length === 0)
33
+ return `No saves in the last ${days} days.`;
34
+ const items = data.map((c, i) => {
35
+ const projects = c.project_captures
36
+ ?.map((pc) => pc.projects?.name)
37
+ .filter(Boolean)
38
+ .join(', ') || 'General';
39
+ return `${i + 1}. **${c.title || 'Untitled'}** · splicr → ${projects}\n` +
40
+ ` ${c.insight}\n` +
41
+ ` ${c.content_category} | ${c.tags?.join(', ') || 'no tags'}`;
42
+ }).join('\n\n');
43
+ // Check for failed captures
44
+ const { count: failedCount } = await supabase
45
+ .from('captures')
46
+ .select('*', { count: 'exact', head: true })
47
+ .eq('user_id', userId)
48
+ .eq('status', 'failed');
49
+ let output = `*From Splicr — ${data.length} recent save(s):*\n\n${items}`;
50
+ if (failedCount && failedCount > 0) {
51
+ output += `\n\n_Note: ${failedCount} capture(s) failed processing. Use retry_failed to reprocess._`;
52
+ }
53
+ return output;
54
+ }
55
+ //# sourceMappingURL=get-recent-insights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-recent-insights.js","sourceRoot":"","sources":["../../src/tools/get-recent-insights.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare const retryFailedSchema: {
2
+ name: "retry_failed";
3
+ description: string;
4
+ inputSchema: {
5
+ type: "object";
6
+ properties: {};
7
+ };
8
+ };
9
+ export declare function handleRetryFailed(_args: Record<string, unknown>): Promise<string>;
10
+ //# sourceMappingURL=retry-failed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-failed.d.ts","sourceRoot":"","sources":["../../src/tools/retry-failed.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB;;;;;;;CAO7B,CAAC;AAEF,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCvF"}
@@ -0,0 +1,53 @@
1
+ import { loadAuth, hasAuth } from '../auth.js';
2
+ import { loadConfig } from '../config.js';
3
+ export const retryFailedSchema = {
4
+ name: 'retry_failed',
5
+ description: `Retry processing of failed captures in Splicr. Some captures may fail during AI processing (extraction, distillation, or routing). This tool requeues them for reprocessing. Returns the number of captures queued for retry.`,
6
+ inputSchema: {
7
+ type: 'object',
8
+ properties: {},
9
+ },
10
+ };
11
+ export async function handleRetryFailed(_args) {
12
+ const config = loadConfig();
13
+ // Get auth token for API call
14
+ let token;
15
+ if (hasAuth()) {
16
+ const auth = await loadAuth();
17
+ token = auth.accessToken;
18
+ }
19
+ else {
20
+ return 'Not authenticated. Run `splicr login` first to enable retry.';
21
+ }
22
+ // Call API server's retry endpoint
23
+ const url = `${config.apiServerUrl}/captures/retry-failed`;
24
+ try {
25
+ const response = await fetch(url, {
26
+ method: 'POST',
27
+ headers: {
28
+ 'Authorization': `Bearer ${token}`,
29
+ 'Content-Type': 'application/json',
30
+ },
31
+ signal: AbortSignal.timeout(15000),
32
+ });
33
+ if (!response.ok) {
34
+ let body = '';
35
+ try {
36
+ body = await response.text();
37
+ }
38
+ catch { }
39
+ return `Retry request failed (${response.status}): ${body}`;
40
+ }
41
+ const result = await response.json();
42
+ if (result.data.retried === 0) {
43
+ return 'No failed captures to retry.';
44
+ }
45
+ return `*Splicr:* ${result.data.message}`;
46
+ }
47
+ catch (err) {
48
+ if (err.name === 'TimeoutError')
49
+ return 'Retry request timed out after 15s.';
50
+ return `Retry request failed: ${err.message}`;
51
+ }
52
+ }
53
+ //# sourceMappingURL=retry-failed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-failed.js","sourceRoot":"","sources":["../../src/tools/retry-failed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,cAAuB;IAC7B,WAAW,EAAE,+NAA+N;IAC5O,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE,EAAE;KACf;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAA8B;IACpE,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,8BAA8B;IAC9B,IAAI,KAAa,CAAC;IAClB,IAAI,OAAO,EAAE,EAAE,CAAC;QACd,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC9B,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,OAAO,8DAA8D,CAAC;IACxE,CAAC;IAED,mCAAmC;IACnC,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,YAAY,wBAAwB,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,KAAK,EAAE;gBAClC,cAAc,EAAE,kBAAkB;aACnC;YACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;SACnC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,IAAI,CAAC;gBAAC,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YAC9C,OAAO,yBAAyB,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC;QAC9D,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAoD,CAAC;QACvF,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,8BAA8B,CAAC;QACxC,CAAC;QACD,OAAO,aAAa,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc;YAAE,OAAO,oCAAoC,CAAC;QAC7E,OAAO,yBAAyB,GAAG,CAAC,OAAO,EAAE,CAAC;IAChD,CAAC;AACH,CAAC"}
@@ -0,0 +1,31 @@
1
+ export declare const saveFromAgentSchema: {
2
+ name: "save_from_agent";
3
+ description: string;
4
+ inputSchema: {
5
+ type: "object";
6
+ properties: {
7
+ content: {
8
+ type: "string";
9
+ description: string;
10
+ };
11
+ title: {
12
+ type: "string";
13
+ description: string;
14
+ };
15
+ project: {
16
+ type: "string";
17
+ description: string;
18
+ };
19
+ tags: {
20
+ type: "array";
21
+ items: {
22
+ type: "string";
23
+ };
24
+ description: string;
25
+ };
26
+ };
27
+ required: ("title" | "content")[];
28
+ };
29
+ };
30
+ export declare function handleSaveFromAgent(args: Record<string, unknown>): Promise<string>;
31
+ //# sourceMappingURL=save-from-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save-from-agent.d.ts","sourceRoot":"","sources":["../../src/tools/save-from-agent.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAa/B,CAAC;AAEF,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAqExF"}
@@ -0,0 +1,84 @@
1
+ import { createHash } from 'crypto';
2
+ import { getSupabase } from '../lib/supabase.js';
3
+ import { detectProject } from '../lib/project-detector.js';
4
+ export const saveFromAgentSchema = {
5
+ name: 'save_from_agent',
6
+ description: `Save knowledge to Splicr. ONLY call this when the user explicitly asks to save, remember, or store something in Splicr. Do NOT call this proactively — the user decides what goes into their knowledge base, not the agent.`,
7
+ inputSchema: {
8
+ type: 'object',
9
+ properties: {
10
+ content: { type: 'string', description: 'The knowledge to save' },
11
+ title: { type: 'string', description: 'Short title' },
12
+ project: { type: 'string', description: 'Project name, "auto", or "all"' },
13
+ tags: { type: 'array', items: { type: 'string' }, description: 'Tags' },
14
+ },
15
+ required: ['content', 'title'],
16
+ },
17
+ };
18
+ export async function handleSaveFromAgent(args) {
19
+ const { supabase, userId } = await getSupabase();
20
+ const content = args.content;
21
+ const title = args.title;
22
+ const projectArg = args.project;
23
+ const tags = args.tags || [];
24
+ // Content hash for dedup
25
+ const contentHash = createHash('sha256').update(content).digest('hex').substring(0, 16);
26
+ // Insert capture (agent saves are already distilled — skip AI pipeline)
27
+ const { data: capture, error } = await supabase
28
+ .from('captures')
29
+ .insert({
30
+ user_id: userId,
31
+ source_type: 'agent',
32
+ captured_from: 'ide_agent',
33
+ title,
34
+ raw_content: content,
35
+ insight: content,
36
+ content_category: 'technique',
37
+ tags,
38
+ content_hash: contentHash,
39
+ status: 'complete',
40
+ processed_at: new Date().toISOString(),
41
+ })
42
+ .select()
43
+ .single();
44
+ // Duplicate detected by DB constraint
45
+ if (error?.code === '23505' || error?.message?.includes('duplicate key')) {
46
+ return `*Already saved in Splicr:* "${title}"`;
47
+ }
48
+ if (error)
49
+ return `Error saving: ${error.message}`;
50
+ if (!capture)
51
+ return 'Error saving: no data returned from insert';
52
+ // Route to project if specified
53
+ if (projectArg && projectArg !== 'all') {
54
+ let projectId;
55
+ if (projectArg === 'auto') {
56
+ const detected = await detectProject(process.cwd());
57
+ projectId = detected?.id;
58
+ }
59
+ else {
60
+ const { data, error: lookupError } = await supabase
61
+ .from('projects')
62
+ .select('id')
63
+ .eq('user_id', userId)
64
+ .ilike('name', projectArg)
65
+ .limit(1);
66
+ if (!lookupError) {
67
+ projectId = data?.[0]?.id;
68
+ }
69
+ }
70
+ if (projectId) {
71
+ const { error: routeError } = await supabase.from('project_captures').insert({
72
+ project_id: projectId,
73
+ capture_id: capture.id,
74
+ relevance: 'high',
75
+ routed_by: 'agent',
76
+ });
77
+ if (routeError) {
78
+ return `*Saved to Splicr:* "${title}" (warning: routing to project failed)`;
79
+ }
80
+ }
81
+ }
82
+ return `*Saved to Splicr:* "${title}"${projectArg ? ` → routed to ${projectArg}` : ''}`;
83
+ }
84
+ //# sourceMappingURL=save-from-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save-from-agent.js","sourceRoot":"","sources":["../../src/tools/save-from-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export declare const searchKnowledgeSchema: {
2
+ name: "search_knowledge";
3
+ description: string;
4
+ inputSchema: {
5
+ type: "object";
6
+ properties: {
7
+ query: {
8
+ type: "string";
9
+ description: string;
10
+ };
11
+ project: {
12
+ type: "string";
13
+ description: string;
14
+ };
15
+ limit: {
16
+ type: "number";
17
+ description: string;
18
+ };
19
+ };
20
+ required: "query"[];
21
+ };
22
+ };
23
+ export declare function handleSearchKnowledge(args: Record<string, unknown>): Promise<string>;
24
+ //# sourceMappingURL=search-knowledge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-knowledge.d.ts","sourceRoot":"","sources":["../../src/tools/search-knowledge.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAsBjC,CAAC;AAyDF,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA2E1F"}