@paigy/mcp 0.40.11 → 0.40.15
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 +35 -9
- package/dist/{chunk-FQVK7SO4.js → chunk-37FS33UP.js} +56 -5
- package/dist/{chunk-H5GGWCPS.js → chunk-PHTQITTC.js} +835 -498
- package/dist/{chunk-I5QINUN6.js → chunk-SE2JCKDI.js} +593 -454
- package/dist/{chunk-XIHVHYDU.js → chunk-X6G7XXCP.js} +1 -1
- package/dist/dist-DKP3DJQJ.js +110 -0
- package/dist/enable.js +9 -4
- package/dist/index.js +29 -5
- package/dist/listen.js +48 -16
- package/dist/onboard.js +4 -4
- package/dist/slot.js +1 -1
- package/dist/stalled.js +35 -0
- package/dist/statusline.js +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AGENT_TOOLS,
|
|
3
|
+
AGENT_TOOL_NAMES,
|
|
4
|
+
AWAIT_WINDOW_MS,
|
|
5
|
+
ApiError,
|
|
6
|
+
BACKEND_URL,
|
|
7
|
+
KEY_PATH,
|
|
8
|
+
NETWORK_MSG,
|
|
9
|
+
NotifyRequestSchema,
|
|
10
|
+
PROTO,
|
|
11
|
+
TOKEN_PATH,
|
|
12
|
+
UnpairedError,
|
|
13
|
+
acceptTriage,
|
|
14
|
+
agentName,
|
|
15
|
+
authToken,
|
|
16
|
+
checkReplies,
|
|
17
|
+
claimGoal,
|
|
18
|
+
claimSessions,
|
|
19
|
+
contact,
|
|
20
|
+
createGoal,
|
|
21
|
+
currentRepo,
|
|
22
|
+
deleteToken,
|
|
23
|
+
dismissTriage,
|
|
24
|
+
getGoal,
|
|
25
|
+
getTriage,
|
|
26
|
+
hatch,
|
|
27
|
+
heartbeat,
|
|
28
|
+
isNetworkError,
|
|
29
|
+
listConnections,
|
|
30
|
+
listNotes,
|
|
31
|
+
listSlots,
|
|
32
|
+
overrideToken,
|
|
33
|
+
parseDue,
|
|
34
|
+
pollToken,
|
|
35
|
+
reach,
|
|
36
|
+
reachAs,
|
|
37
|
+
readToken,
|
|
38
|
+
registerDelivery,
|
|
39
|
+
repoFromRemote,
|
|
40
|
+
requestCode,
|
|
41
|
+
revokeToken,
|
|
42
|
+
runTool,
|
|
43
|
+
saveToken,
|
|
44
|
+
sessionId,
|
|
45
|
+
sessionSlot,
|
|
46
|
+
setIdentity,
|
|
47
|
+
sleep,
|
|
48
|
+
slotIdentity,
|
|
49
|
+
slotName,
|
|
50
|
+
submitTriage,
|
|
51
|
+
subscribeWake,
|
|
52
|
+
updateGoal,
|
|
53
|
+
updateSlot,
|
|
54
|
+
whoAmI
|
|
55
|
+
} from "./chunk-PHTQITTC.js";
|
|
56
|
+
export {
|
|
57
|
+
AGENT_TOOLS,
|
|
58
|
+
AGENT_TOOL_NAMES,
|
|
59
|
+
AWAIT_WINDOW_MS,
|
|
60
|
+
ApiError,
|
|
61
|
+
BACKEND_URL,
|
|
62
|
+
KEY_PATH,
|
|
63
|
+
NETWORK_MSG,
|
|
64
|
+
NotifyRequestSchema,
|
|
65
|
+
PROTO,
|
|
66
|
+
TOKEN_PATH,
|
|
67
|
+
UnpairedError,
|
|
68
|
+
acceptTriage,
|
|
69
|
+
agentName,
|
|
70
|
+
authToken,
|
|
71
|
+
checkReplies,
|
|
72
|
+
claimGoal,
|
|
73
|
+
claimSessions,
|
|
74
|
+
contact,
|
|
75
|
+
createGoal,
|
|
76
|
+
currentRepo,
|
|
77
|
+
deleteToken,
|
|
78
|
+
dismissTriage,
|
|
79
|
+
getGoal,
|
|
80
|
+
getTriage,
|
|
81
|
+
hatch,
|
|
82
|
+
heartbeat,
|
|
83
|
+
isNetworkError,
|
|
84
|
+
listConnections,
|
|
85
|
+
listNotes,
|
|
86
|
+
listSlots,
|
|
87
|
+
overrideToken,
|
|
88
|
+
parseDue,
|
|
89
|
+
pollToken,
|
|
90
|
+
reach,
|
|
91
|
+
reachAs,
|
|
92
|
+
readToken,
|
|
93
|
+
registerDelivery,
|
|
94
|
+
repoFromRemote,
|
|
95
|
+
requestCode,
|
|
96
|
+
revokeToken,
|
|
97
|
+
runTool,
|
|
98
|
+
saveToken,
|
|
99
|
+
sessionId,
|
|
100
|
+
sessionSlot,
|
|
101
|
+
setIdentity,
|
|
102
|
+
sleep,
|
|
103
|
+
slotIdentity,
|
|
104
|
+
slotName,
|
|
105
|
+
submitTriage,
|
|
106
|
+
subscribeWake,
|
|
107
|
+
updateGoal,
|
|
108
|
+
updateSlot,
|
|
109
|
+
whoAmI
|
|
110
|
+
};
|
package/dist/enable.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
PAIGY_TOOL_IDS,
|
|
4
|
-
enablePaigyTools
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import "./chunk-
|
|
4
|
+
enablePaigyTools,
|
|
5
|
+
installSessionListening
|
|
6
|
+
} from "./chunk-37FS33UP.js";
|
|
7
|
+
import "./chunk-SE2JCKDI.js";
|
|
8
|
+
import "./chunk-PHTQITTC.js";
|
|
8
9
|
|
|
9
10
|
// src/enable.ts
|
|
10
11
|
function main() {
|
|
@@ -52,5 +53,9 @@ function main() {
|
|
|
52
53
|
if (result.already.length && result.added.length) {
|
|
53
54
|
console.log(` (${result.already.length} already present)`);
|
|
54
55
|
}
|
|
56
|
+
for (const hook of installSessionListening()) {
|
|
57
|
+
if (!hook.ok) console.log(` ! ${hook.harness}: ${hook.why}`);
|
|
58
|
+
else console.log(`\u2713 ${hook.harness} sessions will be told to listen (${hook.path})${hook.already ? " \u2014 already set" : ""}`);
|
|
59
|
+
}
|
|
55
60
|
}
|
|
56
61
|
main();
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
resolvePairing,
|
|
6
6
|
startPairing,
|
|
7
7
|
suggestedAgentName
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-X6G7XXCP.js";
|
|
9
9
|
import {
|
|
10
10
|
ENABLE_COMMAND,
|
|
11
11
|
OnboardSchema,
|
|
@@ -14,8 +14,11 @@ import {
|
|
|
14
14
|
SERVER_INSTRUCTIONS,
|
|
15
15
|
TOOLS,
|
|
16
16
|
paigyToolsAllowlisted
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import
|
|
17
|
+
} from "./chunk-37FS33UP.js";
|
|
18
|
+
import {
|
|
19
|
+
decideListen,
|
|
20
|
+
listenerAlive
|
|
21
|
+
} from "./chunk-SE2JCKDI.js";
|
|
19
22
|
import {
|
|
20
23
|
clearSurface,
|
|
21
24
|
writeSurface
|
|
@@ -32,10 +35,11 @@ import {
|
|
|
32
35
|
revokeToken,
|
|
33
36
|
runTool,
|
|
34
37
|
saveToken,
|
|
38
|
+
sessionId,
|
|
35
39
|
setIdentity,
|
|
36
40
|
slotName,
|
|
37
41
|
whoAmI
|
|
38
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-PHTQITTC.js";
|
|
39
43
|
|
|
40
44
|
// src/index.ts
|
|
41
45
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -44,6 +48,7 @@ import {
|
|
|
44
48
|
CallToolRequestSchema,
|
|
45
49
|
ListToolsRequestSchema
|
|
46
50
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
51
|
+
import { fileURLToPath } from "url";
|
|
47
52
|
import qrcode from "qrcode-generator";
|
|
48
53
|
var JOIN_CAP_MS = 45e3;
|
|
49
54
|
function pairedResult(token, sas, note) {
|
|
@@ -205,7 +210,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
205
210
|
return await handleTool(request, extra?.signal);
|
|
206
211
|
} catch (e) {
|
|
207
212
|
if (e instanceof UnpairedError) {
|
|
208
|
-
const IDENTITY_TOOLS = /* @__PURE__ */ new Set(["pair", "onboard", "unpair"]);
|
|
213
|
+
const IDENTITY_TOOLS = /* @__PURE__ */ new Set(["pair", "onboard", "unpair", "listen"]);
|
|
209
214
|
const hatched = IDENTITY_TOOLS.has(request.params.name) ? null : await hatchUnderDevice();
|
|
210
215
|
if (hatched) return await handleTool(request, extra?.signal);
|
|
211
216
|
if (listSlots().includes("Desktop")) return unidentifiedResult();
|
|
@@ -304,6 +309,25 @@ async function handleTool(request, signal) {
|
|
|
304
309
|
}]
|
|
305
310
|
};
|
|
306
311
|
}
|
|
312
|
+
// AM I LISTENING? (#2265) Decides and hands over — `listening.ts` owns the rule and the four
|
|
313
|
+
// answers. The facts are read here, once: the harness's session mark, a token to listen as,
|
|
314
|
+
// a live listener's mark for this slot, and where THIS server's node and daemon live. The
|
|
315
|
+
// daemon is the `listen.js` beside our own entry, so the command never resolves a package.
|
|
316
|
+
case "listen": {
|
|
317
|
+
const slot = agentName();
|
|
318
|
+
const pid = listenerAlive(slot);
|
|
319
|
+
const decision = decideListen({
|
|
320
|
+
env: process.env,
|
|
321
|
+
token: !!readToken(),
|
|
322
|
+
pidAlive: pid !== null,
|
|
323
|
+
...pid !== null ? { pid } : {},
|
|
324
|
+
execPath: process.execPath,
|
|
325
|
+
listenJs: fileURLToPath(new URL("./listen.js", import.meta.url)),
|
|
326
|
+
slot,
|
|
327
|
+
session: sessionId()
|
|
328
|
+
});
|
|
329
|
+
return { content: [{ type: "text", text: JSON.stringify(decision) }] };
|
|
330
|
+
}
|
|
307
331
|
default: {
|
|
308
332
|
const name = request.params.name;
|
|
309
333
|
const result = await runTool(name, request.params.arguments ?? {}, { waits: true, signal });
|
package/dist/listen.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
entryWords
|
|
4
|
-
|
|
3
|
+
entryWords,
|
|
4
|
+
removeListenMark,
|
|
5
|
+
writeListenMark
|
|
6
|
+
} from "./chunk-SE2JCKDI.js";
|
|
5
7
|
import {
|
|
8
|
+
agentName,
|
|
6
9
|
checkReplies,
|
|
7
10
|
contact,
|
|
8
11
|
getGoal,
|
|
12
|
+
slotName,
|
|
9
13
|
subscribeWake
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-PHTQITTC.js";
|
|
11
15
|
|
|
12
16
|
// src/listen.ts
|
|
13
17
|
import { spawn } from "child_process";
|
|
@@ -112,17 +116,35 @@ function uninstallService() {
|
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
// src/listen.ts
|
|
115
|
-
|
|
119
|
+
function listenOptions(argv) {
|
|
120
|
+
const brief2 = argv.includes("--brief");
|
|
121
|
+
return { brief: brief2, release: !brief2 };
|
|
122
|
+
}
|
|
123
|
+
var { brief: BRIEF, release: RELEASE } = listenOptions(process.argv);
|
|
124
|
+
var line = (text) => void process.stdout.write(text + "\n");
|
|
125
|
+
var emit = (obj) => line(JSON.stringify(obj));
|
|
126
|
+
var listeningAs = () => slotName(agentName()) ?? agentName();
|
|
116
127
|
function saidIn(delivery) {
|
|
117
128
|
return ("entries" in delivery ? delivery.entries : []).filter((entry) => entry.kind === "contribution").map((entry) => entryWords(entry)).filter(Boolean).join("\n");
|
|
118
129
|
}
|
|
130
|
+
function leadOf(deliveries, goalId) {
|
|
131
|
+
return (goalId ? deliveries.find((d) => d.goalIds.includes(goalId)) : void 0) ?? deliveries[0];
|
|
132
|
+
}
|
|
133
|
+
function brief(waiting, reason, as, goalId) {
|
|
134
|
+
const lead = leadOf(waiting.deliveries, goalId);
|
|
135
|
+
const stalled = waiting.stalled?.length ? ` \xB7 ${waiting.stalled.length} of your Goals stalled 3+ days: update, finish or cancel each` : "";
|
|
136
|
+
if (!lead) return (reason === "boot" ? `Paigy \xB7 listening as ${as} \xB7 nothing waiting` : `Paigy \xB7 ${reason} \xB7 nothing waiting`) + stalled;
|
|
137
|
+
const said = saidIn(lead) || ("about" in lead ? lead.about : "");
|
|
138
|
+
const shown = said.length > 160 ? `${said.slice(0, 160)}\u2026` : said;
|
|
139
|
+
const goal = waiting.goal?.goalId ?? lead.goalIds[0];
|
|
140
|
+
return `Paigy \xB7 ${reason} \xB7 ${waiting.deliveries.length} waiting \xB7 lead ${lead.deliveryId} on Goal ${goal}: "${shown}"${stalled}`;
|
|
141
|
+
}
|
|
119
142
|
function launchEnv(waiting, reason, goalId) {
|
|
120
143
|
const env = { PAIGY_WORK: JSON.stringify(waiting), PAIGY_EVENT: reason };
|
|
121
144
|
const put = (key, value) => {
|
|
122
145
|
if (value) env[key] = value;
|
|
123
146
|
};
|
|
124
|
-
const
|
|
125
|
-
const lead = named ?? waiting.deliveries[0];
|
|
147
|
+
const lead = leadOf(waiting.deliveries, goalId);
|
|
126
148
|
if (!lead) return env;
|
|
127
149
|
put("PAIGY_DELIVERY_ID", lead.deliveryId);
|
|
128
150
|
put("PAIGY_GOAL_ID", waiting.goal?.goalId ?? lead.goalIds[0]);
|
|
@@ -132,26 +154,32 @@ function launchEnv(waiting, reason, goalId) {
|
|
|
132
154
|
async function sweep(reason, goalId) {
|
|
133
155
|
try {
|
|
134
156
|
const cmd = process.env.PAIGY_ON_WAKE;
|
|
135
|
-
const { deliveries: rows } = await checkReplies();
|
|
136
|
-
const lead = (
|
|
137
|
-
const full = lead ? await contact({ deliveryId: lead.deliveryId }, { waits: false }).catch(() => null) : null;
|
|
157
|
+
const { deliveries: rows, stalled } = await checkReplies();
|
|
158
|
+
const lead = leadOf(rows, goalId);
|
|
159
|
+
const full = lead ? await contact({ deliveryId: lead.deliveryId }, { waits: false }).then((d) => "recorded" in d ? null : d).catch(() => null) : null;
|
|
138
160
|
const deliveries = rows.map((d) => d === lead && full ? full : d);
|
|
139
161
|
const leadGoalId = lead?.goalIds[0];
|
|
140
162
|
const goal = leadGoalId ? await getGoal(leadGoalId).then((g) => ({ goalId: leadGoalId, progress: g.progress })).catch(() => null) : null;
|
|
141
|
-
const waiting = { deliveries, goal };
|
|
142
|
-
|
|
143
|
-
|
|
163
|
+
const waiting = { deliveries, goal, ...stalled?.length ? { stalled } : {} };
|
|
164
|
+
if (BRIEF) line(brief(waiting, reason, listeningAs(), goalId));
|
|
165
|
+
else emit({ type: "sweep", reason, ...goalId ? { about: goalId } : {}, ...waiting });
|
|
166
|
+
if (cmd && (deliveries.length || reason === "boot" && waiting.stalled?.length)) {
|
|
144
167
|
spawn(cmd, { shell: true, stdio: "inherit", env: { ...process.env, ...launchEnv(waiting, reason, goalId) } });
|
|
145
168
|
}
|
|
146
169
|
} catch (e) {
|
|
147
|
-
|
|
170
|
+
if (BRIEF) line(`Paigy \xB7 error \xB7 ${e.message}`);
|
|
171
|
+
else emit({ type: "error", reason, message: e.message });
|
|
148
172
|
}
|
|
149
173
|
}
|
|
150
174
|
async function main() {
|
|
151
|
-
const sub = await subscribeWake((nudge) => void sweep(`wake:${nudge.kind ?? "?"}`, nudge.parentId));
|
|
152
|
-
|
|
175
|
+
const sub = await subscribeWake((nudge) => void sweep(`wake:${nudge.kind ?? "?"}`, nudge.parentId), { release: RELEASE });
|
|
176
|
+
const slot = agentName();
|
|
177
|
+
writeListenMark(slot, process.pid);
|
|
178
|
+
process.on("exit", () => removeListenMark(slot));
|
|
179
|
+
if (!BRIEF) emit({ type: "listening", channel: sub.channel });
|
|
153
180
|
await sweep("boot");
|
|
154
181
|
const shutdown = async () => {
|
|
182
|
+
removeListenMark(slot);
|
|
155
183
|
await sub.close();
|
|
156
184
|
process.exit(0);
|
|
157
185
|
};
|
|
@@ -175,13 +203,17 @@ if (isEntry()) {
|
|
|
175
203
|
emit({ type: "uninstalled", unit: uninstallService() });
|
|
176
204
|
} else {
|
|
177
205
|
main().catch((e) => {
|
|
178
|
-
|
|
206
|
+
if (BRIEF) line(`Paigy \xB7 error \xB7 ${e.message}`);
|
|
207
|
+
else emit({ type: "fatal", message: e.message });
|
|
179
208
|
process.exit(1);
|
|
180
209
|
});
|
|
181
210
|
}
|
|
182
211
|
}
|
|
183
212
|
export {
|
|
213
|
+
brief,
|
|
184
214
|
launchEnv,
|
|
215
|
+
leadOf,
|
|
216
|
+
listenOptions,
|
|
185
217
|
saidIn,
|
|
186
218
|
sweep
|
|
187
219
|
};
|
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-X6G7XXCP.js";
|
|
7
7
|
import {
|
|
8
8
|
autoConfigureClients,
|
|
9
9
|
claudeInstallHint,
|
|
10
10
|
openBrowser
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-37FS33UP.js";
|
|
12
|
+
import "./chunk-SE2JCKDI.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-PHTQITTC.js";
|
|
24
24
|
|
|
25
25
|
// src/onboard.ts
|
|
26
26
|
function reportRegistered() {
|
package/dist/slot.js
CHANGED
package/dist/stalled.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/stalled.ts
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
+
import { homedir } from "os";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
function stopReply(stalled) {
|
|
8
|
+
if (!stalled.length) return null;
|
|
9
|
+
const list = stalled.slice(0, 8).map((g) => `"${g.title}" (${g.goalId})`).join(", ");
|
|
10
|
+
const more = stalled.length > 8 ? ` and ${stalled.length - 8} more` : "";
|
|
11
|
+
return {
|
|
12
|
+
decision: "block",
|
|
13
|
+
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.`
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function main() {
|
|
17
|
+
const input = JSON.parse(readFileSync(0, "utf8") || "{}");
|
|
18
|
+
if (input.stop_hook_active) return;
|
|
19
|
+
const session = input.session_id ?? "";
|
|
20
|
+
if (session) process.env.PAIGY_SESSION_ID = session;
|
|
21
|
+
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
22
|
+
const dir = join(homedir(), ".paigy", "stalled-reminded");
|
|
23
|
+
const mark = join(dir, `${session || "session"}-${day}`);
|
|
24
|
+
if (existsSync(mark)) return;
|
|
25
|
+
const { checkReplies } = await import("./dist-DKP3DJQJ.js");
|
|
26
|
+
const reply = stopReply((await checkReplies()).stalled ?? []);
|
|
27
|
+
if (!reply) return;
|
|
28
|
+
mkdirSync(dir, { recursive: true });
|
|
29
|
+
writeFileSync(mark, "");
|
|
30
|
+
process.stdout.write(JSON.stringify(reply));
|
|
31
|
+
}
|
|
32
|
+
if (process.argv[1] && /stalled(\.[jt]s)?$/.test(process.argv[1])) main().catch(() => void 0);
|
|
33
|
+
export {
|
|
34
|
+
stopReply
|
|
35
|
+
};
|
package/dist/statusline.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paigy/mcp",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.15",
|
|
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",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"paigy-listen": "dist/listen.js",
|
|
12
12
|
"paigy-statusline": "dist/statusline.js",
|
|
13
13
|
"paigy-enable-tools": "dist/enable.js",
|
|
14
|
-
"paigy-slot": "dist/slot.js"
|
|
14
|
+
"paigy-slot": "dist/slot.js",
|
|
15
|
+
"paigy-stalled": "dist/stalled.js"
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"dist"
|