@paigy/mcp 0.40.23 → 0.40.25

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.
@@ -0,0 +1,110 @@
1
+ // src/wake.ts
2
+ import { execFile, spawn } from "child_process";
3
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
4
+ import { dirname } from "path";
5
+ function wakeTarget(env) {
6
+ if (env.PAIGY_HARNESS) return { kind: "harness" };
7
+ if (env.PAIGY_ON_WAKE) return { kind: "command", command: env.PAIGY_ON_WAKE };
8
+ if (env.CODEX_THREAD_ID) return { kind: "codex", thread: env.CODEX_THREAD_ID };
9
+ return { kind: "output" };
10
+ }
11
+ function readWakeStatus(path) {
12
+ try {
13
+ return JSON.parse(readFileSync(path, "utf8"));
14
+ } catch {
15
+ return void 0;
16
+ }
17
+ }
18
+ var WakeBridge = class {
19
+ constructor(env, path) {
20
+ this.env = env;
21
+ this.path = path;
22
+ const target = wakeTarget(env);
23
+ const saved = readWakeStatus(path);
24
+ this.state = { ...JSON.stringify(saved?.target) === JSON.stringify(target) ? saved : {}, target, ready: false };
25
+ }
26
+ env;
27
+ path;
28
+ state;
29
+ checked = false;
30
+ status() {
31
+ return { ...this.state };
32
+ }
33
+ save() {
34
+ mkdirSync(dirname(this.path), { recursive: true });
35
+ const temp = `${this.path}.${process.pid}.tmp`;
36
+ writeFileSync(temp, JSON.stringify(this.state), { mode: 384 });
37
+ renameSync(temp, this.path);
38
+ }
39
+ run(command, args, extra = {}) {
40
+ return new Promise((resolve, reject) => {
41
+ execFile(command, args, { env: { ...this.env, ...extra }, timeout: 15e3, maxBuffer: 64 * 1024 }, (error, stdout, stderr) => {
42
+ if (error) reject(new Error(`${error.message}${stderr ? `: ${stderr.trim()}` : ""}`));
43
+ else resolve(stdout);
44
+ });
45
+ });
46
+ }
47
+ launch(command, extra) {
48
+ return new Promise((resolve, reject) => {
49
+ const child = spawn("/bin/sh", ["-c", command], { stdio: "inherit", env: { ...this.env, ...extra } });
50
+ child.once("spawn", resolve);
51
+ child.once("error", reject);
52
+ child.once("exit", (code, signal) => {
53
+ if (code === 0) return;
54
+ this.state.ready = false;
55
+ this.state.lastError = `PAIGY_ON_WAKE exited ${signal ?? code}`;
56
+ this.save();
57
+ process.stderr.write(`Paigy wake error: ${this.state.lastError}
58
+ `);
59
+ });
60
+ });
61
+ }
62
+ async prepare() {
63
+ if (this.checked) return;
64
+ try {
65
+ if (this.state.target.kind === "codex") {
66
+ const help = await this.run("codex", ["queue", "--help"]);
67
+ if (!help.includes("--thread") || !help.includes("--message")) throw new Error("Installed Codex does not support queue --thread --message; update Codex or configure PAIGY_ON_WAKE.");
68
+ }
69
+ this.checked = true;
70
+ this.state.ready = this.state.target.kind === "codex" || this.state.target.kind === "command" || this.state.target.kind === "harness";
71
+ delete this.state.lastError;
72
+ this.save();
73
+ } catch (error) {
74
+ this.state.ready = false;
75
+ this.state.lastError = error.message;
76
+ this.save();
77
+ throw error;
78
+ }
79
+ }
80
+ async deliver(fingerprint, message, extra) {
81
+ await this.prepare();
82
+ const target = this.state.target;
83
+ if (target.kind === "output" || target.kind === "harness") return;
84
+ const fingerprints = fingerprint === void 0 ? void 0 : typeof fingerprint === "string" ? [fingerprint] : fingerprint;
85
+ if (target.kind === "codex" && fingerprints?.every((item) => this.state.fingerprints?.includes(item))) {
86
+ this.state.fingerprints = fingerprints;
87
+ this.save();
88
+ return;
89
+ }
90
+ try {
91
+ if (target.kind === "codex") await this.run("codex", ["queue", "--thread", target.thread, "--message", message]);
92
+ else await this.launch(target.command, extra);
93
+ this.state.fingerprints = fingerprints;
94
+ if (target.kind === "codex") this.state.lastQueuedAt = (/* @__PURE__ */ new Date()).toISOString();
95
+ this.state.ready = true;
96
+ delete this.state.lastError;
97
+ this.save();
98
+ } catch (error) {
99
+ this.state.ready = false;
100
+ this.state.lastError = error.message;
101
+ this.save();
102
+ throw error;
103
+ }
104
+ }
105
+ };
106
+
107
+ export {
108
+ readWakeStatus,
109
+ WakeBridge
110
+ };
@@ -4,11 +4,12 @@ import {
4
4
  serverInstructions,
5
5
  sessionStartHook,
6
6
  withSessionStartHook
7
- } from "./chunk-JLRBZZNT.js";
7
+ } from "./chunk-GHSB2VP6.js";
8
8
  import {
9
9
  CODEX_ENV,
10
- agentName
11
- } from "./chunk-PR7ROBN4.js";
10
+ agentName,
11
+ withCodexEnv
12
+ } from "./chunk-EJYXBEWN.js";
12
13
 
