@paigy/mcp 0.38.0 → 0.40.1

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.
@@ -10,7 +10,7 @@ import {
10
10
  saveToken,
11
11
  sleep,
12
12
  startE2ee
13
- } from "./chunk-PPACGOTU.js";
13
+ } from "./chunk-4UZAPBKK.js";
14
14
 
15
15
  // src/identity.ts
16
16
  var CLIENT_LABELS = {
@@ -0,0 +1,224 @@
1
+ import {
2
+ AGENT_TOOLS,
3
+ mcpInputSchema,
4
+ serverInstructions
5
+ } from "./chunk-3QUIB42M.js";
6
+ import {
7
+ AGENT_NAME
8
+ } from "./chunk-4UZAPBKK.js";
9
+
10
+ // src/toolset.ts
11
+ var ONBOARD_DESCRIPTION = "Get this agent talking to Paigy \u2014 call it FIRST, before contact, and any time you're unsure who you are. One call, and it does whatever the situation needs: NOT SET UP \u2192 hatches an identity instantly if this machine holds a device credential (the user ran the Paigy desktop app or harness), otherwise starts the code ceremony; ALREADY SET UP \u2192 returns your current identity and offers the two things left to decide, renaming it or unpairing; TOKEN NO LONGER VALID \u2192 says so, then re-pairs. Pass { name, voice } to choose who you are when hatching, or to RENAME yourself when already set up (voices: rachel, george, jessica, brian, lily). Safe to call any time: idempotent, and it never writes settings \u2014 the tool-allowlist state it reports is read-only. If it returns a `user_code`, print it to the user immediately and call onboard again with the `device_code`. If it returns `enable_command`, PRINT that command for the user to run \u2014 you cannot apply it yourself (it writes your own permission allowlist, which hosts block as privilege escalation), so print it, don't wait for it, and carry on.";
12
+ var SERVER_INSTRUCTIONS = serverInstructions({ waits: true });
13
+
14
+ // src/tools.ts
15
+ import { z } from "zod";
16
+ var OnboardSchema = z.object({
17
+ name: z.string().max(60).optional(),
18
+ voice: z.string().max(40).optional(),
19
+ /** Continue a code ceremony already in flight — same meaning as `pair`'s. */
20
+ device_code: z.string().optional(),
21
+ /** Which allowlist to REPORT on (never written by `start`). */
22
+ scope: z.enum(["user", "project"]).optional()
23
+ });
24
+ var PairSchema = z.object({
25
+ device_code: z.string().optional().describe("Omit to start pairing (returns an approval link to show the user). Pass the device_code from that first call to finish, once the user has approved."),
26
+ name: z.string().min(1).max(60).optional().describe("Hatch path only: the name you choose for this identity. Pick your own \u2014 ONE or TWO words, the way you'd introduce yourself on a call (it is spoken aloud and shown in lists). 'Piper', 'Blue Heron' \u2014 never a sentence or a task description."),
27
+ voice: z.string().optional().describe("Hatch path only: your voice on calls \u2014 one of rachel, george, jessica, brian, lily.")
28
+ });
29
+ var IDENTITY_TOOLS = [
30
+ {
31
+ // ONE rail for starting a session (#875). `pair`, the `paigy-mcp-onboard` CLI and
32
+ // `enable_tools` were three doors into one flow, and "onboard" was the word people
33
+ // reached for attached to the tool that did the least. It's the door now.
34
+ name: "onboard",
35
+ description: ONBOARD_DESCRIPTION,
36
+ inputSchema: mcpInputSchema(OnboardSchema)
37
+ },
38
+ {
39
+ name: "pair",
40
+ description: "Pair this agent with the user's Paigy account (one-time) \u2014 required before contact work. FAST PATH: if this machine already holds a device credential (the user ran the Paigy desktop harness or app), calling pair hatches a fresh identity INSTANTLY \u2014 no code, no approval. Pass { name, voice } to choose who you are (pick your own; voices: rachel, george, jessica, brian, lily). Only when no device credential exists does the code ceremony below run. It does NOT open a browser; the user enters the code in the Paigy app (or scans `qr`). Step 1: call with NO args \u2014 returns { user_code, device_code, qr, user_message } AND starts polling for approval in the background. REQUIRED: You MUST immediately print the `user_message` (the bare code) as a text message to the user, AND in that same turn call step 2 (pair with the device_code). This ensures the user sees the code in chat while the tool blocks/polls in the background for approval. Step 2: call with that device_code to collect the result. Because approval is already being polled in the background, this returns the moment the user approves; on { status:'pending' } just call again to keep waiting; on { status:'awaiting_confirmation' } (E2EE) show the bare `user_message` verify code and call again to finish. The leading text block of every result states the code plainly, so it shows even if you emit no prose. On { status:'paired' } ALWAYS follow the `enable_prompt` \u2014 PRINT the returned `enable_command` so the user can allowlist Paigy's tools and notify/await stop prompting each time. Printing is the whole job: that command writes your own permission allowlist, so you must not run it and a host will block you if you try.",
41
+ inputSchema: mcpInputSchema(PairSchema)
42
+ },
43
+ {
44
+ name: "unpair",
45
+ description: "Log out / unpair this agent from the user's Paigy account: revokes the token server-side (it stops working everywhere) and deletes the local ~/.paigy/token.json. Takes no arguments. After this, contact won't work until the user pairs again with the pair tool.",
46
+ inputSchema: mcpInputSchema(z.object({}))
47
+ }
48
+ ];
49
+ var TOOLS = [...AGENT_TOOLS, ...IDENTITY_TOOLS];
50
+ var TOOL_NAMES = TOOLS.map((t) => t.name);
51
+ var HIDDEN_ALIASES = [];
52
+
53
+ // src/clients.ts
54
+ import { execFile } from "child_process";
55
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
56
+ import { homedir, platform } from "os";
57
+ import { join, dirname } from "path";
58
+ function openBrowser(url) {
59
+ const cmd = platform() === "darwin" ? "open" : platform() === "win32" ? "cmd" : "xdg-open";
60
+ const args = platform() === "win32" ? ["/c", "start", url] : [url];
61
+ execFile(cmd, args, () => {
62
+ });
63
+ }
64
+ function withPaigyMcpJson(existing, agent) {
65
+ let config = {};
66
+ if (existing) {
67
+ try {
68
+ config = JSON.parse(existing);
69
+ } catch {
70
+ return null;
71
+ }
72
+ }
73
+ config.mcpServers = {
74
+ ...config.mcpServers ?? {},
75
+ paigy: { command: "npx", args: ["-y", "@paigy/mcp@latest"], env: { PAIGY_AGENT: agent } }
76
+ };
77
+ return JSON.stringify(config, null, 2);
78
+ }
79
+ function withPaigyMcpToml(existing, agent) {
80
+ if (existing.includes("[mcp_servers.paigy]")) return null;
81
+ const entry = [
82
+ "",
83
+ "[mcp_servers.paigy]",
84
+ 'command = "npx"',
85
+ 'args = ["-y", "@paigy/mcp@latest"]',
86
+ `env = { PAIGY_AGENT = "${agent}" }`,
87
+ ""
88
+ ].join("\n");
89
+ return existing + entry;
90
+ }
91
+ function autoConfigureClients(skip = AGENT_NAME) {
92
+ const home = homedir();
93
+ const registered = [];
94
+ if (skip !== "antigravity") {
95
+ const antigravityConfigs = [
96
+ join(home, ".gemini", "config", "mcp_config.json"),
97
+ join(home, ".gemini", "antigravity-cli", "mcp_config.json")
98
+ ];
99
+ for (const path of antigravityConfigs) {
100
+ try {
101
+ if (!existsSync(dirname(path))) continue;
102
+ const existing = existsSync(path) ? readFileSync(path, "utf8") : null;
103
+ const updated = withPaigyMcpJson(existing, "antigravity");
104
+ if (updated === null) continue;
105
+ writeFileSync(path, updated);
106
+ registered.push(`Google Antigravity (${path})`);
107
+ } catch {
108
+ }
109
+ }
110
+ }
111
+ if (skip !== "codex") {
112
+ const codexConfig = join(home, ".codex", "config.toml");
113
+ try {
114
+ if (existsSync(dirname(codexConfig))) {
115
+ const existing = existsSync(codexConfig) ? readFileSync(codexConfig, "utf8") : "";
116
+ const updated = withPaigyMcpToml(existing, "codex");
117
+ if (updated !== null) {
118
+ writeFileSync(codexConfig, updated);
119
+ registered.push(`OpenAI Codex (${codexConfig})`);
120
+ }
121
+ }
122
+ } catch {
123
+ }
124
+ }
125
+ return registered;
126
+ }
127
+ function claudeInstallHint(skip = AGENT_NAME) {
128
+ if (skip.startsWith("claude")) return null;
129
+ const claudeDir = join(homedir(), ".claude");
130
+ if (!existsSync(claudeDir)) return null;
131
+ try {
132
+ const registry = join(claudeDir, "plugins", "installed_plugins.json");
133
+ if (existsSync(registry) && readFileSync(registry, "utf8").includes('"paigy@')) return null;
134
+ } catch {
135
+ }
136
+ return "Claude Code detected \u2014 to add Paigy there, run /plugin marketplace add paigy-ai/mcp then /plugin install paigy (pairing carries over; no need to pair again). Note: If you run this inside a live session, type /reload-plugins afterward so the agent connects to the new tools.";
137
+ }
138
+ var ENABLE_COMMAND = "npx -y -p @paigy/mcp@latest paigy-enable-tools";
139
+ var PROMPTS_ON_PURPOSE = /* @__PURE__ */ new Set(["pair", "unpair"]);
140
+ var PAIGY_TOOL_IDS = [
141
+ ...TOOL_NAMES.filter((n) => !PROMPTS_ON_PURPOSE.has(n)),
142
+ ...HIDDEN_ALIASES
143
+ ].map((n) => `mcp__paigy__${n}`);
144
+ function withPaigyAllowlist(existing, tools) {
145
+ let config = {};
146
+ if (existing) {
147
+ try {
148
+ config = JSON.parse(existing);
149
+ } catch {
150
+ return null;
151
+ }
152
+ }
153
+ const permissions = config.permissions && typeof config.permissions === "object" ? config.permissions : {};
154
+ const allow = Array.isArray(permissions.allow) ? [...permissions.allow] : [];
155
+ for (const t of tools) if (!allow.includes(t)) allow.push(t);
156
+ config.permissions = { ...permissions, allow };
157
+ return JSON.stringify(config, null, 2);
158
+ }
159
+ function settingsPathFor(scope, cwd) {
160
+ return scope === "project" ? join(cwd, ".claude", "settings.json") : join(homedir(), ".claude", "settings.json");
161
+ }
162
+ function paigyToolsAllowlisted(scope = "user", cwd = process.cwd()) {
163
+ try {
164
+ const path = settingsPathFor(scope, cwd);
165
+ if (!path || !existsSync(path)) return false;
166
+ const config = JSON.parse(readFileSync(path, "utf8"));
167
+ const allow = Array.isArray(config.permissions?.allow) ? config.permissions.allow : [];
168
+ return PAIGY_TOOL_IDS.every((t) => allow.includes(t));
169
+ } catch {
170
+ return false;
171
+ }
172
+ }
173
+ function enablePaigyTools(scope = "user", cwd = process.cwd()) {
174
+ if (scope === "user" && !existsSync(join(homedir(), ".claude"))) {
175
+ return {
176
+ ok: false,
177
+ reason: `No ~/.claude on this machine \u2014 the hosting tool uses its own permission allowlist. Add these ids there by hand: ${PAIGY_TOOL_IDS.join(", ")}.`
178
+ };
179
+ }
180
+ const path = settingsPathFor(scope, cwd);
181
+ let existing = null;
182
+ try {
183
+ existing = existsSync(path) ? readFileSync(path, "utf8") : null;
184
+ } catch {
185
+ existing = null;
186
+ }
187
+ let prevAllow = [];
188
+ if (existing) {
189
+ try {
190
+ const parsed = JSON.parse(existing);
191
+ if (Array.isArray(parsed.permissions?.allow)) prevAllow = parsed.permissions.allow;
192
+ } catch {
193
+ return { ok: false, reason: `${path} didn't parse as JSON \u2014 not overwriting it. Add the ids by hand.` };
194
+ }
195
+ }
196
+ const updated = withPaigyAllowlist(existing, PAIGY_TOOL_IDS);
197
+ if (updated === null) return { ok: false, reason: `${path} didn't parse as JSON \u2014 not overwriting it. Add the ids by hand.` };
198
+ try {
199
+ mkdirSync(dirname(path), { recursive: true });
200
+ writeFileSync(path, updated + "\n");
201
+ } catch (e) {
202
+ return { ok: false, reason: `Couldn't write ${path}: ${e.message}` };
203
+ }
204
+ return {
205
+ ok: true,
206
+ path,
207
+ added: PAIGY_TOOL_IDS.filter((t) => !prevAllow.includes(t)),
208
+ already: PAIGY_TOOL_IDS.filter((t) => prevAllow.includes(t))
209
+ };
210
+ }
211
+
212
+ export {
213
+ SERVER_INSTRUCTIONS,
214
+ OnboardSchema,
215
+ PairSchema,
216
+ TOOLS,
217
+ openBrowser,
218
+ autoConfigureClients,
219
+ claudeInstallHint,
220
+ ENABLE_COMMAND,
221
+ PAIGY_TOOL_IDS,
222
+ paigyToolsAllowlisted,
223
+ enablePaigyTools
224
+ };
package/dist/enable.js CHANGED
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  PAIGY_TOOL_IDS,
4
4
  enablePaigyTools
5
- } from "./chunk-7IGGSB3H.js";
6
- import "./chunk-KE63GZEQ.js";
7
- import "./chunk-PPACGOTU.js";
5
+ } from "./chunk-TLASZUJD.js";
6
+ import "./chunk-3QUIB42M.js";
7
+ import "./chunk-4UZAPBKK.js";
8
8
 
