@paigy/mcp 0.40.25 → 0.40.27

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.
@@ -4,54 +4,38 @@ import {
4
4
  serverInstructions,
5
5
  sessionStartHook,
6
6
  withSessionStartHook
7
- } from "./chunk-GHSB2VP6.js";
7
+ } from "./chunk-X3GTDW5G.js";
8
8
  import {
9
9
  CODEX_ENV,
10
10
  agentName,
11
11
  withCodexEnv
12
- } from "./chunk-EJYXBEWN.js";
12
+ } from "./chunk-4C6SDQ7A.js";
13
13
 
14
14
  // src/toolset.ts
15
- 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.";
15
+ var CONFIGURE_DESCRIPTION = "Set this agent up with Paigy \u2014 call it FIRST, before contact, and any time you're unsure who you are. One call does whatever the situation needs: NOT SET UP \u2192 if this machine holds a device credential (the user ran the Paigy desktop app or harness) it hatches an identity INSTANTLY, no code and no approval; otherwise it starts the code ceremony. ALREADY SET UP \u2192 returns your current identity and the two things left to decide, renaming it or logging out. 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 (pick your own; 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.\n\nTHE CODE CEREMONY does not open a browser; the user enters the code in the Paigy app (or scans `qr`). A result with { user_code, device_code, qr, user_message } has already started polling for approval in the background: you MUST immediately print the `user_message` (the bare code) to the user, AND in that same turn call configure again with that `device_code` to collect the result. It returns the moment the user approves; on { status:'pending' } 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.\n\nOn { status:'paired' }, or whenever it returns `enable_command`, ALWAYS follow the `enable_prompt`: PRINT that command for the user to run, so Paigy's tools stop prompting each time. 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.\n\nLOG OUT with { logOut: true }: it logs out THIS agent only \u2014 its token is revoked server-side and its local entry removed. Other agents and this device's credential are untouched, and a later configure re-hatches instantly while the device credential exists. Disconnecting the device itself is not an agent tool.";
16
16
  var SERVER_INSTRUCTIONS = serverInstructions({ waits: true });
17
17
 
18
18
  // src/tools.ts
19
19
  import { z } from "zod";
