@splicr/mcp-server 0.9.3 → 0.9.5

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 (95) hide show
  1. package/dist/auth.d.ts +13 -3
  2. package/dist/auth.js +115 -49
  3. package/dist/cli.d.ts +0 -1
  4. package/dist/cli.js +204 -30
  5. package/dist/config.d.ts +0 -1
  6. package/dist/config.js +0 -1
  7. package/dist/index.d.ts +0 -1
  8. package/dist/index.js +0 -1
  9. package/dist/lib/api-client.d.ts +0 -1
  10. package/dist/lib/api-client.js +0 -1
  11. package/dist/lib/feedback-tracker.d.ts +0 -1
  12. package/dist/lib/feedback-tracker.js +0 -1
  13. package/dist/lib/hint-engine.d.ts +0 -1
  14. package/dist/lib/hint-engine.js +0 -1
  15. package/dist/lib/profile-gatherer.d.ts +0 -1
  16. package/dist/lib/profile-gatherer.js +0 -1
  17. package/dist/lib/project-detector.d.ts +0 -1
  18. package/dist/lib/project-detector.js +0 -1
  19. package/dist/lib/session-state.d.ts +0 -1
  20. package/dist/lib/session-state.js +0 -1
  21. package/dist/lib/signal-fusion.d.ts +0 -1
  22. package/dist/lib/signal-fusion.js +0 -1
  23. package/dist/lib/signal-gatherer.d.ts +0 -1
  24. package/dist/lib/signal-gatherer.js +0 -1
  25. package/dist/login-cli.d.ts +0 -1
  26. package/dist/login-cli.js +0 -1
  27. package/dist/tools/browse-project.d.ts +0 -1
  28. package/dist/tools/browse-project.js +0 -1
  29. package/dist/tools/get-compiled-page.d.ts +0 -1
  30. package/dist/tools/get-compiled-page.js +0 -1
  31. package/dist/tools/get-full-content.d.ts +0 -1
  32. package/dist/tools/get-full-content.js +0 -1
  33. package/dist/tools/get-project-context.d.ts +0 -1
  34. package/dist/tools/get-project-context.js +0 -1
  35. package/dist/tools/get-recent-insights.d.ts +0 -1
  36. package/dist/tools/get-recent-insights.js +0 -1
  37. package/dist/tools/get-relevant-context.d.ts +0 -1
  38. package/dist/tools/get-relevant-context.js +0 -1
  39. package/dist/tools/retry-failed.d.ts +0 -1
  40. package/dist/tools/retry-failed.js +0 -1
  41. package/dist/tools/save-from-agent.d.ts +0 -1
  42. package/dist/tools/save-from-agent.js +0 -1
  43. package/dist/tools/search-knowledge.d.ts +0 -1
  44. package/dist/tools/search-knowledge.js +0 -1
  45. package/package.json +3 -2
  46. package/dist/auth.d.ts.map +0 -1
  47. package/dist/auth.js.map +0 -1
  48. package/dist/cli.d.ts.map +0 -1
  49. package/dist/cli.js.map +0 -1
  50. package/dist/config.d.ts.map +0 -1
  51. package/dist/config.js.map +0 -1
  52. package/dist/index.d.ts.map +0 -1
  53. package/dist/index.js.map +0 -1
  54. package/dist/lib/api-client.d.ts.map +0 -1
  55. package/dist/lib/api-client.js.map +0 -1
  56. package/dist/lib/auto-register.d.ts.map +0 -1
  57. package/dist/lib/auto-register.js.map +0 -1
  58. package/dist/lib/embedding.d.ts.map +0 -1
  59. package/dist/lib/embedding.js.map +0 -1
  60. package/dist/lib/feedback-tracker.d.ts.map +0 -1
  61. package/dist/lib/feedback-tracker.js.map +0 -1
  62. package/dist/lib/hint-engine.d.ts.map +0 -1
  63. package/dist/lib/hint-engine.js.map +0 -1
  64. package/dist/lib/profile-gatherer.d.ts.map +0 -1
  65. package/dist/lib/profile-gatherer.js.map +0 -1
  66. package/dist/lib/project-detector.d.ts.map +0 -1
  67. package/dist/lib/project-detector.js.map +0 -1
  68. package/dist/lib/session-state.d.ts.map +0 -1
  69. package/dist/lib/session-state.js.map +0 -1
  70. package/dist/lib/signal-fusion.d.ts.map +0 -1
  71. package/dist/lib/signal-fusion.js.map +0 -1
  72. package/dist/lib/signal-gatherer.d.ts.map +0 -1
  73. package/dist/lib/signal-gatherer.js.map +0 -1
  74. package/dist/lib/supabase.d.ts.map +0 -1
  75. package/dist/lib/supabase.js.map +0 -1
  76. package/dist/login-cli.d.ts.map +0 -1
  77. package/dist/login-cli.js.map +0 -1
  78. package/dist/tools/browse-project.d.ts.map +0 -1
  79. package/dist/tools/browse-project.js.map +0 -1
  80. package/dist/tools/get-compiled-page.d.ts.map +0 -1
  81. package/dist/tools/get-compiled-page.js.map +0 -1
  82. package/dist/tools/get-full-content.d.ts.map +0 -1
  83. package/dist/tools/get-full-content.js.map +0 -1
  84. package/dist/tools/get-project-context.d.ts.map +0 -1
  85. package/dist/tools/get-project-context.js.map +0 -1
  86. package/dist/tools/get-recent-insights.d.ts.map +0 -1
  87. package/dist/tools/get-recent-insights.js.map +0 -1
  88. package/dist/tools/get-relevant-context.d.ts.map +0 -1
  89. package/dist/tools/get-relevant-context.js.map +0 -1
  90. package/dist/tools/retry-failed.d.ts.map +0 -1
  91. package/dist/tools/retry-failed.js.map +0 -1
  92. package/dist/tools/save-from-agent.d.ts.map +0 -1
  93. package/dist/tools/save-from-agent.js.map +0 -1
  94. package/dist/tools/search-knowledge.d.ts.map +0 -1
  95. package/dist/tools/search-knowledge.js.map +0 -1
