@paigy/mcp 0.8.4 → 0.8.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/README.md +21 -0
- package/dist/{chunk-SLK7NHHQ.js → chunk-FDJFLJHR.js} +15 -1
- package/dist/index.js +1 -1
- package/dist/listen.js +1 -1
- package/dist/statusline.js +66 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -102,6 +102,27 @@ Then pair: `npx -p @paigy/mcp@latest paigy-mcp-onboard`.
|
|
|
102
102
|
|
|
103
103
|
- `PAIGY_BACKEND_URL` — the Paigy API base (defaults to the hosted backend).
|
|
104
104
|
|
|
105
|
+
## Statusline (Claude Code)
|
|
106
|
+
|
|
107
|
+
`paigy-statusline` prints a one-line connection status — the account's session
|
|
108
|
+
mode and whether a phone is paired — for Claude Code's status bar:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
paigy: all calls · phone ✓
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Enable it in `~/.claude/settings.json`:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
"statusLine": { "type": "command", "command": "npx -y @paigy/mcp@latest paigy-statusline" }
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
It reads `GET /api/status` with the pairing token and caches the result in
|
|
121
|
+
`~/.paigy/status.json` for 60 seconds, so the bar's constant refreshes never
|
|
122
|
+
hammer the API; when offline it shows the last known state. `paigy: unpaired`
|
|
123
|
+
means there's no token (or the pairing was revoked) — run `/paigy-onboard` to
|
|
124
|
+
pair; `paigy: …` means the status isn't known yet (first run while offline).
|
|
125
|
+
|
|
105
126
|
## Publishing (maintainers)
|
|
106
127
|
|
|
107
128
|
Tool input schemas are generated from zod in `src/schema.ts` as draft-2020-12 JSON
|
|
@@ -186,7 +186,14 @@ var UserSettingsSchema = z.object({
|
|
|
186
186
|
autoCallback: z.boolean(),
|
|
187
187
|
/** Opt-in (default false) to using your content to improve Paigy and train models. */
|
|
188
188
|
improveConsent: z.boolean(),
|
|
189
|
-
missedCall: MissedCallSchema.default("backoff_standard")
|
|
189
|
+
missedCall: MissedCallSchema.default("backoff_standard"),
|
|
190
|
+
/** Where voice audio is processed. 'hosted' (default) = Paigy's voice services
|
|
191
|
+
* (ElevenLabs TTS, faster-whisper STT, the call bot); 'on_device' = the phone
|
|
192
|
+
* synthesizes and transcribes locally — no audio or spoken text leaves it.
|
|
193
|
+
* Optional, NOT defaulted: a stale client PATCHing the full settings object
|
|
194
|
+
* must not silently reset this privacy choice. Absent = leave unchanged on
|
|
195
|
+
* write, 'hosted' on read (see store.ts). */
|
|
196
|
+
voiceMode: z.enum(["hosted", "on_device"]).optional()
|
|
190
197
|
});
|
|
191
198
|
var HistoryItemSchema = z.object({
|
|
192
199
|
id: z.string(),
|
|
@@ -237,6 +244,13 @@ var DeliveryConfigSchema = z.object({
|
|
|
237
244
|
* back to its own PAIGY_SUPABASE_URL / PAIGY_SUPABASE_ANON_KEY env. */
|
|
238
245
|
realtime: z.object({ url: z.string(), anonKey: z.string() }).nullable()
|
|
239
246
|
});
|
|
247
|
+
var StatusSchema = z.object({
|
|
248
|
+
agent: z.string(),
|
|
249
|
+
nickname: z.string(),
|
|
250
|
+
sessionMode: z.enum(["default", "all_calls", "silent"]),
|
|
251
|
+
/** A phone is registered for push/ring (any push token on the account). */
|
|
252
|
+
phone: z.boolean()
|
|
253
|
+
});
|
|
240
254
|
var WakeNudgeSchema = z.object({
|
|
241
255
|
kind: z.enum(["reply", "request", "callback"]),
|
|
242
256
|
notificationId: z.string().optional(),
|
package/dist/index.js
CHANGED
package/dist/listen.js
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
readToken
|
|
4
|
+
} from "./chunk-AILC3H3U.js";
|
|
5
|
+
import {
|
|
6
|
+
BACKEND_URL
|
|
7
|
+
} from "./chunk-GU7C5H6L.js";
|
|
8
|
+
|
|
9
|
+
// src/statusline.ts
|
|
10
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
var DIR = join(homedir(), ".paigy");
|
|
14
|
+
var CACHE = join(DIR, "status.json");
|
|
15
|
+
var TTL_MS = 6e4;
|
|
16
|
+
var MODE_LABEL = {
|
|
17
|
+
default: "default",
|
|
18
|
+
all_calls: "all calls",
|
|
19
|
+
silent: "silent"
|
|
20
|
+
};
|
|
21
|
+
function render(status) {
|
|
22
|
+
if (!status) return "paigy: unpaired";
|
|
23
|
+
return `paigy: ${MODE_LABEL[status.sessionMode]} \xB7 ${status.phone ? "phone \u2713" : "no phone"}`;
|
|
24
|
+
}
|
|
25
|
+
function readCache() {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(readFileSync(CACHE, "utf8"));
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function fetchStatus(token) {
|
|
33
|
+
const res = await fetch(`${BACKEND_URL}/api/status`, {
|
|
34
|
+
headers: { authorization: `Bearer ${token}` },
|
|
35
|
+
signal: AbortSignal.timeout(2e3)
|
|
36
|
+
// a statusline must render fast or not at all
|
|
37
|
+
});
|
|
38
|
+
if (res.status === 401) return null;
|
|
39
|
+
if (res.status === 404) {
|
|
40
|
+
if ((await res.text()).includes("not_found")) return null;
|
|
41
|
+
throw new Error("status 404");
|
|
42
|
+
}
|
|
43
|
+
if (!res.ok) throw new Error(`status ${res.status}`);
|
|
44
|
+
return await res.json();
|
|
45
|
+
}
|
|
46
|
+
async function main() {
|
|
47
|
+
const token = readToken();
|
|
48
|
+
if (!token) return render(null);
|
|
49
|
+
const cached = readCache();
|
|
50
|
+
if (cached && Date.now() - cached.at < TTL_MS) return render(cached.status);
|
|
51
|
+
try {
|
|
52
|
+
const status = await fetchStatus(token);
|
|
53
|
+
mkdirSync(DIR, { recursive: true });
|
|
54
|
+
writeFileSync(CACHE, JSON.stringify({ at: Date.now(), status }));
|
|
55
|
+
return render(status);
|
|
56
|
+
} catch {
|
|
57
|
+
return cached ? render(cached.status) : "paigy: \u2026";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/^file:\/\//, ""))) {
|
|
61
|
+
void main().then((line) => console.log(line));
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
main,
|
|
65
|
+
render
|
|
66
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paigy/mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "Paigy MCP server — a voice inbox for your AI agents. Lets an agent notify a user and await their reply.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"mcp": "./dist/index.js",
|
|
9
9
|
"paigy-mcp": "./dist/index.js",
|
|
10
10
|
"paigy-mcp-onboard": "./dist/onboard.js",
|
|
11
|
-
"paigy-listen": "./dist/listen.js"
|
|
11
|
+
"paigy-listen": "./dist/listen.js",
|
|
12
|
+
"paigy-statusline": "./dist/statusline.js"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"dist"
|
|
@@ -35,8 +36,8 @@
|
|
|
35
36
|
"@paigy/schema": "0.0.0"
|
|
36
37
|
},
|
|
37
38
|
"scripts": {
|
|
38
|
-
"build": "tsup src/index.ts src/onboard.ts src/listen.ts --format esm --clean",
|
|
39
|
-
"dev": "tsup src/index.ts src/onboard.ts src/listen.ts --format esm --watch",
|
|
39
|
+
"build": "tsup src/index.ts src/onboard.ts src/listen.ts src/statusline.ts --format esm --clean",
|
|
40
|
+
"dev": "tsup src/index.ts src/onboard.ts src/listen.ts src/statusline.ts --format esm --watch",
|
|
40
41
|
"typecheck": "tsc --noEmit",
|
|
41
42
|
"test": "vitest run"
|
|
42
43
|
}
|