13
14
  // src/toolset.ts
14
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.";
@@ -49,12 +50,8 @@ var IDENTITY_TOOLS = [
49
50
  inputSchema: mcpInputSchema(z.object({}))
50
51
  },
51
52
  {
52
- // A session asked to "start listening" can, in one call (#2265). Nothing can push an
53
- // answer into a session started in a terminal — an answer waits for its next check_replies —
54
- // and the only thing that reaches a running session mid-turn is a watched background task.
55
- // So this tool decides and hands over: it never subscribes, spawns or writes settings.
56
53
  name: "listen",
57
- description: "Am I listening for answers, and if not, how do I start? Call it when the user asks you to start listening (or to stay reachable), and whenever you are unsure whether you are. Takes no arguments. Returns `status`: `listening` \u2014 nothing to do (a session started by the Paigy harness is ALWAYS listening: its pump types each answer in as it lands; or your own paigy-listen is already running, with its pid); `unpaired` \u2014 call onboard first; `start` \u2014 a `command` you MUST run NOW, in this same turn, as a watched BACKGROUND task (your harness's background-task/monitor tool), and leave running for the session. Each line that task prints is a Delivery waiting for you: claim_goal the Goal it names, read it, answer with contact. Start it once. This tool never subscribes or starts anything itself \u2014 the listener has to be YOUR watched task, or its lines reach no one.",
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.",
58
55
  inputSchema: mcpInputSchema(z.object({}))
59
56
  }
60
57
  ];
@@ -89,7 +86,10 @@ function withPaigyMcpJson(existing, agent) {
89
86
  return JSON.stringify(config, null, 2);
90
87
  }