package/dist/auth.d.ts CHANGED
@@ -7,11 +7,21 @@ export declare function loadAuth(): Promise<{
7
7
  userId: string;
8
8
  }>;
9
9
  /**
10
- * Browser-based login flow opens browser for OTP auth, polls for completion.
10
+ * Terminal-first login — email + OTP, never leaves the terminal.
11
+ * Works for both new signups and existing users.
11
12
  */
12
- export declare function login(): Promise<void>;
13
+ export declare function login(): Promise<{
14
+ userId: string;
15
+ email: string;
16
+ }>;
17
+ /**
18
+ * Terminal-first login with invite code — for team join flows.
19
+ */
20
+ export declare function loginWithInvite(inviteCode: string): Promise<{
21
+ userId: string;
22
+ email: string;
23
+ }>;
13
24
  /**
14
25
  * Check if auth.json exists (user has logged in before).
15
26
  */
16
27
  export declare function hasAuth(): boolean;
17
- //# sourceMappingURL=auth.d.ts.map
package/dist/auth.js CHANGED
@@ -1,4 +1,4 @@
1
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from 'fs';
2
2
  import { execSync } from 'child_process';
3
3
  import { homedir } from 'os';
4
4
  import { join } from 'path';
@@ -27,8 +27,13 @@ function readAuthFile() {
27
27
  function writeAuthFile(auth) {
28
28
  const dir = join(homedir(), '.splicr');
29
29
  if (!existsSync(dir))
30
- mkdirSync(dir, { recursive: true });
31
- writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2));
30
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
31
+ writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2), { mode: 0o600 });
32
+ // Ensure permissions even if file already existed
33
+ try {
34
+ chmodSync(AUTH_FILE, 0o600);
35
+ }
36
+ catch { /* Windows doesn't support chmod */ }
32
37
  }
33
38
  /**
34
39
  * Load auth token. No refresh needed — token is permanent.
@@ -53,57 +58,119 @@ function openBrowser(url) {
53
58
  }
54
59
  }
55
60
  /**
56
- * Browser-based login flow opens browser for OTP auth, polls for completion.
61
+ * Terminal-first login — email + OTP, never leaves the terminal.
62
+ * Works for both new signups and existing users.
57
63
  */