20
- var OnboardSchema = z.object({
21
- name: z.string().max(60).optional(),
22
- voice: z.string().max(40).optional(),
23
- /** Continue a code ceremony already in flight — same meaning as `pair`'s. */
24
- device_code: z.string().optional(),
25
- /** Which allowlist to REPORT on (never written by `start`). */
26
- scope: z.enum(["user", "project"]).optional()
27
- });
28
- var PairSchema = z.object({
29
- 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."),
30
- 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."),
31
- voice: z.string().optional().describe("Hatch path only: your voice on calls \u2014 one of rachel, george, jessica, brian, lily.")
20
+ var ConfigureSchema = z.object({
21
+ name: z.string().min(1).max(60).optional().describe("Who you are: the name you choose when hatching, or the new one to RENAME yourself to when already set up. 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."),
22
+ voice: z.string().max(40).optional().describe("Your voice on calls \u2014 one of rachel, george, jessica, brian, lily."),
23
+ device_code: z.string().optional().describe("Continue a code ceremony already in flight: the device_code a previous configure returned. Omit it otherwise."),
24
+ /** Which allowlist to REPORT on (never written). */
25
+ scope: z.enum(["user", "project"]).optional().describe("Which tool allowlist to report on (user or project settings). Read-only."),
26
+ logOut: z.boolean().optional().describe("true: log THIS agent out \u2014 its token is revoked and its local entry removed. Other agents and this device's credential are untouched.")
32
27
  });
33
28
  var IDENTITY_TOOLS = [
34
29
  {
35
- // ONE rail for starting a session (#875). `pair`, the `paigy-mcp-onboard` CLI and
36
- // `enable_tools` were three doors into one flow, and "onboard" was the word people
37
- // reached for attached to the tool that did the least. It's the door now.
38
- name: "onboard",
39
- description: ONBOARD_DESCRIPTION,
40
- inputSchema: mcpInputSchema(OnboardSchema)
41
- },
42
- {
43
- name: "pair",
44
- 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.",
45
- inputSchema: mcpInputSchema(PairSchema)
46
- },
47
- {
48
- name: "unpair",
49
- 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.",
50
- inputSchema: mcpInputSchema(z.object({}))
30
+ // ONE rail for starting a session (#875), and since 2026-10-07 the only identity tool: `onboard`
31
+ // renamed, and `pair` (which it already did everything of) and `unpair` (`logOut`) folded in.
32
+ name: "configure",
33
+ description: CONFIGURE_DESCRIPTION,
34
+ inputSchema: mcpInputSchema(ConfigureSchema)
51
35
  },
52
36
  {
53
37
  name: "listen",
54
- description: "Am I listening for answers, and can Paigy resume this session? Takes no arguments. Returns status `listening` for harness delivery or a running listener with a ready wake adapter; `receiving` means a process is running but automatic resume is not confirmed (read its wake error or watch its output); `unpaired` means call onboard; `start` gives the exact command to run NOW as a watched background task for this session. Start it once. Codex queues into CODEX_THREAD_ID automatically when its CLI supports queue; PAIGY_ON_WAKE overrides it. A successful queue is not evidence the agent handled the answer: receive with contact({ wait: false }) and read the relevant Goal, then respond with contact. This tool never subscribes or starts anything itself.",
38
+ description: "Am I listening for answers, and can Paigy resume this session? Takes no arguments. Returns status `listening` for harness delivery or a running listener with a ready wake adapter; `receiving` means a process is running but automatic resume is not confirmed (read its wake error or watch its output); `unpaired` means call configure; `start` gives the exact command to run NOW as a watched background task for this session. Start it once. Codex queues into CODEX_THREAD_ID automatically when its CLI supports queue; PAIGY_ON_WAKE overrides it. A successful queue is not evidence the agent handled the answer: receive with contact({ wait: false }) and read the relevant Goal, then respond with contact. This tool never subscribes or starts anything itself.",
55
39
  inputSchema: mcpInputSchema(z.object({}))
56
40
  }
57
41
  ];
@@ -218,9 +202,8 @@ function claudeInstallHint(skip = agentName()) {
218
202
  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.";
219
203
  }
220
204
  var ENABLE_COMMAND = "npx -y -p @paigy/mcp@latest paigy-enable-tools";
221
- var PROMPTS_ON_PURPOSE = /* @__PURE__ */ new Set(["pair", "unpair"]);
222
205
  var PAIGY_TOOL_IDS = [
223
- ...TOOL_NAMES.filter((n) => !PROMPTS_ON_PURPOSE.has(n)),
206
+ ...TOOL_NAMES,
224
207
  ...HIDDEN_ALIASES
225
208
  ].map((n) => `mcp__paigy__${n}`);
226
209
  function withPaigyAllowlist(existing, tools) {
@@ -332,8 +315,7 @@ function installSessionListening() {
332
315
 
333
316
  export {
334
317
  SERVER_INSTRUCTIONS,
335
- OnboardSchema,
336
- PairSchema,
318
+ ConfigureSchema,
337
319
  TOOLS,
338
320
  openBrowser,
339
321
  autoConfigureClients,
@@ -6,7 +6,7 @@ import {
6
6
  saveToken,
7
7
  setIdentity,
8
8
  sleep
9
- } from "./chunk-EJYXBEWN.js";
9
+ } from "./chunk-4C6SDQ7A.js";
10
10
 
11
11
  // src/identity.ts
12
12
  var CLIENT_LABELS = {
@@ -34,12 +34,12 @@ async function identify(who, ask) {
34
34
  who = await setIdentity({ ...ask.name ? { name: ask.name } : {}, ...ask.voice ? { voice: ask.voice } : {} });
35
35
  renamed = true;
36
36
  } catch (e) {
37
- const message2 = e instanceof NameTakenError ? e.message : `The rename did not go through (${e.message}); nothing changed. Call onboard again to retry, or carry on.`;
37
+ const message2 = e instanceof NameTakenError ? e.message : `The rename did not go through (${e.message}); nothing changed. Call configure again to retry, or carry on.`;
38
38
  return { name: who.name, voice: who.voice, message: message2 };
39
39
  }
40
40
  }
41
41
  const voice = who.voice ? ` (voice: ${who.voice})` : "";
42
- const message = !who.name ? [renamed && who.voice ? `Your voice is ${who.voice} now.` : "", who.unnamed ?? "Set up, with no name yet."].filter(Boolean).join(" ") : renamed ? `Renamed \u2014 this agent is "${who.name}"${voice} now.` : `Already set up as "${who.name}"${voice}. Ask the user if they want to rename it or unpair; otherwise carry on.`;
42
+ const message = !who.name ? [renamed && who.voice ? `Your voice is ${who.voice} now.` : "", who.unnamed ?? "Set up, with no name yet."].filter(Boolean).join(" ") : renamed ? `Renamed \u2014 this agent is "${who.name}"${voice} now.` : `Already set up as "${who.name}"${voice}. Ask the user if they want to rename it or log it out; otherwise carry on.`;
43
43
  return { name: who.name, voice: who.voice, message };
44
44
  }
45
45