9
9
  // src/enable.ts
10
10
  function main() {
package/dist/index.js CHANGED
@@ -1,74 +1,44 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- awaitMessage,
4
- contactMessage
5
- } from "./chunk-UG2FARVV.js";
6
2
  import {
7
3
  clearPairing,
8
4
  joinBackgroundPair,
9
5
  resolvePairing,
10
6
  startPairing,
11
7
  suggestedAgentName
12
- } from "./chunk-4UEL7Y5U.js";
8
+ } from "./chunk-CXABA27N.js";
13
9
  import {
14
- AnswerCallerQuestionSchema,
15
- AwaitReplySchema,
16
- ClaimGoalSchema,
17
10
  ENABLE_COMMAND,
18
- GetThreadSchema,
19
11
  OnboardSchema,
20
12
  PAIGY_TOOL_IDS,
21
13
  PairSchema,
22
14
  SERVER_INSTRUCTIONS,
23
- SearchThreadsSchema,
24
- SetTaskStateToolSchema,
25
15
  TOOLS,
26
- UpdateGoalToolSchema,
27
16
  autoConfigureClients,
28
17
  claudeInstallHint,
29
18
  paigyToolsAllowlisted
30
- } from "./chunk-7IGGSB3H.js";
31
- import {
32
- CreateGoalSchema,
33
- HandoffSchema
34
- } from "./chunk-KE63GZEQ.js";
19
+ } from "./chunk-TLASZUJD.js";
20
+ import "./chunk-3QUIB42M.js";
35
21
  import {
36
22
  clearSurface,
37
23
  writeSurface
38
24
  } from "./chunk-3SVNPJPN.js";