91
88
  function withPaigyMcpToml(existing, agent) {
92
- if (existing.includes("[mcp_servers.paigy]")) return null;
89
+ if (existing.includes("[mcp_servers.paigy]")) {
90
+ const updated = withCodexEnv(existing);
91
+ return updated === existing ? null : updated;
92
+ }
93
93
  const entry = [
94
94
  "",
95
95
  "[mcp_servers.paigy]",
@@ -14,14 +14,13 @@ import {
14
14
  TOKEN_PATH,
15
15
  UnpairedError,
16
16
  acceptTriage,
17
+ acknowledge,
17
18
  agentName,
18
19
  authToken,
19
- checkReplies,
20
20
  claimGoal,
21
21
  claimSessionEnds,
22
22
  claimSessions,
23
23
  contact,
24
- createGoal,
25
24
  currentRepo,
26
25
  deleteToken,
27
26
  dismissTriage,
@@ -34,13 +33,17 @@ import {
34
33
  listConnections,
35
34
  listNotes,
36
35
  listSlots,
36
+ manageGoals,
37
37
  overrideToken,
38
38
  parseDue,
39
+ pendingEvents,
39
40
  pollToken,
40
41
  reach,
41
42
  reachAs,
42
43
  readSlot,
43
44
  readToken,
45
+ receive,
46
+ receiveContact,
44
47
  recordDecision,
45
48
  registerDelivery,
46
49
  repoFromRemote,
@@ -48,8 +51,10 @@ import {
48
51
  revokeToken,
49
52
  runTool,
50
53
  saveToken,
54
+ searchRecords,
51
55
  sessionId,
52
56
  sessionSlot,
57
+ setClient,
53
58
  setIdentity,
54
59
  sleep,
55
60
  slotIdentity,
@@ -59,8 +64,9 @@ import {
59
64
  updateGoal,
60
65
  updateSlot,
61
66
  whoAmI,
62
- whoIsWorking
63
- } from "./chunk-PR7ROBN4.js";
67
+ whoIsWorking,
68
+ withCodexEnv
69
+ } from "./chunk-EJYXBEWN.js";
64
70
  export {
65
71
  AGENT_TOOLS,
66
72
  AGENT_TOOL_NAMES,
@@ -77,14 +83,13 @@ export {
77
83
  TOKEN_PATH,
78
84
  UnpairedError,
79
85
  acceptTriage,
86
+ acknowledge,
80
87
  agentName,
81
88
  authToken,
82
- checkReplies,
83
89
  claimGoal,
84
90
  claimSessionEnds,
85
91
  claimSessions,
86
92
  contact,
87
- createGoal,
88
93
  currentRepo,
89
94
  deleteToken,
90
95
  dismissTriage,
@@ -97,13 +102,17 @@ export {
97
102
  listConnections,
98
103
  listNotes,
99
104
  listSlots,
105
+ manageGoals,
100
106
  overrideToken,
101
107
  parseDue,
108
+ pendingEvents,
102
109
  pollToken,
103
110
  reach,
104
111
  reachAs,
105
112
  readSlot,
106
113
  readToken,
114
+ receive,
115
+ receiveContact,
107
116
  recordDecision,
108
117
  registerDelivery,
109
118
  repoFromRemote,
@@ -111,8 +120,10 @@ export {
111
120
  revokeToken,
112
121
  runTool,
113
122
  saveToken,
123
+ searchRecords,
114
124
  sessionId,
115
125
  sessionSlot,
126
+ setClient,
116
127
  setIdentity,
117
128
  sleep,
118
129
  slotIdentity,
@@ -122,5 +133,6 @@ export {
122
133
  updateGoal,
123
134
  updateSlot,
124
135
  whoAmI,
125
- whoIsWorking
136
+ whoIsWorking,
137
+ withCodexEnv
126
138
  };
package/dist/enable.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  PAIGY_TOOL_IDS,
4
4
  enablePaigyTools,
5
5
  installSessionListening
6
- } from "./chunk-HKODQKUV.js";
7
- import "./chunk-JLRBZZNT.js";
8
- import "./chunk-PR7ROBN4.js";
6
+ } from "./chunk-UAVXYNLV.js";
7
+ import "./chunk-GHSB2VP6.js";
8
+ import "./chunk-EJYXBEWN.js";
9
9
 
10
10
  // src/enable.ts
11
11
  function main() {
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ readWakeStatus
4
+ } from "./chunk-RK5LT7NH.js";
2
5
  import {
3
6
  clearPairing,
4
7
  identify,
@@ -6,7 +9,7 @@ import {
6
9
  resolvePairing,
7
10
  startPairing,
8
11
  suggestedAgentName
9
- } from "./chunk-BNMMRKEY.js";
12
+ } from "./chunk-2ROD77AW.js";
10
13
  import {
11
14
  ENABLE_COMMAND,
12
15
  OnboardSchema,
@@ -15,11 +18,13 @@ import {
15
18
  SERVER_INSTRUCTIONS,
16
19
  TOOLS,
17
20
  paigyToolsAllowlisted
18
- } from "./chunk-HKODQKUV.js";
21
+ } from "./chunk-UAVXYNLV.js";
19
22
  import {
20
23
  decideListen,
21
- listenerAlive
22
- } from "./chunk-JLRBZZNT.js";
24
+ existingListener,
25
+ listenerKey,
26
+ wakeStatusPath
27
+ } from "./chunk-GHSB2VP6.js";
23
28
  import {
24
29
  clearSurface,
25
30
  writeSurface
@@ -37,9 +42,10 @@ import {
37
42
  runTool,
38
43
  saveToken,
39
44
  sessionId,
45
+ setClient,
40
46
  slotName,
41
47
  whoAmI
42
- } from "./chunk-PR7ROBN4.js";
48
+ } from "./chunk-EJYXBEWN.js";
43
49
 
44
50
  // src/index.ts
45
51
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -49,6 +55,7 @@ import {
49
55
  ListToolsRequestSchema
50
56
  } from "@modelcontextprotocol/sdk/types.js";
51
57
  import { fileURLToPath } from "url";
58
+ import { createRequire } from "module";
52
59
  import qrcode from "qrcode-generator";
53
60
 
54
61
  // src/survive.ts
@@ -194,8 +201,10 @@ This session isn't on a connected computer, so it asks by code.`;
194
201
  }) }
195
202
  ] };
