@paigy/mcp 0.37.0 → 0.38.0

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-VXHTA4PB.js";
13
+ } from "./chunk-PPACGOTU.js";
14
14
 
15
15
  // src/identity.ts
16
16
  var CLIENT_LABELS = {
@@ -13,10 +13,10 @@ import {
13
13
  SetWorkStateSchema,
14
14
  mcpInputSchema,
15
15
  serverInstructions
16
- } from "./chunk-242XN7FD.js";
16
+ } from "./chunk-KE63GZEQ.js";
17
17
  import {
18
18
  AGENT_NAME
19
- } from "./chunk-VXHTA4PB.js";
19
+ } from "./chunk-PPACGOTU.js";
20
20
 
21
21
  // src/toolset.ts
22
22
  var ONBOARD_DESCRIPTION = "Get this agent talking to Paigy \u2014 call it FIRST, before contact/await_reply, 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.";
@@ -465,6 +465,7 @@ var AwaitItemSchema = z2.discriminatedUnion("type", [
465
465
  var CallbackTriggerSchema = z2.enum(["on_done", "on_blocked", "scheduled"]);
466
466
  var ScheduleCallbackSchema = z2.object({
467
467
  parentId: z2.string().describe("The thread to call back on (from a prior contact / reply / request)."),
468
+ goalId: z2.string().uuid().optional().describe("The Goal this callback advances; preferred for Goal-owned work."),
468
469
  trigger: CallbackTriggerSchema,
469
470
  dueInSeconds: z2.number().int().positive().optional().describe("For 'scheduled' only: how many seconds from now to fire."),
470
471
  note: z2.string().optional().describe("What to tell the user when you follow up.")
@@ -909,6 +910,15 @@ var AgentActivitySchema = z2.object({
909
910
  var ConnectionSummarySchema = z2.object({
910
911
  /** The connection = the agent's token id (used to address a request). */
911
912
  id: z2.string(),
913
+ /** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
914
+ * never talks); "agent" = an identity that sends. The roster and devices surfaces split
915
+ * on this. Optional/absent reads as "agent" (a row predating the kind column). See
916
+ * apps/api/src/tokens/devices-vs-agents-design.md. */
917
+ kind: z2.enum(["device", "agent"]).optional(),
918
+ /** For an agent, the token id of the DEVICE that minted it — so agents group under their
919
+ * machine, and revoking a device cascades to them. Null on devices, and on unlinked
920
+ * agents (phone-launched, provider-managed, or minted before the link existed). */
921
+ mintedByDevice: z2.string().nullable().optional(),
912
922
  device: z2.string().nullable(),
913
923
  /** The agent's display name (the single pairing name). */
914
924
  name: z2.string(),
@@ -4010,6 +4010,7 @@ var AwaitItemSchema = z2.discriminatedUnion("type", [
4010
4010
  var CallbackTriggerSchema = z2.enum(["on_done", "on_blocked", "scheduled"]);
4011
4011
  var ScheduleCallbackSchema = z2.object({
4012
4012
  parentId: z2.string().describe("The thread to call back on (from a prior contact / reply / request)."),
4013
+ goalId: z2.string().uuid().optional().describe("The Goal this callback advances; preferred for Goal-owned work."),
4013
4014
  trigger: CallbackTriggerSchema,
4014
4015
  dueInSeconds: z2.number().int().positive().optional().describe("For 'scheduled' only: how many seconds from now to fire."),
4015
4016
  note: z2.string().optional().describe("What to tell the user when you follow up.")
@@ -4454,6 +4455,15 @@ var AgentActivitySchema = z2.object({
4454
4455
  var ConnectionSummarySchema = z2.object({
4455
4456
  /** The connection = the agent's token id (used to address a request). */
4456
4457
  id: z2.string(),
4458
+ /** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
4459
+ * never talks); "agent" = an identity that sends. The roster and devices surfaces split
4460
+ * on this. Optional/absent reads as "agent" (a row predating the kind column). See
4461
+ * apps/api/src/tokens/devices-vs-agents-design.md. */
4462
+ kind: z2.enum(["device", "agent"]).optional(),
4463
+ /** For an agent, the token id of the DEVICE that minted it — so agents group under their
4464
+ * machine, and revoking a device cascades to them. Null on devices, and on unlinked
4465
+ * agents (phone-launched, provider-managed, or minted before the link existed). */
4466
+ mintedByDevice: z2.string().nullable().optional(),
4457
4467
  device: z2.string().nullable(),
4458
4468
  /** The agent's display name (the single pairing name). */
4459
4469
  name: z2.string(),
@@ -5807,6 +5817,7 @@ export {
5807
5817
  NotifyRequestSchema,
5808
5818
  SetWorkStateSchema,
5809
5819
  ScheduleCallbackSchema,
5820
+ sessionSlot,
5810
5821
  contactParentId,
5811
5822
  AGENT_NAME,
5812
5823
  TOKEN_PATH,
package/dist/enable.js CHANGED
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  PAIGY_TOOL_IDS,
4
4
  enablePaigyTools
5
- } from "./chunk-PN7FDW26.js";
6
- import "./chunk-242XN7FD.js";
7
- import "./chunk-VXHTA4PB.js";
5
+ } from "./chunk-7IGGSB3H.js";
6
+ import "./chunk-KE63GZEQ.js";
7
+ import "./chunk-PPACGOTU.js";
8
8
 
9
9
  // src/enable.ts
10
10
  function main() {
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  resolvePairing,
10
10
  startPairing,
11
11
  suggestedAgentName
12
- } from "./chunk-V66NUNSQ.js";
12
+ } from "./chunk-4UEL7Y5U.js";
13
13
  import {
14
14
  AnswerCallerQuestionSchema,
15
15
  AwaitReplySchema,
@@ -27,11 +27,11 @@ import {
27
27
  autoConfigureClients,
28
28
  claudeInstallHint,
29
29
  paigyToolsAllowlisted
30
- } from "./chunk-PN7FDW26.js";
30
+ } from "./chunk-7IGGSB3H.js";
31
31
  import {
32
32
  CreateGoalSchema,
33
33
  HandoffSchema
34
- } from "./chunk-242XN7FD.js";
34
+ } from "./chunk-KE63GZEQ.js";
35
35
  import {
36
36
  clearSurface,
37
37
  writeSurface
@@ -68,7 +68,7 @@ import {
68
68
  submitNotification,
69
69
  updateGoal,
70
70
  whoAmI
71
- } from "./chunk-VXHTA4PB.js";
71
+ } from "./chunk-PPACGOTU.js";
72
72
 
73
73
  // src/index.ts
74
74
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -193,6 +193,7 @@ function pairStartResult(start, loggedOut) {
193
193
  qr.make();
194
194
  const link = start.verificationUri;
195
195
  const ascii = qr.createASCII(1, 2);
196
+ const door = "in Paigy \u2192 Devices \u2192 Connect a computer";
196
197
  const userMessage = loggedOut ? `**Your machine was logged out.** Reconnect and every agent here pairs itself again \u2014 no more codes.
197
198
 
198
199
  **[Reconnect this machine](${link})**
@@ -205,14 +206,17 @@ Or scan:
205
206
  ${ascii}
206
207
  \`\`\`
207
208
 
208
- Or enter code **${start.userCode}** in the Paigy app (Inbox \u2192 Add a new agent).` : `**[Approve this agent](${link})**
209
+ Or type **${start.userCode}** ${door}.` : `**Approve this agent from your phone**
209
210
 
210
- Or open: ${link}
211
- Or enter code **${start.userCode}** in the Paigy app (Inbox \u2192 Add a new agent).`;
211
+ **[Open](${link})** ${link}
212
+
213
+ Or scan the QR, or type **${start.userCode}** ${door}.
214
+
215
+ This session isn't on a connected computer, so it asks by code.`;
212
216
  return { content: [
213
217
  { type: "text", text: loggedOut ? `YOUR MACHINE WAS LOGGED OUT \u2014 reconnect: ${link}
214
- (or scan the QR, or enter code ${start.userCode} in the app)` : `APPROVE: ${link}
215
- (or code ${start.userCode} in the app: Inbox \u2192 Add a new agent)` },
218
+ (or scan the QR, or type ${start.userCode} ${door})` : `APPROVE THIS AGENT FROM YOUR PHONE: ${link}
219
+ (or scan the QR, or type ${start.userCode} ${door})` },
216
220
  { type: "text", text: JSON.stringify({
217
221
  status: "awaiting_approval",
218
222
  verification_uri_complete: link,
package/dist/listen.js CHANGED
@@ -5,14 +5,14 @@ import {
5
5
  import {
6
6
  WAKE_EVENT,
7
7
  wakeChannel
8
- } from "./chunk-242XN7FD.js";
8
+ } from "./chunk-KE63GZEQ.js";
9
9
  import {
10
10
  ackReply,
11
11
  authToken,
12
12
  decodeReply,
13
13
  registerDelivery,
14
14
  sweepLeased
15
- } from "./chunk-VXHTA4PB.js";
15
+ } from "./chunk-PPACGOTU.js";
16
16
 
17
17
  // src/listen.ts
18
18
  import { createClient } from "@supabase/supabase-js";
package/dist/onboard.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  resolvePairing,
4
4
  startPairing,
5
5
  suggestedAgentName
6
- } from "./chunk-V66NUNSQ.js";
6
+ } from "./chunk-4UEL7Y5U.js";
7
7
  import {
8
8
  autoConfigureClients,
9
9
  claudeInstallHint,
10
10
  openBrowser
11
- } from "./chunk-PN7FDW26.js";
12
- import "./chunk-242XN7FD.js";
11
+ } from "./chunk-7IGGSB3H.js";
12
+ import "./chunk-KE63GZEQ.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-VXHTA4PB.js";
23
+ } from "./chunk-PPACGOTU.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-VXHTA4PB.js";
4
+ } from "./chunk-PPACGOTU.js";
5
5
 
6
6
  // src/slot.ts
7
7
  process.stdout.write(AGENT_NAME);
@@ -4,9 +4,12 @@ import {
4
4
  } from "./chunk-3SVNPJPN.js";
5
5
  import {
6
6
  BACKEND_URL,
7
+ listSlots,
7
8
  reach,
8
- readToken
9
- } from "./chunk-VXHTA4PB.js";
9
+ readToken,
10
+ sessionSlot,
11
+ slotName
12
+ } from "./chunk-PPACGOTU.js";
10
13
 
11
14
  // src/statusline.ts
12
15
  import { mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
@@ -21,10 +24,43 @@ var MODE_LABEL = {
21
24
  all_calls: "all calls",
22
25
  silent: "silent"
23
26
  };
24
- function render(status, surface = null) {
25
- if (surface) return `paigy \u26A0 ${surface.label}: ${surface.code}`;
26
- if (!status) return "paigy: unpaired";
27
- return `paigy: ${MODE_LABEL[status.sessionMode]} \xB7 ${status.phone ? "phone \u2713" : "no phone"}`;
27
+ function render(v) {
28
+ switch (v.kind) {
29
+ case "surface":
30
+ return `paigy \u26A0 ${v.label}: ${v.code}`;
31
+ case "unpaired":
32
+ return "paigy: unpaired";
33
+ case "device-only":
34
+ return "paigy: paired \xB7 session hatches on first use";
35
+ case "session": {
36
+ const who = v.name ? `${v.name} \xB7 ` : "";
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"}`;
39
+ }
40
+ }
41
+ }
42
+ async function stdinSessionId(input = process.stdin) {
43
+ if (input.isTTY) return void 0;
44
+ try {
45
+ const raw = await new Promise((resolve) => {
46
+ let buf = "";
47
+ const done = () => resolve(buf);
48
+ input.setEncoding("utf8");
49
+ input.on("data", (c) => {
50
+ buf += c;
51
+ });
52
+ input.on("end", done);
53
+ input.on("error", done);
54
+ setTimeout(done, 300).unref();
55
+ });
56
+ const sid = JSON.parse(raw).session_id;
57
+ return typeof sid === "string" && sid.trim() ? sid : void 0;
58
+ } catch {
59
+ return void 0;
60
+ }
61
+ }
62
+ function resolveSlot(sid) {
63
+ return process.env.PAIGY_AGENT || sessionSlot(sid);
28
64
  }
29
65
  function readCache() {
30
66
  try {
@@ -49,18 +85,22 @@ async function fetchStatus(token) {
49
85
  }
50
86
  async function main() {
51
87
  const surface = readSurface();
52
- if (surface) return render(null, surface);
53
- const token = readToken();
54
- if (!token) return render(null);
88
+ if (surface) return render({ kind: "surface", ...surface });
89
+ const slot = resolveSlot(await stdinSessionId());
90
+ const token = readToken(slot);
91
+ if (!token) {
92
+ return render(listSlots().includes("Desktop") ? { kind: "device-only" } : { kind: "unpaired" });
93
+ }
94
+ const name = slotName(slot);
55
95
  const cached = readCache();
56
- if (cached && Date.now() - cached.at < TTL_MS) return render(cached.status);
96
+ if (cached && Date.now() - cached.at < TTL_MS) return render({ kind: "session", name, status: cached.status });
57
97
  try {
58
98
  const status = await fetchStatus(token);
59
99
  mkdirSync(DIR, { recursive: true });
60
100
  writeFileSync(CACHE, JSON.stringify({ at: Date.now(), status }));
61
- return render(status);
101
+ return render({ kind: "session", name, status });
62
102
  } catch {
63
- return cached ? render(cached.status) : "paigy: \u2026";
103
+ return cached ? render({ kind: "session", name, status: cached.status }) : "paigy: \u2026";
64
104
  }
65
105
  }
66
106
  function isEntry() {
@@ -75,5 +115,7 @@ function isEntry() {
75
115
  if (isEntry()) void main().then((line) => console.log(line));
76
116
  export {
77
117
  main,
78
- render
118
+ render,
119
+ resolveSlot,
120
+ stdinSessionId
79
121
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paigy/mcp",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
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",
@@ -24,13 +24,6 @@
24
24
  "url": "git+https://github.com/mauurda/paigy.git",
25
25
  "directory": "apps/mcp"
26
26
  },
27
- "scripts": {
28
- "build": "tsup",
29
- "dev": "tsup --watch",
30
- "typecheck": "tsc --noEmit",
31
- "test": "vitest run",
32
- "prepublishOnly": "pnpm --filter @paigy/schema build && pnpm --filter @paigy/crypto build && pnpm --filter @paigy/sdk build && pnpm build"
33
- },
34
27
  "dependencies": {
35
28
  "@modelcontextprotocol/sdk": "^1.0.4",
36
29
  "@supabase/supabase-js": "^2.47.10",
@@ -40,13 +33,19 @@
40
33
  "zod-to-json-schema": "^3.24.1"
41
34
  },
42
35
  "devDependencies": {
43
- "@paigy/crypto": "workspace:*",
44
- "@paigy/schema": "workspace:*",
45
- "@paigy/sdk": "workspace:*",
46
36
  "@types/node": "^22.0.0",
47
37
  "@types/qrcode-generator": "^1.0.6",
48
38
  "tsup": "^8.3.5",
49
39
  "typescript": "^5.7.2",
50
- "vitest": "^2.1.8"
40
+ "vitest": "^2.1.8",
41
+ "@paigy/crypto": "0.0.0",
42
+ "@paigy/schema": "0.0.0",
43
+ "@paigy/sdk": "0.2.0"
44
+ },
45
+ "scripts": {
46
+ "build": "tsup",
47
+ "dev": "tsup --watch",
48
+ "typecheck": "tsc --noEmit",
49
+ "test": "vitest run"
51
50
  }
52
- }
51
+ }