39
25
  import {
40
26
  AGENT_NAME,
41
- NotifyRequestSchema,
42
- ScheduleCallbackSchema,
43
- SetWorkStateSchema,
44
27
  UnpairedError,
45
- answerCallerQuestion,
46
- awaitReply2,
47
- checkReplies,
48
- claimGoal,
49
- contactParentId,
50
- createGoal,
51
28
  deleteKeyFile,
52
29
  deleteToken,
53
- getThread,
54
- handoff,
55
30
  hatch,
56
31
  heartbeat,
57
32
  listSlots,
58
33
  overrideToken,
59
34
  readToken,
60
35
  revokeToken,
36
+ runTool,
61
37
  saveToken,
62
- scheduleCallback,
63
- searchThreads,
64
38
  setIdentity,
65
- setTaskState,
66
- setWorkState,
67
39
  slotName,
68
- submitNotification,
69
- updateGoal,
70
40
  whoAmI
71
- } from "./chunk-PPACGOTU.js";
41
+ } from "./chunk-4UZAPBKK.js";
72
42
 
73
43
  // src/index.ts
74
44
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -77,36 +47,8 @@ import {
77
47
  CallToolRequestSchema,
78
48
  ListToolsRequestSchema
79
49
  } from "@modelcontextprotocol/sdk/types.js";