196
203
  }
204
+ var VERSION = createRequire(import.meta.url)("../package.json").version;
205
+ setClient(`mcp@${VERSION}`);
197
206
  var server = new Server(
198
- { name: "paigy", version: "0.0.0" },
207
+ { name: "paigy", version: VERSION },
199
208
  {
200
209
  capabilities: { tools: {} },
201
210
  instructions: SERVER_INSTRUCTIONS
@@ -341,11 +350,13 @@ async function handleTool(request, signal) {
341
350
  // daemon is the `listen.js` beside our own entry, so the command never resolves a package.
342
351
  case "listen": {
343
352
  const slot = agentName();
344
- const pid = listenerAlive(slot);
353
+ const key = listenerKey(slot, process.env);
354
+ const pid = existingListener(slot, process.env);
345
355
  const decision = decideListen({
346
356
  env: process.env,
347
357
  token: !!readToken(),
348
358
  pidAlive: pid !== null,
359
+ wake: readWakeStatus(wakeStatusPath(key)),
349
360
  ...pid !== null ? { pid } : {},
350
361
  execPath: process.execPath,
351
362
  listenJs: fileURLToPath(new URL("./listen.js", import.meta.url)),
package/dist/listen.js CHANGED
@@ -1,20 +1,28 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ WakeBridge
4
+ } from "./chunk-RK5LT7NH.js";
2
5
  import {
3
6
  entryWords,
7
+ existingListener,
8
+ harnessDriven,
9
+ listenerKey,
4
10
  removeListenMark,
11
+ wakeStatusPath,
5
12
  writeListenMark
6
- } from "./chunk-JLRBZZNT.js";
13
+ } from "./chunk-GHSB2VP6.js";
7
14
  import {
8
15
  agentName,
9
- checkReplies,
10
16
  contact,
11
17
  getGoal,
18
+ heartbeat,
19
+ receive,
12
20
  slotName,
13
21
  subscribeWake
14
- } from "./chunk-PR7ROBN4.js";
22
+ } from "./chunk-EJYXBEWN.js";
15
23
 
16
24
  // src/listen.ts
17
- import { spawn } from "child_process";
25
+ import { createHash } from "crypto";
18
26
  import { realpathSync } from "fs";
19
27
  import { fileURLToPath } from "url";
20
28
 
@@ -157,10 +165,11 @@ function launchEnv(waiting, reason, goalId) {
157
165
  put("PAIGY_TEXT", saidIn(lead) || ("about" in lead ? lead.about : ""));
158
166
  return env;
159
167
  }
160
- async function sweep(reason, goalId) {
168
+ async function sweep(reason, goalId, bridge = new WakeBridge(process.env, wakeStatusPath(listenerKey(agentName(), process.env))), participant) {
161
169
  try {
162
- const cmd = process.env.PAIGY_ON_WAKE;
163
- const { deliveries: rows, stalled, review, assigned } = await checkReplies();
170
+ void Promise.resolve().then(() => heartbeat(void 0, { listening: true })).catch(() => {
171
+ });
172
+ const { deliveries: rows, stalled, review, assigned } = await receive();
164
173
  const lead = leadOf(rows, goalId);
165
174
  const full = lead ? await contact({ deliveryId: lead.deliveryId }, { waits: false }).then((d) => "sent" in d ? null : d).catch(() => null) : null;
166
175
  const deliveries = rows.map((d) => d === lead && full ? full : d);
@@ -169,8 +178,32 @@ async function sweep(reason, goalId) {
169
178
  const waiting = { deliveries, goal, ...stalled?.length ? { stalled } : {}, ...review?.length ? { review } : {}, ...assigned?.length ? { assigned } : {} };
170
179
  if (BRIEF) line(brief(waiting, reason, listeningAs(), goalId));
171
180
  else emit({ type: "sweep", reason, ...goalId ? { about: goalId } : {}, ...waiting });
172
- if (cmd && (deliveries.length || waiting.review?.length || waiting.assigned?.length || reason === "boot" && waiting.stalled?.length)) {
173
- spawn(cmd, { shell: true, stdio: "inherit", env: { ...process.env, ...launchEnv(waiting, reason, goalId) } });
181
+ if (deliveries.length || waiting.review?.length || waiting.assigned?.length || reason === "boot" && waiting.stalled?.length) {
182
+ let unreadable = false;
183
+ const reviews = await Promise.all((review ?? []).map(async ({ goalId: id }) => {
184
+ try {
185
+ const g = await getGoal(id);
186
+ return [
187
+ `review:${id}`,
188
+ ...(g.entries ?? []).filter((e) => participant ? e.authorParticipant !== participant : e.authorParticipant.startsWith("human:")).map((e) => `entry:${e.entryId}:${e.createdAt}`),
189
+ ...(g.answers ?? []).map((a) => `answer:${a.decisionNeedId}:${a.acceptedAt}`)
190
+ ];
191
+ } catch (error) {
192
+ unreadable = true;
193
+ emit({ type: "error", reason: "review_read", goalId: id, message: error.message });
194
+ return [`review:${id}`];
195
+ }
196
+ }));
197
+ const fingerprints = unreadable ? void 0 : [
198
+ ...rows.map((d) => createHash("sha256").update(JSON.stringify(d)).digest("hex")),
199
+ ...reviews.flat(),
200
+ ...(assigned ?? []).map((g) => `assigned:${g.goalId}`),
201
+ ...!rows.length && !reviews.length && !assigned?.length ? (stalled ?? []).map((g) => `stalled:${g.goalId}:${g.since}`) : []
202
+ ];
203
+ const message = `Paigy has waiting work${goalId ? ` on Goal ${goalId}` : ""}. Read contact({ wait: false }) and the relevant Goal conversation, handle new user input, and acknowledge (contact({ ackEventIds })) only events actually handled. Preserve this session's current task; do not start unrelated old work. This wake is not new authorization.`;
204
+ await bridge.deliver(fingerprints, message, launchEnv(waiting, reason, goalId));
205
+ } else if (bridge.status().target.kind === "codex") {
206
+ await bridge.deliver([], "", {});
174
207
  }
175
208
  } catch (e) {
176
209
  if (BRIEF) line(`Paigy \xB7 error \xB7 ${e.message}`);
@@ -180,23 +213,57 @@ async function sweep(reason, goalId) {
180
213
  function catchUpReason(joins) {
181
214
  return joins > 1 ? "resubscribed" : null;
182
215
  }
216
+ function coalesceSweeps(run) {
217
+ let running;
218
+ let pending;
219
+ return (reason, goalId) => {
220
+ pending = { reason, goalId };
221
+ if (running) return running;
222
+ running = (async () => {
223
+ try {
224
+ while (pending) {
225
+ const next = pending;
226
+ pending = void 0;
227
+ await run(next.reason, next.goalId);
228
+ }
229
+ } finally {
230
+ running = void 0;
231
+ }
232
+ })();
233
+ return running;
234
+ };
235
+ }
183
236
  async function main() {
184
- const sub = await subscribeWake((nudge) => void sweep(`wake:${nudge.kind ?? "?"}`, nudge.parentId), {
237
+ if (harnessDriven(process.env)) {
238
+ emit({ type: "listening", via: "harness", message: "The harness already delivers; no second listener started." });
239
+ return;
240
+ }
241
+ const slot = listenerKey(agentName(), process.env);
242
+ const existing = existingListener(agentName(), process.env);
243
+ if (existing) {
244
+ emit({ type: "receiving", pid: existing, message: "Listener already running; use listen to inspect its wake status." });
245
+ return;
246
+ }
247
+ const bridge = new WakeBridge(process.env, wakeStatusPath(slot));
248
+ await bridge.prepare().catch((error) => emit({ type: "wake_error", message: error.message }));
249
+ let participant;
250
+ const requestSweep = coalesceSweeps((reason, goalId) => sweep(reason, goalId, bridge, participant));
251
+ const sub = await subscribeWake((nudge) => void requestSweep(`wake:${nudge.kind ?? "?"}`, nudge.parentId), {
185
252
  release: RELEASE,
186
253
  onJoined: (joins) => {
187
254
  const reason = catchUpReason(joins);
188
- if (reason) void sweep(reason);
255
+ if (reason) void requestSweep(reason);
189
256
  }
190
257
  });
191
- const slot = agentName();
258
+ participant = `agent:${sub.tokenId}`;
192
259
  writeListenMark(slot, process.pid);
193
260
  process.on("exit", () => removeListenMark(slot));
194
- if (!BRIEF) emit({ type: "listening", channel: sub.channel });
195
- await sweep("boot");
196
- const heartbeat = setInterval(() => void sweep("timer"), SWEEP_EVERY_MS);
197
- heartbeat.unref?.();
261
+ if (!BRIEF) emit({ type: "listening", channel: sub.channel, wake: bridge.status() });
262
+ await requestSweep("boot");
263
+ const heartbeat2 = setInterval(() => void requestSweep("timer"), SWEEP_EVERY_MS);
264
+ heartbeat2.unref?.();
198
265
  const shutdown = async () => {
199
- clearInterval(heartbeat);
266
+ clearInterval(heartbeat2);
200
267
  removeListenMark(slot);
201
268
  await sub.close();
202
269
  process.exit(0);
@@ -231,6 +298,7 @@ export {
231
298
  SWEEP_EVERY_MS,
232
299
  brief,
233
300
  catchUpReason,
301
+ coalesceSweeps,
234
302
  launchEnv,
235
303
  leadOf,
236
304
  listenOptions,
package/dist/onboard.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  resolvePairing,
4
4
  startPairing,
5
5
  suggestedAgentName
6
- } from "./chunk-BNMMRKEY.js";
6
+ } from "./chunk-2ROD77AW.js";
7
7
  import {
8
8
  autoConfigureClients,
9
9
  claudeInstallHint,
10
10
  openBrowser
11
- } from "./chunk-HKODQKUV.js";
12
- import "./chunk-JLRBZZNT.js";
11
+ } from "./chunk-UAVXYNLV.js";
12
+ import "./chunk-GHSB2VP6.js";
13
13
  import {
14
14
  TOKEN_PATH,
15
15
  agentName,
@@ -20,7 +20,7 @@ import {
20
20
  saveToken,
21
21
  setIdentity,
22
22
  whoAmI
23
- } from "./chunk-PR7ROBN4.js";
23
+ } from "./chunk-EJYXBEWN.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
  agentName
4
- } from "./chunk-PR7ROBN4.js";
4
+ } from "./chunk-EJYXBEWN.js";
5
5
 
6
6
  // src/slot.ts
7
7
  process.stdout.write(agentName());
package/dist/stalled.js CHANGED
@@ -15,7 +15,7 @@ function stopReply(stalled, event = "Stop") {
15
15
  if (!stalled.length) return null;
16
16
  const list = stalled.slice(0, 8).map((g) => `"${g.title}" (${g.goalId})`).join(", ");
17
17
  const more = stalled.length > 8 ? ` and ${stalled.length - 8} more` : "";
18
- const reason = `Before you stop: ${stalled.length} of your Paigy Goals have had no progress for 3 days: ${list}${more}. For each, update_goal with progress, finish it, or cancel it.`;
18
+ const reason = `Before you stop: ${stalled.length} of your Paigy Goals have had no progress for 3 days: ${list}${more}. For each, update_goal with progress, or finish or cancel it with manage_goals.`;
19
19
  return event === "AfterAgent" ? { decision: "block", reason, systemMessage: reason } : { decision: "block", reason };
20
20
  }
21
21
  async function main() {
@@ -29,8 +29,8 @@ async function main() {
29
29
  const dir = join(homedir(), ".paigy", "stalled-reminded");
30
30
  const mark = join(dir, `${session || "session"}-${day}`);
31
31
  if (existsSync(mark)) return;
32
- const { checkReplies } = await import("./dist-B7AOS5TG.js");
33
- const reply = stopReply((await checkReplies()).stalled ?? [], input.hook_event_name ?? "Stop");
32
+ const { receive } = await import("./dist-NMHU2UNG.js");
33
+ const reply = stopReply((await receive()).stalled ?? [], input.hook_event_name ?? "Stop");
34
34
  if (!reply) return;
35
35
  mkdirSync(dir, { recursive: true });
36
36
  writeFileSync(mark, "");
@@ -7,7 +7,7 @@ import {
7
7
  readToken,
8
8
  sessionSlot,
9
9
  slotName
10
- } from "./chunk-PR7ROBN4.js";
10
+ } from "./chunk-EJYXBEWN.js";
11
11
 
12
12
  // src/statusline.ts
13
13
  import { realpathSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paigy/mcp",
3
- "version": "0.40.23",
3
+ "version": "0.40.25",
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",