@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.
- package/dist/auth.d.ts +13 -3
- package/dist/auth.js +115 -49
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +204 -30
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/lib/api-client.d.ts +0 -1
- package/dist/lib/api-client.js +0 -1
- package/dist/lib/feedback-tracker.d.ts +0 -1
- package/dist/lib/feedback-tracker.js +0 -1
- package/dist/lib/hint-engine.d.ts +0 -1
- package/dist/lib/hint-engine.js +0 -1
- package/dist/lib/profile-gatherer.d.ts +0 -1
- package/dist/lib/profile-gatherer.js +0 -1
- package/dist/lib/project-detector.d.ts +0 -1
- package/dist/lib/project-detector.js +0 -1
- package/dist/lib/session-state.d.ts +0 -1
- package/dist/lib/session-state.js +0 -1
- package/dist/lib/signal-fusion.d.ts +0 -1
- package/dist/lib/signal-fusion.js +0 -1
- package/dist/lib/signal-gatherer.d.ts +0 -1
- package/dist/lib/signal-gatherer.js +0 -1
- package/dist/login-cli.d.ts +0 -1
- package/dist/login-cli.js +0 -1
- package/dist/tools/browse-project.d.ts +0 -1
- package/dist/tools/browse-project.js +0 -1
- package/dist/tools/get-compiled-page.d.ts +0 -1
- package/dist/tools/get-compiled-page.js +0 -1
- package/dist/tools/get-full-content.d.ts +0 -1
- package/dist/tools/get-full-content.js +0 -1
- package/dist/tools/get-project-context.d.ts +0 -1
- package/dist/tools/get-project-context.js +0 -1
- package/dist/tools/get-recent-insights.d.ts +0 -1
- package/dist/tools/get-recent-insights.js +0 -1
- package/dist/tools/get-relevant-context.d.ts +0 -1
- package/dist/tools/get-relevant-context.js +0 -1
- package/dist/tools/retry-failed.d.ts +0 -1
- package/dist/tools/retry-failed.js +0 -1
- package/dist/tools/save-from-agent.d.ts +0 -1
- package/dist/tools/save-from-agent.js +0 -1
- package/dist/tools/search-knowledge.d.ts +0 -1
- package/dist/tools/search-knowledge.js +0 -1
- package/package.json +3 -2
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/api-client.d.ts.map +0 -1
- package/dist/lib/api-client.js.map +0 -1
- package/dist/lib/auto-register.d.ts.map +0 -1
- package/dist/lib/auto-register.js.map +0 -1
- package/dist/lib/embedding.d.ts.map +0 -1
- package/dist/lib/embedding.js.map +0 -1
- package/dist/lib/feedback-tracker.d.ts.map +0 -1
- package/dist/lib/feedback-tracker.js.map +0 -1
- package/dist/lib/hint-engine.d.ts.map +0 -1
- package/dist/lib/hint-engine.js.map +0 -1
- package/dist/lib/profile-gatherer.d.ts.map +0 -1
- package/dist/lib/profile-gatherer.js.map +0 -1
- package/dist/lib/project-detector.d.ts.map +0 -1
- package/dist/lib/project-detector.js.map +0 -1
- package/dist/lib/session-state.d.ts.map +0 -1
- package/dist/lib/session-state.js.map +0 -1
- package/dist/lib/signal-fusion.d.ts.map +0 -1
- package/dist/lib/signal-fusion.js.map +0 -1
- package/dist/lib/signal-gatherer.d.ts.map +0 -1
- package/dist/lib/signal-gatherer.js.map +0 -1
- package/dist/lib/supabase.d.ts.map +0 -1
- package/dist/lib/supabase.js.map +0 -1
- package/dist/login-cli.d.ts.map +0 -1
- package/dist/login-cli.js.map +0 -1
- package/dist/tools/browse-project.d.ts.map +0 -1
- package/dist/tools/browse-project.js.map +0 -1
- package/dist/tools/get-compiled-page.d.ts.map +0 -1
- package/dist/tools/get-compiled-page.js.map +0 -1
- package/dist/tools/get-full-content.d.ts.map +0 -1
- package/dist/tools/get-full-content.js.map +0 -1
- package/dist/tools/get-project-context.d.ts.map +0 -1
- package/dist/tools/get-project-context.js.map +0 -1
- package/dist/tools/get-recent-insights.d.ts.map +0 -1
- package/dist/tools/get-recent-insights.js.map +0 -1
- package/dist/tools/get-relevant-context.d.ts.map +0 -1
- package/dist/tools/get-relevant-context.js.map +0 -1
- package/dist/tools/retry-failed.d.ts.map +0 -1
- package/dist/tools/retry-failed.js.map +0 -1
- package/dist/tools/save-from-agent.d.ts.map +0 -1
- package/dist/tools/save-from-agent.js.map +0 -1
- package/dist/tools/search-knowledge.d.ts.map +0 -1
- 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
|
-
*
|
|
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<
|
|
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
|
-
*
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
102
|
-
|
|
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
|
-
|
|
106
|
-
|
|
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
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
|
|
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:
|
|
223
|
-
console.error(
|
|
224
|
-
await
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
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.
|
|
932
|
-
2.
|
|
933
|
-
3.
|
|
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
package/dist/config.js
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/lib/api-client.d.ts
CHANGED
package/dist/lib/api-client.js
CHANGED
package/dist/lib/hint-engine.js
CHANGED
|
@@ -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
|
|
@@ -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
|
package/dist/login-cli.d.ts
CHANGED