80
- import { execSync } from "child_process";
81
50
  import qrcode from "qrcode-generator";
82
51
  var JOIN_CAP_MS = 45e3;
83
- function fixAndRetry(err) {
84
- const msg = String(err?.message ?? err);
85
- const m = msg.match(/^notify failed: 422 (\{[\s\S]*\})$/);
86
- if (!m) return null;
87
- try {
88
- const body = JSON.parse(m[1]);
89
- return body.error === "fix_and_retry" ? { error: "fix_and_retry", problems: body.problems ?? [] } : null;
90
- } catch {
91
- return null;
92
- }
93
- }
94
- function detectGit() {
95
- const run = (cmd) => {
96
- try {
97
- return execSync(cmd, { stdio: ["ignore", "pipe", "ignore"], encoding: "utf8" }).trim();
98
- } catch {
99
- return "";
100
- }
101
- };
102
- const remote = run("git remote get-url origin");
103
- const match = remote.match(/[:/]([^/:]+\/[^/]+?)(?:\.git)?$/);
104
- const branch = run("git rev-parse --abbrev-ref HEAD");
105
- return {
106
- repo: match ? match[1] : void 0,
107
- branch: branch && branch !== "HEAD" ? branch : void 0
108
- };
109
- }
110
52
  function pairedResult(token, sas, note, e2ee) {
111
53
  clearSurface();
112
54
  const base = {
@@ -379,96 +321,13 @@ async function handleTool(request, signal) {
379
321
  }]
380
322
  };
