passalong 0.8.0 → 0.9.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.
- package/bin/passalong +7 -3
- package/package.json +1 -1
- package/src/api.js +8 -4
- package/src/mcp.js +37 -15
- package/src/passalong.js +27 -6
package/bin/passalong
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// passalong work [--once] [--agent CMD] run an agent on each ready task here, one after another
|
|
13
13
|
// passalong approve <id> the work in review is done
|
|
14
14
|
// passalong reject <id> <why> not done: back to Ready, and the next agent reads why
|
|
15
|
-
// passalong release <id> take
|
|
15
|
+
// passalong release <id> take work back from whoever holds it, of any kind
|
|
16
16
|
// passalong attach <image> upload evidence and print the markdown that points at it
|
|
17
17
|
// passalong pull <id|link> fetch a guide into ./.passalong/ and print it
|
|
18
18
|
// passalong start <id|link> pull it and take it — one command for "I am doing this"
|
|
@@ -332,8 +332,12 @@ const commands = {
|
|
|
332
332
|
|
|
333
333
|
async release(f) {
|
|
334
334
|
const id = f._[0] || die("usage: passalong release <id>");
|
|
335
|
-
await passalong.
|
|
336
|
-
|
|
335
|
+
const r = await passalong.release(id).catch((e) => die(e.message));
|
|
336
|
+
const from = Number(r?.from) || 1;
|
|
337
|
+
console.error(
|
|
338
|
+
`${id} is back in Ready${from > 1 ? `, taken back from ${from} places` : ""}` +
|
|
339
|
+
" — whoever had it has been told",
|
|
340
|
+
);
|
|
337
341
|
},
|
|
338
342
|
|
|
339
343
|
async ready(f) {
|
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -176,8 +176,11 @@ export const setStatus = (id, status) =>
|
|
|
176
176
|
call(`/v1/guides/${id}/status`, { method: "PATCH", body: { status } });
|
|
177
177
|
export const remove = (id) => call(`/v1/guides/${id}`, { method: "DELETE" });
|
|
178
178
|
/** Does it actually work? `note` is required when it does not. */
|
|
179
|
-
export const verdict = (id, ok, note = "") =>
|
|
180
|
-
call(`/v1/guides/${id}/verdict`, {
|
|
179
|
+
export const verdict = (id, ok, note = "", detail = "") =>
|
|
180
|
+
call(`/v1/guides/${id}/verdict`, {
|
|
181
|
+
method: "PUT",
|
|
182
|
+
body: { ok, note, ...(detail ? { detail } : {}) },
|
|
183
|
+
});
|
|
181
184
|
|
|
182
185
|
export const tasks = () => call("/v1/tasks");
|
|
183
186
|
export const nextTask = (body) => call("/v1/tasks/next", { method: "POST", body });
|
|
@@ -189,8 +192,9 @@ export const approveTask = (id) =>
|
|
|
189
192
|
call(`/v1/tasks/${encodeURIComponent(id)}/approve`, { method: "POST", body: {} });
|
|
190
193
|
export const rejectTask = (id, why) =>
|
|
191
194
|
call(`/v1/tasks/${encodeURIComponent(id)}/reject`, { method: "POST", body: { why } });
|
|
192
|
-
|
|
193
|
-
|
|
195
|
+
/** Take work back from whoever holds it, of any kind. `/v1/tasks/…/release` is the old path. */
|
|
196
|
+
export const release = (id) =>
|
|
197
|
+
call(`/v1/guides/${encodeURIComponent(id)}/release`, { method: "POST", body: {} });
|
|
194
198
|
/** The four verbs every guide answers to. See docs/V2.md §11. */
|
|
195
199
|
export const working = () => call("/v1/working");
|
|
196
200
|
export const handedIn = () => call("/v1/handed_in");
|
package/src/mcp.js
CHANGED
|
@@ -326,7 +326,7 @@ export function buildServer() {
|
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
async function doHandIn({ id, ok, note, evidence, checks, markdown, report, pr, cwd }) {
|
|
329
|
+
async function doHandIn({ id, ok, note, evidence, checks, writeup, markdown, report, pr, cwd }) {
|
|
330
330
|
try {
|
|
331
331
|
// A check that names a command is run here, before anything is recorded, and its exit code
|
|
332
332
|
// decides it rather than the agent's account of it. A failure is refused with the command's
|
|
@@ -346,6 +346,7 @@ export function buildServer() {
|
|
|
346
346
|
note: note || "",
|
|
347
347
|
evidence: evidence || "",
|
|
348
348
|
checks: done.checks,
|
|
349
|
+
writeup: writeup || "",
|
|
349
350
|
markdown,
|
|
350
351
|
report,
|
|
351
352
|
pr: pr || "",
|
|
@@ -640,18 +641,22 @@ export function buildServer() {
|
|
|
640
641
|
outputSchema: handInOut,
|
|
641
642
|
annotations: ADDS,
|
|
642
643
|
description:
|
|
643
|
-
"Done here, with proof
|
|
644
|
-
"
|
|
645
|
-
"
|
|
646
|
-
"of output for the part that answers each
|
|
647
|
-
"
|
|
648
|
-
"
|
|
649
|
-
"
|
|
650
|
-
"
|
|
651
|
-
"transfer guide about what you did and decided —
|
|
652
|
-
"handoff or a bug takes `ok`, whether its
|
|
653
|
-
"went wrong when it did not.
|
|
654
|
-
"
|
|
644
|
+
"Done here, with proof, sorted against the line it answers. Send `checks`: one entry per " +
|
|
645
|
+
"line the guide asks for — `## Acceptance` on a task, `## Verification` on a handoff or a " +
|
|
646
|
+
"bug — each with that line and the evidence for it. That is what its author reads, line " +
|
|
647
|
+
"against line, instead of hunting through a wall of output for the part that answers each " +
|
|
648
|
+
"one, AND IT IS HOW YOU KNOW YOU ARE DONE: every line has one. Give a check `cmd` when a " +
|
|
649
|
+
"command proves it: the command is run here before the hand-in lands, a non-zero exit " +
|
|
650
|
+
"refuses it, and what it printed is recorded instead of your account of it. Use `ran` for " +
|
|
651
|
+
"a check no command can settle. `evidence` as one block is the older shape and still " +
|
|
652
|
+
"works. A task also takes `markdown`, a transfer guide about what you did and decided — " +
|
|
653
|
+
"this publishes it and attaches it. A handoff or a bug takes `ok`, whether its " +
|
|
654
|
+
"Verification held here, and `note` saying what went wrong when it did not. DO NOT " +
|
|
655
|
+
"publish a guide to carry your evidence: it belongs on this call, and a second document " +
|
|
656
|
+
'titled "Hand-in evidence" is the thing `checks` exists to replace. If it worked but you ' +
|
|
657
|
+
"had to adapt something, that goes in `writeup` and the next reader of the guide is shown " +
|
|
658
|
+
"it — that is its home. A follow-up guide is for work somebody else should now do, not " +
|
|
659
|
+
"for answering.",
|
|
655
660
|
inputSchema: {
|
|
656
661
|
id: z.string().describe("passalong id"),
|
|
657
662
|
evidence: z
|
|
@@ -664,7 +669,12 @@ export function buildServer() {
|
|
|
664
669
|
checks: z
|
|
665
670
|
.array(
|
|
666
671
|
z.object({
|
|
667
|
-
check: z
|
|
672
|
+
check: z
|
|
673
|
+
.string()
|
|
674
|
+
.describe(
|
|
675
|
+
"the line this answers, in the guide's own words: an Acceptance line on a task, " +
|
|
676
|
+
"a Verification line on a handoff or a bug",
|
|
677
|
+
),
|
|
668
678
|
ran: z
|
|
669
679
|
.string()
|
|
670
680
|
.optional()
|
|
@@ -681,9 +691,21 @@ export function buildServer() {
|
|
|
681
691
|
}),
|
|
682
692
|
)
|
|
683
693
|
.optional()
|
|
684
|
-
.describe(
|
|
694
|
+
.describe(
|
|
695
|
+
"one entry per line the guide asks for — Acceptance on a task, Verification on a " +
|
|
696
|
+
"handoff or a bug — in the order you worked them",
|
|
697
|
+
),
|
|
685
698
|
ok: z.boolean().optional().describe("handoff or bug: did its Verification hold"),
|
|
686
699
|
note: z.string().optional().describe("one line; required when ok is false"),
|
|
700
|
+
writeup: z
|
|
701
|
+
.string()
|
|
702
|
+
.optional()
|
|
703
|
+
.describe(
|
|
704
|
+
"handoff or bug: what you had to adapt to make it work here — a version, a name, a " +
|
|
705
|
+
"step that needed something the guide does not mention. Prose, and optional: leave " +
|
|
706
|
+
"it out when it worked as written. The next person to open the guide is shown it, " +
|
|
707
|
+
"which is why it does not need to be a guide of its own",
|
|
708
|
+
),
|
|
687
709
|
markdown: z
|
|
688
710
|
.string()
|
|
689
711
|
.optional()
|
package/src/passalong.js
CHANGED
|
@@ -412,6 +412,7 @@ export async function handIn(
|
|
|
412
412
|
note = "",
|
|
413
413
|
evidence = "",
|
|
414
414
|
checks = [],
|
|
415
|
+
writeup = "",
|
|
415
416
|
markdown,
|
|
416
417
|
report,
|
|
417
418
|
pr = "",
|
|
@@ -446,6 +447,9 @@ export async function handIn(
|
|
|
446
447
|
}
|
|
447
448
|
: {}),
|
|
448
449
|
...(report ? { report, pr } : {}),
|
|
450
|
+
// Left out when there is nothing to say, rather than sent as "": most hand-ins have nothing
|
|
451
|
+
// to adapt, and the field is for the ones that do.
|
|
452
|
+
...(writeup ? { writeup } : {}),
|
|
449
453
|
...(typeof ok === "boolean" ? { ok } : {}),
|
|
450
454
|
});
|
|
451
455
|
}
|
|
@@ -539,9 +543,16 @@ export async function rejectTask(id, why) {
|
|
|
539
543
|
return r;
|
|
540
544
|
}
|
|
541
545
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
546
|
+
/**
|
|
547
|
+
* Take it back from whoever is holding it — a task, a handoff or a bug, and from all of them at
|
|
548
|
+
* once when several people hold the same handoff in different repos.
|
|
549
|
+
*
|
|
550
|
+
* It was tasks only, which left an asymmetry nobody chose: the author of a handoff could mark it
|
|
551
|
+
* done or give it to somebody else, and had no way to simply have it back.
|
|
552
|
+
*/
|
|
553
|
+
export async function release(id) {
|
|
554
|
+
needsSync("taking work back");
|
|
555
|
+
const r = await api.release(id);
|
|
545
556
|
store.remove(id);
|
|
546
557
|
return r;
|
|
547
558
|
}
|
|
@@ -808,11 +819,21 @@ export async function activity({ all = false, limit = 50 } = {}) {
|
|
|
808
819
|
* `done` says "I implemented it", a verdict says "I tried it and it holds up" — or does not.
|
|
809
820
|
* A failing verdict needs a note; "it doesn't work" without a reason helps nobody.
|
|
810
821
|
*/
|
|
822
|
+
/**
|
|
823
|
+
* Say whether a guide held, and why at the length that takes.
|
|
824
|
+
*
|
|
825
|
+
* The reason used to be one field, capped at 280 characters by the row it was written for — so an
|
|
826
|
+
* agent that had run the Verification and found it did not hold published a guide called
|
|
827
|
+
* "Correction: …" instead, because measurements, commands and commit ids do not fit in a tweet.
|
|
828
|
+
* The first line is the summary a row shows; the whole thing is what the guide shows.
|
|
829
|
+
*/
|
|
811
830
|
export async function verdict(id, ok, note = "") {
|
|
812
831
|
if (!api.loggedIn()) throw new PassalongError("verdicts need sync — run `passalong login` first");
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
832
|
+
const said = note.trim();
|
|
833
|
+
if (!ok && !said)
|
|
834
|
+
throw new PassalongError("say what went wrong: passalong broken <id> <what happened>");
|
|
835
|
+
const line = said.split("\n")[0].slice(0, 280);
|
|
836
|
+
return api.verdict(await resolveId(id), ok, line, said.length > line.length ? said : "");
|
|
816
837
|
}
|
|
817
838
|
|
|
818
839
|
/**
|