@paigy/mcp 0.40.23 → 0.40.24
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 +29 -16
- package/dist/{chunk-HKODQKUV.js → chunk-J7T3EB5Y.js} +9 -9
- package/dist/chunk-RK5LT7NH.js +110 -0
- package/dist/{chunk-BNMMRKEY.js → chunk-TP7DM2MP.js} +1 -1
- package/dist/{chunk-JLRBZZNT.js → chunk-VUKR2E24.js} +676 -498
- package/dist/{chunk-PR7ROBN4.js → chunk-WR2M3RME.js} +720 -522
- package/dist/{dist-B7AOS5TG.js → dist-EKLTLANV.js} +7 -3
- package/dist/enable.js +3 -3
- package/dist/index.js +18 -7
- package/dist/listen.js +83 -15
- package/dist/onboard.js +4 -4
- package/dist/slot.js +1 -1
- package/dist/stalled.js +1 -1
- package/dist/statusline.js +1 -1
- package/package.json +1 -1
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
saveToken,
|
|
51
51
|
sessionId,
|
|
52
52
|
sessionSlot,
|
|
53
|
+
setClient,
|
|
53
54
|
setIdentity,
|
|
54
55
|
sleep,
|
|
55
56
|
slotIdentity,
|
|
@@ -59,8 +60,9 @@ import {
|
|
|
59
60
|
updateGoal,
|
|
60
61
|
updateSlot,
|
|
61
62
|
whoAmI,
|
|
62
|
-
whoIsWorking
|
|
63
|
-
|
|
63
|
+
whoIsWorking,
|
|
64
|
+
withCodexEnv
|
|
65
|
+
} from "./chunk-WR2M3RME.js";
|
|
64
66
|
export {
|
|
65
67
|
AGENT_TOOLS,
|
|
66
68
|
AGENT_TOOL_NAMES,
|
|
@@ -113,6 +115,7 @@ export {
|
|
|
113
115
|
saveToken,
|
|
114
116
|
sessionId,
|
|
115
117
|
sessionSlot,
|
|
118
|
+
setClient,
|
|
116
119
|
setIdentity,
|
|
117
120
|
sleep,
|
|
118
121
|
slotIdentity,
|
|
@@ -122,5 +125,6 @@ export {
|
|
|
122
125
|
updateGoal,
|
|
123
126
|
updateSlot,
|
|
124
127
|
whoAmI,
|
|
125
|
-
whoIsWorking
|
|
128
|
+
whoIsWorking,
|
|
129
|
+
withCodexEnv
|
|
126
130
|
};
|
package/dist/enable.js
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
PAIGY_TOOL_IDS,
|
|
4
4
|
enablePaigyTools,
|
|
5
5
|
installSessionListening
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-J7T3EB5Y.js";
|
|
7
|
+
import "./chunk-VUKR2E24.js";
|
|
8
|
+
import "./chunk-WR2M3RME.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-
|
|
12
|
+
} from "./chunk-TP7DM2MP.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-
|
|
21
|
+
} from "./chunk-J7T3EB5Y.js";
|
|
19
22
|
import {
|
|
20
23
|
decideListen,
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
existingListener,
|
|
25
|
+
listenerKey,
|
|
26
|
+
wakeStatusPath
|
|
27
|
+
} from "./chunk-VUKR2E24.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-
|
|
48
|
+
} from "./chunk-WR2M3RME.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:
|
|
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
|
|
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-
|
|
13
|
+
} from "./chunk-VUKR2E24.js";
|
|
7
14
|
import {
|
|
8
15
|
agentName,
|
|
9
16
|
checkReplies,
|
|
10
17
|
contact,
|
|
11
18
|
getGoal,
|
|
19
|
+
heartbeat,
|
|
12
20
|
slotName,
|
|
13
21
|
subscribeWake
|
|
14
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-WR2M3RME.js";
|
|
15
23
|
|
|
16
24
|
// src/listen.ts
|
|
17
|
-
import {
|
|
25
|
+
import { createHash } from "crypto";
|
|
18
26
|
import { realpathSync } from "fs";
|
|
19
27
|
import { fileURLToPath } from "url";
|
|
20
28
|
|
|
@@ -157,9 +165,10 @@ 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
|
-
|
|
170
|
+
void Promise.resolve().then(() => heartbeat(void 0, { listening: true })).catch(() => {
|
|
171
|
+
});
|
|
163
172
|
const { deliveries: rows, stalled, review, assigned } = await checkReplies();
|
|
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;
|
|
@@ -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 (
|
|
173
|
-
|
|
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 check_replies and the relevant Goal conversation, handle new user input, and acknowledge only evidence 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
|
-
|
|
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
|
|
255
|
+
if (reason) void requestSweep(reason);
|
|
189
256
|
}
|
|
190
257
|
});
|
|
191
|
-
|
|
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
|
|
196
|
-
const
|
|
197
|
-
|
|
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(
|
|
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-
|
|
6
|
+
} from "./chunk-TP7DM2MP.js";
|
|
7
7
|
import {
|
|
8
8
|
autoConfigureClients,
|
|
9
9
|
claudeInstallHint,
|
|
10
10
|
openBrowser
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-J7T3EB5Y.js";
|
|
12
|
+
import "./chunk-VUKR2E24.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-
|
|
23
|
+
} from "./chunk-WR2M3RME.js";
|
|
24
24
|
|
|
25
25
|
// src/onboard.ts
|
|
26
26
|
function reportRegistered() {
|
package/dist/slot.js
CHANGED
package/dist/stalled.js
CHANGED
|
@@ -29,7 +29,7 @@ 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-
|
|
32
|
+
const { checkReplies } = await import("./dist-EKLTLANV.js");
|
|
33
33
|
const reply = stopReply((await checkReplies()).stalled ?? [], input.hook_event_name ?? "Stop");
|
|
34
34
|
if (!reply) return;
|
|
35
35
|
mkdirSync(dir, { recursive: true });
|
package/dist/statusline.js
CHANGED
package/package.json
CHANGED