381
323
  }
382
- // `contact` (#575) is the one LISTED name; `notify` (#496) and `notify_user`
383
- // (the original) are HIDDEN aliases — unlisted but accepted, so stale prompts,
384
- // hooks, and cached 0.24 servers' habits keep working. Same handler, same wire.
385
- case "contact":
386
- case "notify":
387
- case "notify_user": {
388
- const parsed = NotifyRequestSchema.parse(request.params.arguments);
389
- const git = detectGit();
390
- const enriched = {
391
- ...parsed,
392
- repo: parsed.repo ?? git.repo,
393
- branch: parsed.branch ?? git.branch,
394
- // THREAD-SCOPED IDENTITY (stage 3, identity-ownership-design.md). A worker subagent
395
- // shares the parent's identity/slot, so its requests would otherwise scatter across
396
- // fresh threads and mix with a sibling's. Default an unthreaded contact to THIS
397
- // subagent's own thread so its requests group and siblings never collide. An explicit
398
- // parentId (continuing a specific conversation) always wins; a top-level parent session
399
- // is left untouched (undefined ⇒ the server mints a fresh thread, exactly as today).
400
- parentId: contactParentId(parsed.parentId)
401
- };
402
- let result;
403
- try {
404
- result = await submitNotification(enriched);
405
- } catch (err) {
406
- const fixable = fixAndRetry(err);
407
- if (fixable) return { isError: true, content: [{ type: "text", text: JSON.stringify(fixable) }] };
408
- throw err;
409
- }
410
- const sentAs = slotName(AGENT_NAME);
411
- const shown = { ...result, message: contactMessage(result) };
412
- return { content: [{ type: "text", text: JSON.stringify(sentAs ? { ...shown, sentAs } : shown) }] };
413
- }
414
- case "await_reply": {
415
- const { notificationId } = AwaitReplySchema.parse(request.params.arguments);
416
- const item = await awaitReply2(notificationId, {
417
- ...signal ? { signal } : {}
418
- });
419
- return { content: [{ type: "text", text: JSON.stringify({ ...item, message: awaitMessage(item) }) }] };
420
- }
421
- case "check_replies": {
422
- const result = await checkReplies();
423
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
424
- }
425
- case "get_thread": {
426
- const { parentId } = GetThreadSchema.parse(request.params.arguments);
427
- return { content: [{ type: "text", text: JSON.stringify(await getThread(parentId)) }] };
428
- }
429
- case "search_threads": {
430
- const { q } = SearchThreadsSchema.parse(request.params.arguments);
431
- return { content: [{ type: "text", text: JSON.stringify(await searchThreads(q)) }] };
432
- }
433
- case "answer_caller_question": {
434
- const { notificationId, answer } = AnswerCallerQuestionSchema.parse(request.params.arguments);
435
- const result = await answerCallerQuestion(notificationId, answer);
436
- return { content: [{ type: "text", text: JSON.stringify({
437
- ...result,
438
- ...result.live ? {} : { note: "The call already ended \u2014 send this as a threaded contact instead so the answer still reaches them." }
439
- }) }] };
440
- }
441
- case "set_task_state": {
442
- const { notificationId, state } = SetTaskStateToolSchema.parse(request.params.arguments);
443
- const result = await setTaskState(notificationId, state);
444
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
445
- }
446
- case "set_work_state": {
447
- const result = await setWorkState(SetWorkStateSchema.parse(request.params.arguments));
448
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
449
- }
450
- case "create_goal": {
451
- const result = await createGoal(CreateGoalSchema.parse(request.params.arguments));
452
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
453
- }
454
- case "claim_goal": {
455
- const { goalId } = ClaimGoalSchema.parse(request.params.arguments);
456
- return { content: [{ type: "text", text: JSON.stringify(await claimGoal(goalId)) }] };
457
- }
458
- case "update_goal": {
459
- const { goalId, ...input } = UpdateGoalToolSchema.parse(request.params.arguments);
460
- return { content: [{ type: "text", text: JSON.stringify(await updateGoal(goalId, input)) }] };
461
- }
462
- case "schedule_callback": {
463
- const result = await scheduleCallback(ScheduleCallbackSchema.parse(request.params.arguments));
464
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
465
- }
466
- case "handoff": {
467
- const result = await handoff(HandoffSchema.parse(request.params.arguments));
468
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
324
+ default: {
325
+ const name = request.params.name;
326
+ const result = await runTool(name, request.params.arguments ?? {}, { waits: true, signal });
327
+ const sentAs = name === "contact" ? slotName(AGENT_NAME) : null;
328
+ const shaped = sentAs && result && typeof result === "object" ? { ...result, sentAs } : result;
329
+ return { content: [{ type: "text", text: JSON.stringify(shaped) }] };
469
330
  }
470
- default:
471
- throw new Error(`Unknown tool: ${request.params.name}`);
472
331
  }
