passalong 1.4.0 → 1.5.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/README.md +0 -4
- package/bin/passalong +24 -78
- package/package.json +1 -1
- package/src/api.js +0 -5
- package/src/checks.js +2 -2
- package/src/passalong.js +7 -437
- package/src/update.js +47 -2
- package/src/runner.js +0 -645
package/README.md
CHANGED
|
@@ -51,10 +51,6 @@ passalong archive <id> off the board and out of the free tier's count
|
|
|
51
51
|
passalong rm <id> delete it
|
|
52
52
|
passalong attach <file> upload a picture or file and print the markdown that points at it
|
|
53
53
|
passalong work [--once] [--agent CMD] run an agent on each piece of ready work here, in turn
|
|
54
|
-
passalong work --watch the runner, in a repo or a folder of repos: work a person marked safe
|
|
55
|
-
to run alone, up to 3 at once, each in its own worktree, finished
|
|
56
|
-
as a pull request; each agent's steps show in the hub. When Claude's
|
|
57
|
-
usage runs out it pauses, and carries on once it is back
|
|
58
54
|
passalong now what this worktree holds and what is waiting
|
|
59
55
|
passalong hub open the hub in the browser
|
|
60
56
|
passalong export [dir] every piece of work as plain markdown
|
package/bin/passalong
CHANGED
|
@@ -22,8 +22,6 @@
|
|
|
22
22
|
// passalong rm <id> delete it
|
|
23
23
|
// passalong attach <file> upload a picture or a file and print the markdown that points at it
|
|
24
24
|
// passalong work [--once] [--agent CMD] run an agent on each piece of ready work here, one after another
|
|
25
|
-
// passalong work --watch [--every SECS] the runner, in a repo or a folder of repos: keep taking work marked safe to run alone,
|
|
26
|
-
// up to 3 at once, each in its own worktree and branch, finished as a pull request
|
|
27
25
|
// passalong hub open the hub in the browser
|
|
28
26
|
// passalong export [dir] dump every piece of work as plain markdown (default ./passalong-export)
|
|
29
27
|
// passalong admin create <email> make an account that runs Passalong (owner only)
|
|
@@ -61,7 +59,6 @@ import * as api from "../src/api.js";
|
|
|
61
59
|
import { workScaffold } from "../src/capture.js";
|
|
62
60
|
import { parse, serialize } from "../src/work.js";
|
|
63
61
|
import * as passalong from "../src/passalong.js";
|
|
64
|
-
import { otherCopies } from "../src/runner.js";
|
|
65
62
|
import * as store from "../src/store.js";
|
|
66
63
|
|
|
67
64
|
const PKG = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
@@ -252,79 +249,6 @@ async function statusLine() {
|
|
|
252
249
|
}
|
|
253
250
|
}
|
|
254
251
|
|
|
255
|
-
/**
|
|
256
|
-
* `passalong work --watch`: the runner (src/runner.js). Each piece of work marked safe to run alone
|
|
257
|
-
* gets its own worktree, branch and Claude Code; what it does arrives as a pull request.
|
|
258
|
-
*/
|
|
259
|
-
async function runner(f) {
|
|
260
|
-
const every = Number(f.every) || 60;
|
|
261
|
-
let idle = false;
|
|
262
|
-
/** "a, b and 4 more": the repos a runner serves, short enough for one line. */
|
|
263
|
-
const some = (repos) =>
|
|
264
|
-
repos.length <= 3 ? repos.join(", ") : `${repos.slice(0, 3).join(", ")} and ${repos.length - 3} more`;
|
|
265
|
-
await passalong
|
|
266
|
-
.watch({
|
|
267
|
-
agent: typeof f.agent === "string" ? f.agent : undefined,
|
|
268
|
-
every,
|
|
269
|
-
cli: fileURLToPath(import.meta.url),
|
|
270
|
-
signals: true,
|
|
271
|
-
// Said only once the folder checked out: a runner that cannot run says why, not what it will do.
|
|
272
|
-
onStart: ({ repos, skipped }) => {
|
|
273
|
-
console.error(
|
|
274
|
-
`Runner for ${repos.length === 1 ? repos[0] : `${repos.length} repos: ${some(repos)}`}.\n` +
|
|
275
|
-
"It takes work marked safe to run alone, up to 3 at once, and finishes each " +
|
|
276
|
-
"as a pull request. You can watch each agent here and on the work's page in the hub. " +
|
|
277
|
-
"Stop it with Ctrl-C: agents running then stop too.",
|
|
278
|
-
);
|
|
279
|
-
if (skipped.length)
|
|
280
|
-
console.error(`Skipped ${skipped.length} checkout${skipped.length === 1 ? "" : "s"} with no origin remote: ${some(skipped)}`);
|
|
281
|
-
// Another copy on PATH (npm's beside pnpm's): updating one leaves the other running.
|
|
282
|
-
const mine = JSON.parse(readFileSync(join(PKG, "package.json"), "utf8")).version;
|
|
283
|
-
const { others, shadowed } = otherCopies(fileURLToPath(import.meta.url));
|
|
284
|
-
for (const o of others)
|
|
285
|
-
console.error(
|
|
286
|
-
`! Another passalong${o.version ? ` (${o.version})` : ""} is installed at ${o.path}` +
|
|
287
|
-
(shadowed && o === others[0]
|
|
288
|
-
? `, and it is the one \`passalong\` runs in a new terminal, not this ${mine}.`
|
|
289
|
-
: `, beside this ${mine}.`) +
|
|
290
|
-
" Keep one: `npm uninstall -g passalong` or `pnpm remove -g passalong`, whichever installed it.",
|
|
291
|
-
);
|
|
292
|
-
},
|
|
293
|
-
onTask: (t, { dir, branch, repo }) => {
|
|
294
|
-
idle = false;
|
|
295
|
-
console.error(`\n→ ${t.id} ${t.title}\n ${repo}, on ${branch} in ${dir}`);
|
|
296
|
-
},
|
|
297
|
-
onStep: (t, text) => console.error(` ${t.id} · ${text}`),
|
|
298
|
-
onIdle: (repos) => {
|
|
299
|
-
if (!idle)
|
|
300
|
-
console.error(
|
|
301
|
-
`waiting for work marked safe to run alone in ${some(repos)}. ` +
|
|
302
|
-
"Work with no repo needs one picked on its page in the hub.",
|
|
303
|
-
);
|
|
304
|
-
idle = true;
|
|
305
|
-
},
|
|
306
|
-
onPaused: (t, { until }) =>
|
|
307
|
-
console.error(
|
|
308
|
-
`‖ ${t.id} paused: Claude's usage ran out. ` +
|
|
309
|
-
(until
|
|
310
|
-
? `It carries on at ${new Date(until).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })}`
|
|
311
|
-
: "It tries again every 15 minutes") +
|
|
312
|
-
", and takes nothing new until then.",
|
|
313
|
-
),
|
|
314
|
-
onFinished: (t, { branch, log }) => console.error(`✓ ${t.id} finished on ${branch} (log: ${log})`),
|
|
315
|
-
onWaiting: (t, { question }) =>
|
|
316
|
-
console.error(`? ${t.id} is waiting on you: "${question.split("\n")[0]}" (answer it in the hub)`),
|
|
317
|
-
onResumed: (t, { afterPause }) =>
|
|
318
|
-
console.error(
|
|
319
|
-
`\n→ ${t.id} ${t.title} (${afterPause ? "carrying on where it stopped" : "answered: carrying on"})`,
|
|
320
|
-
),
|
|
321
|
-
onPassed: (t, { dir, log }) =>
|
|
322
|
-
console.error(`✗ ${t.id} went back to its author, unfinished. Its worktree: ${dir} (log: ${log})`),
|
|
323
|
-
onTrouble: (err, t) => console.error(`! ${t ? `${t.id}: ` : ""}${err?.message || err}`),
|
|
324
|
-
})
|
|
325
|
-
.catch((e) => die(e.message));
|
|
326
|
-
}
|
|
327
|
-
|
|
328
252
|
const commands = {
|
|
329
253
|
/**
|
|
330
254
|
* Write work down: a sentence becomes its title, summary and text, or a file is sent as it is. At
|
|
@@ -519,7 +443,14 @@ const commands = {
|
|
|
519
443
|
* files without asking — which is yours to decide, not this command's.
|
|
520
444
|
*/
|
|
521
445
|
async work(f) {
|
|
522
|
-
|
|
446
|
+
// The runner `--watch` started was removed (2026-11-07). Saying so beats running the queue
|
|
447
|
+
// instead, which is a different thing from what whoever typed `--watch` asked for.
|
|
448
|
+
if (f.watch) {
|
|
449
|
+
console.error(
|
|
450
|
+
"The runner has been removed from Passalong. Open a Claude Code session in your repo and ask it to take work from Passalong instead.",
|
|
451
|
+
);
|
|
452
|
+
process.exit(1);
|
|
453
|
+
}
|
|
523
454
|
const run = await passalong
|
|
524
455
|
.work({
|
|
525
456
|
agent: typeof f.agent === "string" ? f.agent : undefined,
|
|
@@ -939,7 +870,22 @@ if (typeof argv.as === "string") {
|
|
|
939
870
|
// both are caught here, with `version`, before dispatch. Only the number goes to stdout, so
|
|
940
871
|
// `passalong -v` can be read by a script comparing it against the registry.
|
|
941
872
|
if (cmd === "-v" || cmd === "version" || (cmd === "help" && argv.version === true)) {
|
|
942
|
-
|
|
873
|
+
const mine = JSON.parse(readFileSync(join(PKG, "package.json"), "utf8")).version;
|
|
874
|
+
console.log(mine);
|
|
875
|
+
// Another copy on PATH (npm's beside pnpm's) is the usual reason the version is not the one
|
|
876
|
+
// expected: updating one leaves the other answering. Said on stderr, so stdout stays the number.
|
|
877
|
+
try {
|
|
878
|
+
const { otherCopies } = await import("../src/update.js");
|
|
879
|
+
const { others, shadowed } = otherCopies(fileURLToPath(import.meta.url));
|
|
880
|
+
for (const o of others)
|
|
881
|
+
console.error(
|
|
882
|
+
`! Another passalong${o.version ? ` (${o.version})` : ""} is installed at ${o.path}` +
|
|
883
|
+
(shadowed && o === others[0]
|
|
884
|
+
? `, and it is the one \`passalong\` runs in a new terminal, not this ${mine}.`
|
|
885
|
+
: `, beside this ${mine}.`) +
|
|
886
|
+
" Keep one: `npm uninstall -g passalong` or `pnpm remove -g passalong`, whichever installed it.",
|
|
887
|
+
);
|
|
888
|
+
} catch {}
|
|
943
889
|
} else if (cmd === "--help" || cmd === "-h" || cmd === "help") commands.help();
|
|
944
890
|
// A command this build does not have used to print the help page and exit 0, which reads as "that
|
|
945
891
|
// command exists and did nothing" — and the usual cause is an older passalong, where the command is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "passalong",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Work, projects, documents and files for a team and its agents: take work, hand it in with evidence, and keep what the team knows in its projects.",
|
|
5
5
|
"mcpName": "io.github.codellyson/passalong",
|
|
6
6
|
"keywords": [
|
package/src/api.js
CHANGED
|
@@ -357,11 +357,6 @@ export const setStatus = (id, status) =>
|
|
|
357
357
|
export const remove = (id) => call(`/v1/work/${id}`, { method: "DELETE" });
|
|
358
358
|
export const tasks = () => call("/v1/tasks");
|
|
359
359
|
export const nextTask = (body) => call("/v1/tasks/next", { method: "POST", body });
|
|
360
|
-
/** The runner saying how it is, for the hub: what it is on, today's count, or that it stopped. */
|
|
361
|
-
export const runnerStatus = (body) => call("/v1/runner", { method: "PUT", body });
|
|
362
|
-
/** What a runner's agent did since the last report, a line each, for the hub to show. */
|
|
363
|
-
export const workSteps = (id, steps) =>
|
|
364
|
-
call(`/v1/work/${encodeURIComponent(id)}/steps`, { method: "POST", body: { steps } });
|
|
365
360
|
export const reopen = (id, why) =>
|
|
366
361
|
call(`/v1/work/${encodeURIComponent(id)}/reopen`, { method: "POST", body: { why } });
|
|
367
362
|
/** Take work back from whoever holds it. */
|
package/src/checks.js
CHANGED
|
@@ -50,8 +50,8 @@ export const CHECK_TIMEOUT_MS = 10 * 60 * 1000;
|
|
|
50
50
|
export const OUTPUT_MAX = 4000;
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
* The tail of what a command printed, because that is where a runner puts what went wrong. A
|
|
54
|
-
* would hold the banner and the first hundred passing lines.
|
|
53
|
+
* The tail of what a command printed, because that is where a test runner puts what went wrong. A
|
|
54
|
+
* head would hold the banner and the first hundred passing lines.
|
|
55
55
|
*/
|
|
56
56
|
function tail(out, max = OUTPUT_MAX) {
|
|
57
57
|
const s = String(out ?? "").replace(/\s+$/, "");
|