58
64
  export async function login() {
59
- // Step 1: Create CLI link code
60
- const linkRes = await fetch(`${API_URL}/auth/cli-link`, {
61
- method: 'POST',
62
- headers: { 'Content-Type': 'application/json' },
63
- body: JSON.stringify({}),
64
- });
65
- if (!linkRes.ok) {
66
- console.error(' Failed to create auth link. Check your internet connection.');
67
- process.exit(1);
65
+ const rl = await createReadlineInterface();
66
+ try {
67
+ // Step 1: Get email
68
+ const email = await prompt(rl, ' Enter your email: ');
69
+ if (!email || !email.includes('@')) {
70
+ console.error(' Invalid email address.');
71
+ process.exit(1);
72
+ }
73
+ // Step 2: Send OTP
74
+ process.stderr.write(' Sending verification code...');
75
+ const sendRes = await fetch(`${API_URL}/auth/otp/send`, {
76
+ method: 'POST',
77
+ headers: { 'Content-Type': 'application/json', 'X-Splicr-Client': 'cli' },
78
+ body: JSON.stringify({ email }),
79
+ });
80
+ if (!sendRes.ok) {
81
+ const err = await sendRes.json().catch(() => ({}));
82
+ console.error(`\n ${err.error || 'Failed to send code. Check your email and try again.'}`);
83
+ process.exit(1);
84
+ }
85
+ console.error(' sent!');
86
+ // Step 3: Get OTP code
87
+ const code = await prompt(rl, ' Enter 6-digit code from your email: ');
88
+ if (!code || code.length !== 6) {
89
+ console.error(' Invalid code. Must be 6 digits.');
90
+ process.exit(1);
91
+ }
92
+ // Step 4: Verify OTP
93
+ process.stderr.write(' Verifying...');
94
+ const verifyRes = await fetch(`${API_URL}/auth/otp/verify`, {
95
+ method: 'POST',
96
+ headers: { 'Content-Type': 'application/json', 'X-Splicr-Client': 'cli' },
97
+ body: JSON.stringify({ email, code }),
98
+ });
99
+ if (!verifyRes.ok) {
100
+ const err = await verifyRes.json().catch(() => ({}));
101
+ console.error(`\n ${err.error || 'Verification failed.'}`);
102
+ process.exit(1);
103
+ }
104
+ const { data } = await verifyRes.json();
105
+ // Step 5: Save credentials
106
+ writeAuthFile({ token: data.token, user_id: data.user.id });
107
+ console.error(` authenticated as ${data.user.email}`);
108
+ return { userId: data.user.id, email: data.user.email };
68
109
  }
69
- const { data: { code } } = await linkRes.json();
70
- const authUrl = `${WEB_URL}/cli-auth?code=${code}`;
71
- // Step 2: Open browser
72
- console.error(` Opening browser to sign in...`);
73
- console.error(` If the browser didn't open, visit:\n ${authUrl}\n`);
74
- openBrowser(authUrl);
75
- // Step 3: Poll for completion (every 2s, up to 5 min)
76
- const maxAttempts = 150;
77
- for (let i = 0; i < maxAttempts; i++) {
78
- await new Promise(r => setTimeout(r, 2000));
79
- try {
80
- const pollRes = await fetch(`${API_URL}/auth/cli-link/${code}`);
81
- if (!pollRes.ok) {
82
- console.error('\n Auth link expired. Run setup again.');
83
- process.exit(1);
84
- }
85
- const pollBody = await pollRes.json();
86
- if (pollBody.data.status === 'complete') {
87
- const auth = {
88
- token: pollBody.data.token,
89
- user_id: pollBody.data.user.id,
90
- };
91
- writeAuthFile(auth);
92
- console.error(` Authenticated as ${pollBody.data.user.email}`);
93
- console.error(` Credentials saved to ${AUTH_FILE}`);
94
- return;
95
- }
96
- // Show dots for progress
97
- if (i > 0 && i % 5 === 0) {
98
- process.stderr.write('.');
99
- }
110
+ finally {
111
+ rl.close();
112
+ }
113
+ }
114
+ /**
115
+ * Terminal-first login with invite code — for team join flows.
116
+ */
117
+ export async function loginWithInvite(inviteCode) {
118
+ const rl = await createReadlineInterface();
119
+ try {
120
+ const email = await prompt(rl, ' Enter your email: ');
121
+ if (!email || !email.includes('@')) {
122
+ console.error(' Invalid email address.');
123
+ process.exit(1);
124
+ }
125
+ process.stderr.write(' Sending verification code...');
126
+ const sendRes = await fetch(`${API_URL}/auth/otp/send`, {
127
+ method: 'POST',
128
+ headers: { 'Content-Type': 'application/json', 'X-Splicr-Client': 'cli' },
129
+ body: JSON.stringify({ email, invite_code: inviteCode }),
130
+ });
131
+ if (!sendRes.ok) {
132
+ const err = await sendRes.json().catch(() => ({}));
133
+ console.error(`\n ${err.error || 'Failed to send code.'}`);
134
+ process.exit(1);
135
+ }
136
+ console.error(' sent!');
137
+ const code = await prompt(rl, ' Enter 6-digit code from your email: ');
138
+ if (!code || code.length !== 6) {
139
+ console.error(' Invalid code. Must be 6 digits.');
140
+ process.exit(1);
100
141
  }
101
- catch {
102
- // Network error keep polling
142
+ process.stderr.write(' Verifying...');
143
+ const verifyRes = await fetch(`${API_URL}/auth/otp/verify`, {
144
+ method: 'POST',
145
+ headers: { 'Content-Type': 'application/json', 'X-Splicr-Client': 'cli' },
146
+ body: JSON.stringify({ email, code }),
147
+ });
148
+ if (!verifyRes.ok) {
149
+ const err = await verifyRes.json().catch(() => ({}));
150
+ console.error(`\n ${err.error || 'Verification failed.'}`);
151
+ process.exit(1);
103
152
  }
153
+ const { data } = await verifyRes.json();
154
+ writeAuthFile({ token: data.token, user_id: data.user.id });
155
+ console.error(` authenticated as ${data.user.email}`);
156
+ return { userId: data.user.id, email: data.user.email };
104
157
  }
105
- console.error('\n Authentication timed out. Run `npx @splicr/mcp-server login` to try again.');
106
- process.exit(1);
158
+ finally {
159
+ rl.close();
160
+ }
161
+ }
162
+ // ===== readline helpers =====
163
+ import { createInterface } from 'readline';
164
+ function createReadlineInterface() {
165
+ return createInterface({
166
+ input: process.stdin,
167
+ output: process.stderr,
168
+ });
169
+ }
170
+ function prompt(rl, question) {
171
+ return new Promise((resolve) => {
172
+ rl.question(question, (answer) => resolve(answer.trim()));
173
+ });
107
174
  }
108
175
  /**
109
176
  * Check if auth.json exists (user has logged in before).
@@ -111,4 +178,3 @@ export async function login() {
111
178
  export function hasAuth() {
112
179
  return readAuthFile() !== null;
113
180
  }
114
- //# sourceMappingURL=auth.js.map
package/dist/cli.d.ts CHANGED
@@ -8,4 +8,3 @@
8
8
  * - "help" → print usage
9
9
  */
10
10
  export {};
11
- //# sourceMappingURL=cli.d.ts.map
package/dist/cli.js CHANGED
@@ -12,6 +12,10 @@ import { execSync } from 'child_process';
12
12
  import { homedir } from 'os';
13
13
  import { join } from 'path';
14
14
  const command = process.argv[2];
15
+ const subCommand = process.argv[3];
16
+ // Parse --join flag from any position
17
+ const joinIndex = process.argv.indexOf('--join');
18
+ const joinCode = joinIndex !== -1 ? process.argv[joinIndex + 1] : undefined;
15
19
  // Hook constants
16
20
  const SPLICR_HOOK_MARKER = '@splicr/mcp-server hook';
17
21
  const SPLICR_HOOK_CONFIG = {
@@ -172,6 +176,9 @@ async function main() {
172
176
  await login();
173
177
  break;
174
178
  }
179
+ case 'team':
180
+ await teamCommand();
181
+ break;
175
182
  case 'uninstall':
176
183
  case 'remove':
177
184
  await uninstall();
@@ -217,13 +224,33 @@ async function main() {
217
224
  }
218
225
  }
219
226
  async function setup() {
220
- const { login } = await import('./auth.js');
227
+ const hasJoin = !!joinCode;
228
+ const totalSteps = hasJoin ? 3 : 2;
221
229
  console.error('\n Splicr — route what you read to what you\'re building\n');
222
- // Step 1: Login
223
- console.error(' Step 1/2: Authenticate\n');
224
- await login();
225
- // Step 2: Detect and configure coding agents
226
- console.error('\n Step 2/2: Configure coding agents\n');
230
+ // Step 1: Authenticate in terminal (email + OTP)
231
+ console.error(` Step 1/${totalSteps}: Authenticate\n`);
232
+ const { hasAuth, login, loginWithInvite } = await import('./auth.js');
233
+ let authInfo;
234
+ if (hasAuth()) {
235
+ const { loadAuth } = await import('./auth.js');
236
+ const existing = await loadAuth();
237
+ console.error(` Already authenticated (${existing.userId.substring(0, 8)}...)`);
238
+ authInfo = { userId: existing.userId, email: '' };
239
+ }
240
+ else if (hasJoin) {
241
+ authInfo = await loginWithInvite(joinCode);
242
+ }
243
+ else {
244
+ authInfo = await login();
245
+ }
246
+ // Step 2 (optional): Join team
247
+ if (hasJoin) {
248
+ console.error(`\n Step 2/${totalSteps}: Join team\n`);
249
+ await joinTeam(joinCode);
250
+ }
251
+ // Step N: Detect and configure coding agents
252
+ const agentStep = hasJoin ? 3 : 2;
253
+ console.error(`\n Step ${agentStep}/${totalSteps}: Configure coding agents\n`);
227
254
  const detected = detectInstalledAgents();
228
255
  if (detected.length === 0) {
229
256
  console.error(' No coding agents detected. Add Splicr manually to your agent\'s MCP config:\n');
@@ -242,16 +269,13 @@ async function setup() {
242
269
  console.error('✗ failed (configure manually)');
243
270
  }
244
271
  }
245
- // Step 3: Inject CLAUDE.md instruction for reliable tool usage
272
+ // Inject instruction files + hooks
246
273
  injectClaudeMd();
247
- // Step 4: Inject Claude Code hook for 100% context injection
248
274
  injectClaudeHook();
249
275
  if (configured > 0) {
250
276
  console.error(`\n Done! Splicr is connected to ${configured} agent(s).`);
251
277
  console.error(' Start a new session in any agent to use it.');
252
278
  console.error(' Save articles from your phone or browser — they\'ll show up when you code.\n');
253
- console.error(' For manual setup or other agents:\n');
254
- printManualConfig();
255
279
  }
256
280
  else {
257
281
  console.error('\n Could not auto-configure any agents. Add manually:\n');
@@ -586,18 +610,26 @@ async function runStop() {
586
610
  process.exit(0);
587
611
  return;
588
612
  }
589
- // If agent already saved to Splicr, no need to nudge
590
- if (transcript.includes('save_from_agent') && transcript.includes('Saved to Splicr')) {
591
- process.exit(0);
592
- return;
593
- }
594
- // Count tool calls as a rough significance signal
613
+ // Count total tool calls as a rough significance signal
595
614
  const toolCalls = (transcript.match(/"tool_use"/g) || []).length;
596
615
  if (toolCalls < 5) {
597
616
  process.exit(0);
598
617
  return;
599
618
  }
600
- // Significant session, no savenudge the agent
619
+ // Check if agent saved to Splicr but only suppress if save was RECENT
620
+ // (i.e., no significant work happened after the last save)
621
+ const lastSaveIndex = transcript.lastIndexOf('Saved to Splicr');
622
+ if (lastSaveIndex !== -1) {
623
+ const afterSave = transcript.slice(lastSaveIndex);
624
+ const toolCallsAfterSave = (afterSave.match(/"tool_use"/g) || []).length;
625
+ // If fewer than 5 tool calls happened after the last save, don't nudge
626
+ if (toolCallsAfterSave < 5) {
627
+ process.exit(0);
628
+ return;
629
+ }
630
+ // 5+ tool calls after last save = significant new work, nudge again
631
+ }
632
+ // Significant session with no recent save — nudge the agent
601
633
  const output = JSON.stringify({
602
634
  decision: 'block',
603
635
  reason: 'SPLICR BACK-PRESSURE: This was a significant session (many tool calls). Before finishing, consider: did you make any decisions, discoveries, or workarounds worth saving? If yes, call save_from_agent with the learning and include the context field (agent, files, decision_type, durability). If nothing significant was learned, you may finish.',
@@ -901,6 +933,144 @@ function injectClaudeHook() {
901
933
  console.error(' • Claude Code hook... ✗ could not write settings.json');
902
934
  }
903
935
  }
936
+ // ===== Team commands =====
937
+ const API_URL = process.env.SPLICR_API_URL || 'https://api-production-d889.up.railway.app';
938
+ async function getAuthHeaders() {
939
+ const { loadAuth } = await import('./auth.js');
940
+ const auth = await loadAuth();
941
+ return {
942
+ 'Authorization': `Bearer ${auth.accessToken}`,
943
+ 'Content-Type': 'application/json',
944
+ };
945
+ }
946
+ async function joinTeam(inviteCode) {
947
+ const headers = await getAuthHeaders();
948
+ // Preview the team first
949
+ const previewRes = await fetch(`${API_URL}/teams/preview/${inviteCode}`);
950
+ if (!previewRes.ok) {
951
+ console.error(' Invalid invite code.');
952
+ process.exit(1);
953
+ }
954
+ const { data: preview } = await previewRes.json();
955
+ process.stderr.write(` Joining "${preview.name}" (${preview.member_count} members)...`);
956
+ const joinRes = await fetch(`${API_URL}/teams/join/${inviteCode}`, {
957
+ method: 'POST',
958
+ headers,
959
+ });
960
+ if (!joinRes.ok) {
961
+ const err = await joinRes.json().catch(() => ({}));
962
+ console.error(`\n ${err.error || 'Failed to join team.'}`);
963
+ process.exit(1);
964
+ }
965
+ const { data } = await joinRes.json();
966
+ console.error(` joined "${data.name}"!`);
967
+ }
968
+ async function teamCommand() {
969
+ const { hasAuth } = await import('./auth.js');
970
+ if (!hasAuth()) {
971
+ console.error('\n Not authenticated. Run `npx @splicr/mcp-server setup` first.\n');
972
+ process.exit(1);
973
+ }
974
+ switch (subCommand) {
975
+ case 'create': {
976
+ const name = process.argv.slice(4).join(' ');
977
+ if (!name) {
978
+ console.error('\n Usage: npx @splicr/mcp-server team create "My Team"\n');
979
+ process.exit(1);
980
+ }
981
+ const headers = await getAuthHeaders();
982
+ process.stderr.write(`\n Creating team "${name}"...`);
983
+ const res = await fetch(`${API_URL}/teams`, {
984
+ method: 'POST',
985
+ headers,
986
+ body: JSON.stringify({ name }),
987
+ });
988
+ if (!res.ok) {
989
+ const err = await res.json().catch(() => ({}));
990
+ console.error(`\n ${err.error || 'Failed to create team.'}`);
991
+ process.exit(1);
992
+ }
993
+ const { data } = await res.json();
994
+ console.error(' done!\n');
995
+ console.error(` Team: ${data.name}`);
996
+ console.error(` Invite code: ${data.invite_code}`);
997
+ console.error(` Invite link: https://splicr.dev/join/${data.invite_code}`);
998
+ console.error(`\n Share the link with teammates. They can join with:`);
999
+ console.error(` npx @splicr/mcp-server setup --join ${data.invite_code}\n`);
1000
+ break;
1001
+ }
1002
+ case 'list': {
1003
+ const headers = await getAuthHeaders();
1004
+ const res = await fetch(`${API_URL}/teams`, { headers });
1005
+ if (!res.ok) {
1006
+ console.error('\n Failed to load teams.\n');
1007
+ process.exit(1);
1008
+ }
1009
+ const { data: teams } = await res.json();
1010
+ if (!teams || teams.length === 0) {
1011
+ console.error('\n You\'re not on any teams yet.');
1012
+ console.error(' Create one: npx @splicr/mcp-server team create "My Team"\n');
1013
+ return;
1014
+ }
1015
+ console.error('\n Your teams:\n');
1016
+ for (const team of teams) {
1017
+ console.error(` • ${team.name} (${team.role})`);
1018
+ console.error(` Invite code: ${team.invite_code}`);
1019
+ console.error(` Invite link: https://splicr.dev/join/${team.invite_code}`);
1020
+ }
1021
+ console.error('');
1022
+ break;
1023
+ }
1024
+ case 'invite': {
1025
+ const headers = await getAuthHeaders();
1026
+ const res = await fetch(`${API_URL}/teams`, { headers });
1027
+ if (!res.ok) {
1028
+ console.error('\n Failed to load teams.\n');
1029
+ process.exit(1);
1030
+ }
1031
+ const { data: teams } = await res.json();
1032
+ if (!teams || teams.length === 0) {
1033
+ console.error('\n You\'re not on any teams. Create one first:');
1034
+ console.error(' npx @splicr/mcp-server team create "My Team"\n');
1035
+ return;
1036
+ }
1037
+ // Use the first team (most users will have one)
1038
+ const team = teams[0];
1039
+ const link = `https://splicr.dev/join/${team.invite_code}`;
1040
+ const setupCmd = `npx @splicr/mcp-server setup --join ${team.invite_code}`;
1041
+ console.error(`\n Team: ${team.name}\n`);
1042
+ console.error(` Invite link: ${link}`);
1043
+ console.error(` Terminal setup: ${setupCmd}`);
1044
+ console.error(`\n Share either with your teammates.\n`);
1045
+ break;
1046
+ }
1047
+ case 'join': {
1048
+ const code = process.argv[4];
1049
+ if (!code) {
1050
+ console.error('\n Usage: npx @splicr/mcp-server team join <invite-code>\n');
1051
+ process.exit(1);
1052
+ }
1053
+ console.error('');
1054
+ await joinTeam(code);
1055
+ console.error('');
1056
+ break;
1057
+ }
1058
+ default:
1059
+ console.error(`
1060
+ Splicr Teams
1061
+
1062
+ Commands:
1063
+ team create "Name" Create a new team
1064
+ team list List your teams
1065
+ team invite Show invite link for your team
1066
+ team join <code> Join a team by invite code
1067
+
1068
+ Or use setup --join:
1069
+ setup --join <code> Sign up + join team + configure agents (one command)
1070
+ `);
1071
+ break;
1072
+ }
1073
+ }
904
1074
  function printManualConfig() {
905
1075
  console.error(' Add this to your agent\'s MCP settings:\n');
906
1076
  console.error(' {');
@@ -914,28 +1084,32 @@ function printManualConfig() {
914
1084
  }
915
1085
  function printHelp() {
916
1086
  console.error(`
917
- Splicr MCP Server — route what you read to what you're building
1087
+ Splicr — route what you read to what you're building
1088
+
1089
+ Getting started:
1090
+ npx @splicr/mcp-server setup Sign up + configure all agents (one command)
1091
+ npx @splicr/mcp-server setup --join <code> Sign up + join team + configure agents
918
1092
 
919
- Usage:
920
- npx @splicr/mcp-server setup One-time setup: login + configure agents + hook
921
- npx @splicr/mcp-server login Re-authenticate with your Splicr account
922
- npx @splicr/mcp-server hook Context hook (used by Claude Code automatically)
923
- npx @splicr/mcp-server dashboard Open your knowledge dashboard in the browser
924
- npx @splicr/mcp-server uninstall Remove Splicr from all coding agents
925
- npx @splicr/mcp-server Start MCP server (used by coding agents)
1093
+ Commands:
1094
+ setup One-time setup: authenticate + configure agents + hooks
1095
+ login Re-authenticate
1096
+ team create "Name" Create a new team
1097
+ team list List your teams
1098
+ team invite Show invite link for your team
1099
+ team join <code> Join a team by invite code
1100
+ dashboard Open knowledge dashboard in browser
1101
+ uninstall Remove Splicr from all coding agents
926
1102
 
927
1103
  Supported agents (auto-detected):
928
1104
  Claude Code, Codex, Cursor, Cline, Antigravity
929
1105
 
930
1106
  Quick start:
931
- 1. Sign up at splicr.dev
932
- 2. Run: npx @splicr/mcp-server setup
933
- 3. Start saving articles from your phone or browser
934
- 4. Open any coding agent — your saves show up when relevant
1107
+ 1. Run: npx @splicr/mcp-server setup
1108
+ 2. Start saving articles from your phone or browser
1109
+ 3. Open any coding agent your saves show up when relevant
935
1110
  `);
936
1111
  }
937
1112
  main().catch(err => {
938
1113
  console.error(`Error: ${err.message}`);
939
1114
  process.exit(1);
940
1115
  });
941
- //# sourceMappingURL=cli.js.map
package/dist/config.d.ts CHANGED
@@ -2,4 +2,3 @@ export interface SplicrConfig {
2
2
  apiServerUrl: string;
3
3
  }
4
4
  export declare function loadConfig(): SplicrConfig;
5
- //# sourceMappingURL=config.d.ts.map
package/dist/config.js CHANGED
@@ -23,4 +23,3 @@ export function loadConfig() {
23
23
  // Default — production API
24
24
  return { apiServerUrl: 'https://api-production-d889.up.railway.app' };
25
25
  }
26
- //# sourceMappingURL=config.js.map
package/dist/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -98,4 +98,3 @@ server.connect(transport).then(() => {
98
98
  console.error('[Splicr MCP] Failed to start:', err);
99
99
  process.exit(1);
100
100
  });
101
- //# sourceMappingURL=index.js.map
@@ -112,4 +112,3 @@ export declare function getRelevantContext(params: {
112
112
  search_strategy: string;
113
113
  }>;
114
114
  export { API_URL };
115
- //# sourceMappingURL=api-client.d.ts.map
@@ -95,4 +95,3 @@ export async function getRelevantContext(params) {
95
95
  return { results: data.results ?? [], search_strategy: data.search_strategy ?? '' };
96
96
  }
97
97
  export { API_URL };
98
- //# sourceMappingURL=api-client.js.map
@@ -9,4 +9,3 @@ export declare function trackSearchResults(resultIds: string[], query: string, s
9
9
  * Fire-and-forget — never blocks the content fetch.
10
10
  */
11
11
  export declare function checkAndLogFeedback(captureId: string): void;
12
- //# sourceMappingURL=feedback-tracker.d.ts.map
@@ -37,4 +37,3 @@ export function checkAndLogFeedback(captureId) {
37
37
  source_tool: lastSearchTool,
38
38
  }).catch(() => { });
39
39
  }
40
- //# sourceMappingURL=feedback-tracker.js.map
@@ -6,4 +6,3 @@ export interface HintContext {
6
6
  topResultTitle?: string;
7
7
  }
8
8
  export declare function generateHints(ctx: HintContext): string;
9
- //# sourceMappingURL=hint-engine.d.ts.map
@@ -18,4 +18,3 @@ export function generateHints(ctx) {
18
18
  return '';
19
19
  return '\n\n---\n*Hints:*\n' + hints.map(h => `- ${h}`).join('\n');
20
20
  }
21
- //# sourceMappingURL=hint-engine.js.map
@@ -18,4 +18,3 @@ export interface ProjectProfileData {
18
18
  * Every operation is individually try/caught — one failure never blocks the rest.
19
19
  */
20
20
  export declare function gatherProjectProfile(cwd: string): ProjectProfileData;
21
- //# sourceMappingURL=profile-gatherer.d.ts.map
@@ -144,4 +144,3 @@ function detectTechStack(cwd) {
144
144
  techStack.push('rust');
145
145
  return techStack;
146
146
  }
147
- //# sourceMappingURL=profile-gatherer.js.map
@@ -9,4 +9,3 @@ export declare function detectProject(cwd: string): Promise<DetectedProject | nu
9
9
  export declare function getGitRemoteUrl(cwd: string): string | null;
10
10
  export declare function normalizeGitUrl(url: string): string;
11
11
  export {};
12
- //# sourceMappingURL=project-detector.d.ts.map
@@ -163,4 +163,3 @@ function detectTechStack(cwd) {
163
163
  techStack.push('rust');
164
164
  return techStack;
165
165
  }
166
- //# sourceMappingURL=project-detector.js.map
@@ -13,4 +13,3 @@ export declare function getStats(): {
13
13
  saves: number;
14
14
  contextServed: number;
15
15
  };
16
- //# sourceMappingURL=session-state.d.ts.map
@@ -42,4 +42,3 @@ export function getStats() {
42
42
  contextServed: contextServedIds.size,
43
43
  };
44
44
  }
45
- //# sourceMappingURL=session-state.js.map
@@ -31,4 +31,3 @@ export declare function parseBranchName(name: string): string | null;
31
31
  * ["src/routes/auth.ts", "src/middleware/rate-limit.ts"] → "auth routes rate-limit middleware"
32
32
  */
33
33
  export declare function extractConceptsFromPaths(files: string[]): string | null;
34
- //# sourceMappingURL=signal-fusion.d.ts.map
@@ -123,4 +123,3 @@ function cleanError(error) {
123
123
  function dedupeStrings(arr) {
124
124
  return [...new Set(arr.map(s => s.trim()).filter(Boolean))];
125
125
  }
126
- //# sourceMappingURL=signal-fusion.js.map
@@ -13,4 +13,3 @@ export interface EnvironmentSignals {
13
13
  * Target: < 1 second total.
14
14
  */
15
15
  export declare function gatherSignals(cwd: string): EnvironmentSignals;
16
- //# sourceMappingURL=signal-gatherer.d.ts.map
@@ -90,4 +90,3 @@ function detectProjectName(cwd) {
90
90
  }
91
91
  return cwd.replace(/\\/g, '/').split('/').pop() || null;
92
92
  }
93
- //# sourceMappingURL=signal-gatherer.js.map
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
- //# sourceMappingURL=login-cli.d.ts.map