473
332
  }
474
333
  var beatDown = false;
package/dist/listen.js CHANGED
@@ -1,18 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- answerText
4
- } from "./chunk-UG2FARVV.js";
5
2
  import {
6
3
  WAKE_EVENT,
7
4
  wakeChannel
8
- } from "./chunk-KE63GZEQ.js";
5
+ } from "./chunk-3QUIB42M.js";
9
6
  import {
10
7
  ackReply,
11
8
  authToken,
12
9
  decodeReply,
13
10
  registerDelivery,
14
11
  sweepLeased
15
- } from "./chunk-PPACGOTU.js";
12
+ } from "./chunk-4UZAPBKK.js";
16
13
 
17
14
  // src/listen.ts
18
15
  import { createClient } from "@supabase/supabase-js";
@@ -117,6 +114,29 @@ function uninstallService() {
117
114
  return unit;
118
115
  }
119
116
 
117
+ // src/message.ts
118
+ function answerText(answer) {
119
+ switch (answer.kind) {
120
+ case "text":
121
+ return answer.text;
122
+ case "option":
123
+ return answer.label ?? answer.optionId;
124
+ case "multi":
125
+ case "ranked":
126
+ return (answer.labels ?? answer.optionIds).join(", ");
127
+ case "confirm":
128
+ return answer.approved ? "approved" : "declined";
129
+ case "clarify":
130
+ return answer.chunks.join(" ");
131
+ case "turns":
132
+ return answer.turns.map((turn) => turn.reply).join(" ");
133
+ case "precedent":
134
+ return answer.answer;
135
+ case "ignored":
136
+ return "";
137
+ }
138
+ }
139
+
120
140
  // src/listen.ts
