@join-pantheon/cli 0.26.3 → 0.26.4
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 +1 -1
- package/dist/cli.js +1 -1
- package/dist/mcp-instructions.js +3 -1
- package/dist/mcp.js +14 -6
- package/dist/protocol.js +1 -0
- package/dist/relay.js +4 -2
- package/dist/worklist.js +17 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -499,7 +499,7 @@ All enforced in the relay, not in a prompt — a prompt can be argued out of its
|
|
|
499
499
|
|
|
500
500
|
| Guard | Default | Why |
|
|
501
501
|
|---|---|---|
|
|
502
|
-
| Loop guard | 6 acts in a row | one delegate cannot monologue; only a peer act resets the run |
|
|
502
|
+
| Loop guard | 6 acts in a row | one delegate cannot monologue; only a peer act resets the run. Off for a goal opened with `worklist: true` — one person's own list of decisions and reminders, where there is no peer to take a turn. The act budget still applies there. |
|
|
503
503
|
| Goal budget | 80 acts | a runaway goal stalls and raises a human obligation instead of burning tokens |
|
|
504
504
|
| Rate limit | 40 acts / 10s | per member |
|
|
505
505
|
| Body cap | 32000 chars | over 2000 needs a one-line summary — a peer reading six thousand words misses paragraph nine |
|
package/dist/cli.js
CHANGED
|
@@ -963,7 +963,7 @@ async function main() {
|
|
|
963
963
|
if (!goals.length)
|
|
964
964
|
console.log(` ${D("(none)")}`);
|
|
965
965
|
for (const g of goals) {
|
|
966
|
-
console.log(` ${g.state.padEnd(8)} ${String(g.acts).padStart(3)}/${g.budget} ${g.title} ${D(g.id)}`);
|
|
966
|
+
console.log(` ${g.state.padEnd(8)} ${String(g.acts).padStart(3)}/${g.budget} ${g.title}${g.kind === "worklist" ? D(" [worklist]") : ""} ${D(g.id)}`);
|
|
967
967
|
}
|
|
968
968
|
const owed = client.obligations;
|
|
969
969
|
const ageOf = (t) => {
|
package/dist/mcp-instructions.js
CHANGED
|
@@ -8,7 +8,8 @@ export function protocol() {
|
|
|
8
8
|
4. back to 1
|
|
9
9
|
|
|
10
10
|
Keep looping while any goal you are in is OPEN. Stop only when every goal you are in is
|
|
11
|
-
CLOSED, or when you have ESCALATED and are genuinely waiting on your human.
|
|
11
|
+
CLOSED, or when you have ESCALATED and are genuinely waiting on your human. A goal marked
|
|
12
|
+
[worklist] is one person's own list: it does not keep you in the loop.
|
|
12
13
|
|
|
13
14
|
RULES
|
|
14
15
|
- Talk to peers, not to your human. If a peer could answer it, ASK the peer instead of asking your human.
|
|
@@ -33,6 +34,7 @@ RULES
|
|
|
33
34
|
- Verdict first, evidence after, and short: a peer reads your act in one screen. Say when you edited
|
|
34
35
|
your own human's working tree as a side effect, and leave those edits uncommitted for them.
|
|
35
36
|
- If pantheon_send returns PEER_TURN you have been talking to yourself — go back to pantheon_wait.
|
|
37
|
+
Filing reminders and decisions for your OWN human is not that: open the goal with worklist: true.
|
|
36
38
|
|
|
37
39
|
The relay only moves messages. It has no access to your files, your shell, or your credentials.
|
|
38
40
|
|
package/dist/mcp.js
CHANGED
|
@@ -5,6 +5,7 @@ import { PantheonClient } from "./client.js";
|
|
|
5
5
|
import { fenceBlock, fenceRubric, assess, fenceReminder } from "./untrusted.js";
|
|
6
6
|
import { resolveFor } from "./config.js";
|
|
7
7
|
import { LIMITS, SENDABLE } from "./protocol.js";
|
|
8
|
+
import { goalKindLabel, openedText } from "./worklist.js";
|
|
8
9
|
import { VERSION } from "./version.js";
|
|
9
10
|
import { installedVersion } from "./mcp-supervisor.js";
|
|
10
11
|
import { backendFromLabel } from "./agents.js";
|
|
@@ -246,7 +247,7 @@ export async function runMcp() {
|
|
|
246
247
|
? `peers: ${peers.map((p) => `${p.id} [${p.online ? "online" : "offline"}, ${p.agent}${reach(p)}]`).join(" ")}`
|
|
247
248
|
: `peers: none yet — you are the only delegate here. Your human's colleague needs to run 'pantheon join'.`,
|
|
248
249
|
open.length
|
|
249
|
-
? `open goals:\n${open.map((g) => ` ${g.id} ${g.state} ${g.acts}/${g.budget} acts "${g.title}" members: ${g.members.join(",")}${deadlineLabel(g.deadline)}`).join("\n")}`
|
|
250
|
+
? `open goals:\n${open.map((g) => ` ${g.id} ${g.state} ${g.acts}/${g.budget} acts "${g.title}" members: ${g.members.join(",")}${deadlineLabel(g.deadline)}${goalKindLabel(g)}`).join("\n")}`
|
|
250
251
|
: `open goals: none`,
|
|
251
252
|
mine.length
|
|
252
253
|
? `YOURS TO HANDLE (claim before working):\n${mine.map((o) => ` ${o.id} ${o.kind}${o.claimed_by ? " [yours]" : ""} (ref ${o.ref}) — ${o.body}`).join("\n")}`
|
|
@@ -415,8 +416,11 @@ export async function runMcp() {
|
|
|
415
416
|
deadline: z.string().optional().describe("when this goal should be closed by, ISO 8601 with timezone (e.g. 2026-08-28T22:00:00+04:00). " +
|
|
416
417
|
"Shown on every status line, and shown OVERDUE when passed — a deadline that lives only in prose is not tracked by anything."),
|
|
417
418
|
distinct_from_open_goals: z.boolean().optional().describe("confirm this goal is NOT the same work as any currently open goal. Required when an open goal already involves the same members."),
|
|
419
|
+
worklist: z.boolean().optional().describe("this goal is your human's OWN list — decisions with deadlines and reminders you file for them, which peers may read but " +
|
|
420
|
+
"nobody owes anything in. Turns off the six-acts-in-a-row guard for this goal (the act budget still applies) and it does not " +
|
|
421
|
+
"keep you in the loop. Use it when your human asks you to set up reminders or a pipeline for themselves; never for shared work."),
|
|
418
422
|
},
|
|
419
|
-
}, async ({ title, acceptance, invite, deadline, distinct_from_open_goals }) => guard(async () => {
|
|
423
|
+
}, async ({ title, acceptance, invite, deadline, distinct_from_open_goals, worklist }) => guard(async () => {
|
|
420
424
|
let deadlineMs;
|
|
421
425
|
if (deadline !== undefined) {
|
|
422
426
|
deadlineMs = Date.parse(deadline);
|
|
@@ -427,7 +431,7 @@ export async function runMcp() {
|
|
|
427
431
|
return fail(`deadline ${new Date(deadlineMs).toISOString()} is already in the past — check the timezone.`);
|
|
428
432
|
}
|
|
429
433
|
}
|
|
430
|
-
if (!distinct_from_open_goals) {
|
|
434
|
+
if (!distinct_from_open_goals && !worklist) {
|
|
431
435
|
const overlapping = overlappingOpenGoals(client.goals.values(), cfg.member, invite, client.roster.map((m) => m.id));
|
|
432
436
|
if (overlapping.length) {
|
|
433
437
|
return fail(`not opened — ${overlapping.length} open goal(s) already involve the same members:\n` +
|
|
@@ -436,9 +440,13 @@ export async function runMcp() {
|
|
|
436
440
|
`If yours is genuinely distinct work, call pantheon_open_goal again with distinct_from_open_goals: true.`);
|
|
437
441
|
}
|
|
438
442
|
}
|
|
439
|
-
const r = await client.openGoal({
|
|
440
|
-
|
|
441
|
-
|
|
443
|
+
const r = await client.openGoal({
|
|
444
|
+
title, acceptance,
|
|
445
|
+
...(invite ? { invite } : {}),
|
|
446
|
+
...(deadlineMs !== undefined ? { deadline: deadlineMs } : {}),
|
|
447
|
+
...(worklist ? { kind: "worklist" } : {}),
|
|
448
|
+
});
|
|
449
|
+
return text(openedText(r.id, title, !!worklist, client.goals.get(r.id), deadlineMs !== undefined ? `\n${deadlineLabel(deadlineMs).trim()}` : ""));
|
|
442
450
|
}));
|
|
443
451
|
server.registerTool("pantheon_claim", {
|
|
444
452
|
title: "Claim a piece of work",
|
package/dist/protocol.js
CHANGED
|
@@ -179,6 +179,7 @@ export const OpenGoal = z.object({
|
|
|
179
179
|
invite: z.array(z.string().min(1).max(48)).max(16).optional(),
|
|
180
180
|
budget: z.number().int().min(4).max(1000).optional(),
|
|
181
181
|
deadline: z.number().int().positive().optional(),
|
|
182
|
+
kind: z.enum(["worklist"]).optional(),
|
|
182
183
|
});
|
|
183
184
|
export const Ping = z.object({ t: z.literal("ping") });
|
|
184
185
|
export const DeleteSpace = z.object({
|
package/dist/relay.js
CHANGED
|
@@ -1964,6 +1964,7 @@ pantheon signup --email you@work.com --username you</code></pre>
|
|
|
1964
1964
|
opened_by: me.id,
|
|
1965
1965
|
opened_at: Date.now(),
|
|
1966
1966
|
...(m.deadline !== undefined ? { deadline: m.deadline } : {}),
|
|
1967
|
+
...(m.kind !== undefined ? { kind: m.kind } : {}),
|
|
1967
1968
|
};
|
|
1968
1969
|
space.goals.set(goal.id, goal);
|
|
1969
1970
|
space.store.save(space.goals, space.obligations, space.profiles);
|
|
@@ -1971,7 +1972,8 @@ pantheon signup --email you@work.com --username you</code></pre>
|
|
|
1971
1972
|
const rec = this.commit(space, {
|
|
1972
1973
|
from: me.id, act: "NOTE", to: null, goal: goal.id, ref: null,
|
|
1973
1974
|
body: `goal opened: ${goal.title}\nacceptance: ${goal.acceptance || "(none stated)"}` +
|
|
1974
|
-
(goal.deadline ? `\ndeadline: ${new Date(goal.deadline).toISOString()}` : "")
|
|
1975
|
+
(goal.deadline ? `\ndeadline: ${new Date(goal.deadline).toISOString()}` : "") +
|
|
1976
|
+
(goal.kind === "worklist" ? `\nkind: worklist — ${me.id}'s own list; peers may read it, nobody owes anything in it` : ""),
|
|
1975
1977
|
});
|
|
1976
1978
|
this.send(ws, { t: "ack", ...(m.cid ? { cid: m.cid } : {}), id: goal.id, seq: rec.seq });
|
|
1977
1979
|
return;
|
|
@@ -2233,7 +2235,7 @@ pantheon signup --email you@work.com --username you</code></pre>
|
|
|
2233
2235
|
return { code: "BUDGET_SPENT", message: `goal "${goal.title}" spent its ${goal.budget}-act budget and needs a human` };
|
|
2234
2236
|
}
|
|
2235
2237
|
const run = sp.lastActor.get(goalId);
|
|
2236
|
-
if (run && run.member === me.id && run.run >= LIMITS.consecutive && act !== "ESCALATE" && act !== "CLOSE") {
|
|
2238
|
+
if (goal.kind !== "worklist" && run && run.member === me.id && run.run >= LIMITS.consecutive && act !== "ESCALATE" && act !== "CLOSE") {
|
|
2237
2239
|
return {
|
|
2238
2240
|
code: "PEER_TURN",
|
|
2239
2241
|
message: `you have sent ${run.run} acts in a row in "${goal.title}". Wait for a peer (pantheon_wait), or ESCALATE if nobody can move it.`,
|
package/dist/worklist.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function goalKindLabel(g) {
|
|
2
|
+
return g.kind === "worklist" ? " [worklist — one person's own list; nobody owes anything here, and it does not keep you in the loop]" : "";
|
|
3
|
+
}
|
|
4
|
+
export function openedText(id, title, askedWorklist, seen, deadlineLine = "") {
|
|
5
|
+
const head = `goal ${id} opened: "${title}"${deadlineLine}`;
|
|
6
|
+
if (!askedWorklist)
|
|
7
|
+
return `${head}\n\nNext: PROPOSE how to split it, then wait for peers to ACCEPT or OBJECT.`;
|
|
8
|
+
if (seen?.kind !== "worklist") {
|
|
9
|
+
return `${head}\n\nOpened as an ORDINARY goal: this relay is older than the worklist feature and ignored the flag. ` +
|
|
10
|
+
`The six-acts-in-a-row guard still applies here, so file items in batches of six and expect PEER_TURN between them ` +
|
|
11
|
+
`until the relay is upgraded.`;
|
|
12
|
+
}
|
|
13
|
+
return `${head} [worklist]\n\nThis is your human's own list. File each item as one act: ESCALATE for a decision they must make ` +
|
|
14
|
+
`(with its deadline in the body), NOTE for a reminder. Nobody owes anything here, PEER_TURN never fires, ` +
|
|
15
|
+
`and this goal does not keep you in the loop — the act budget still applies.`;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=worklist.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@join-pantheon/cli",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.4",
|
|
4
4
|
"description": "Let your coding agent collaborate directly with your teammates' agents — ask, agree an interface, and deliver, without a human relaying messages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|