121
141
  var emit = (obj) => void process.stdout.write(JSON.stringify(obj) + "\n");
122
142
  function launchEnv(work, reason) {
package/dist/onboard.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  resolvePairing,
4
4
  startPairing,
5
5
  suggestedAgentName
6
- } from "./chunk-4UEL7Y5U.js";
6
+ } from "./chunk-CXABA27N.js";
7
7
  import {
8
8
  autoConfigureClients,
9
9
  claudeInstallHint,
10
10
  openBrowser
11
- } from "./chunk-7IGGSB3H.js";
12
- import "./chunk-KE63GZEQ.js";
11
+ } from "./chunk-TLASZUJD.js";
12
+ import "./chunk-3QUIB42M.js";
13
13
  import {
14
14
  AGENT_NAME,
15
15
  TOKEN_PATH,
@@ -20,7 +20,7 @@ import {
20
20
  saveToken,
21
21
  setIdentity,
22
22
  whoAmI
23
- } from "./chunk-PPACGOTU.js";
23
+ } from "./chunk-4UZAPBKK.js";
24
24
 
25
25
  // src/onboard.ts
26
26
  function reportRegistered() {
package/dist/slot.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  AGENT_NAME
4
- } from "./chunk-PPACGOTU.js";
4
+ } from "./chunk-4UZAPBKK.js";
5
5
 
6
6
  // src/slot.ts
7
7
  process.stdout.write(AGENT_NAME);
@@ -9,7 +9,7 @@ import {
9
9
  readToken,
10
10
  sessionSlot,
11
11
  slotName
12
- } from "./chunk-PPACGOTU.js";
12
+ } from "./chunk-4UZAPBKK.js";
13
13
 
14
14
  // src/statusline.ts
15
15
  import { mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
@@ -35,7 +35,9 @@ function render(v) {
35
35
  case "session": {
36
36
  const who = v.name ? `${v.name} \xB7 ` : "";
37
37
  if (!v.status) return `paigy: ${who}revoked`;
38
- return `paigy: ${who}${MODE_LABEL[v.status.sessionMode]} \xB7 ${v.status.phone ? "phone \u2713" : "no phone"}`;
38
+ const n = v.status.waiting ?? 0;
39
+ const waiting = n > 0 ? ` \xB7 ${n} waiting` : "";
40
+ return `paigy: ${who}${MODE_LABEL[v.status.sessionMode]} \xB7 ${v.status.phone ? "phone \u2713" : "no phone"}${waiting}`;
39
41
  }
40
42
  }
41
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paigy/mcp",
3
- "version": "0.38.0",
3
+ "version": "0.40.1",
4
4
  "description": "Paigy MCP server — the AI agent harness that calls you. Lets an agent notify a user and await their reply.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,7 +40,7 @@
40
40
  "vitest": "^2.1.8",
41
41
  "@paigy/crypto": "0.0.0",
42
42
  "@paigy/schema": "0.0.0",
43
- "@paigy/sdk": "0.2.0"
43
+ "@paigy/sdk": "0.2.1"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsup",