passalong 0.3.1 → 0.3.2

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 CHANGED
@@ -48,6 +48,7 @@ passalong team join <link> accept an invite
48
48
  passalong team use <slug> switch the current team
49
49
  passalong setup install the Claude Code capture skill + register the MCP server
50
50
  passalong mcp run the MCP server over stdio
51
+ passalong version print the installed version (also -v, --version)
51
52
  ```
52
53
 
53
54
  ## Teams
package/bin/passalong CHANGED
@@ -30,6 +30,7 @@
30
30
  // passalong team use <slug> switch the current team
31
31
  // passalong setup install the Claude Code capture skill + register the MCP server
32
32
  // passalong mcp run the MCP server over stdio
33
+ // passalong version print the installed version (also -v, --version)
33
34
  import { execFileSync, spawnSync } from "node:child_process";
34
35
  import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
35
36
  import { homedir } from "node:os";
@@ -490,5 +491,11 @@ const commands = {
490
491
 
491
492
  const argv = flags(process.argv.slice(2));
492
493
  const cmd = argv._.shift() || "help";
493
- if (cmd === "--help" || cmd === "-h" || !commands[cmd]) commands.help();
494
+ // The first thing anyone runs when something is off, and until now it printed the help page. The
495
+ // parser only knows `--x`, so `--version` arrives as a flag on an empty command and `-v` as a word;
496
+ // both are caught here, with `version`, before dispatch. Only the number goes to stdout, so
497
+ // `passalong -v` can be read by a script comparing it against the registry.
498
+ if (cmd === "-v" || cmd === "version" || (cmd === "help" && argv.version === true)) {
499
+ console.log(JSON.parse(readFileSync(join(PKG, "package.json"), "utf8")).version);
500
+ } else if (cmd === "--help" || cmd === "-h" || !commands[cmd]) commands.help();
494
501
  else await commands[cmd](argv).catch((e) => die(e.message));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "passalong",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Hand a finished implementation from one context to another, in a form an AI agent can act on.",
5
5
  "keywords": [
6
6
  "mcp",
package/skill/SKILL.md CHANGED
@@ -33,6 +33,13 @@ session's history. Write for execution, not for permanence.
33
33
  team"), add `--to <team>` or `--to <team>/<handle>`; `passalong team` lists the current
34
34
  team's members and their handles. It prints the guide id on stdout and the share link (and
35
35
  who it was handed to) on stderr.
36
+
37
+ **If this session started from a passalong guide** — you ran `passalong start` or `pull` on an
38
+ id, or an agent opened one — and what you are capturing is what doing it taught you, add
39
+ `--follows <that id>`. The original then lists this one as a follow-up. That is the case when
40
+ you departed from it: changed or skipped a Step, adapted an `ASSUMES` for this stack, found the
41
+ fix a failing guide did not have, or hit a Gotcha it does not list. If it worked exactly as
42
+ written there is nothing to capture — say so with `passalong works <id>` instead.
36
43
  6. **Report** the id (and link if synced) and one line on how to use it on the other side:
37
44
  `passalong start <id>` in the target repo, or "start passalong <id>" to an agent with the
38
45
  Passalong MCP server. `start` rather than `pull` on purpose: it takes the handoff as well as
package/src/mcp.js CHANGED
@@ -95,7 +95,13 @@ export async function serve() {
95
95
  "shows whether the guides they handed off have landed. When the user asks what they have " +
96
96
  "been working on, or wants a standup or a summary of a period, call log — but say that it " +
97
97
  "holds what they passed along and not everything they did. Gotchas are " +
98
- "the highest-value section: record what failed and why.",
98
+ "the highest-value section: record what failed and why.\n" +
99
+ "A FOLLOW-UP IS A GUIDE, NOT A NOTE. When you worked from a guide and departed from it — " +
100
+ "changed or skipped a Step, adapted an ASSUMES for this stack, found the fix a failing " +
101
+ "guide did not have, or hit a Gotcha it does not list — publish what you learned as its " +
102
+ "own guide with publish_guide `parent` set to that guide's id; the original then lists it " +
103
+ "as a follow-up. If it worked exactly as written, do not: answer with verify_guide, or " +
104
+ "every guide collects copies that say nothing new.",
99
105
  },
100
106
  );
101
107
 
@@ -223,7 +229,10 @@ export async function serve() {
223
229
  description:
224
230
  "After following a guide's Verification section, report the result. This is the only way " +
225
231
  "the author learns their handoff did not land — `set_guide_status consumed` says it was " +
226
- "implemented, this says it actually works. A failing verdict must say what went wrong.",
232
+ "implemented, this says it actually works. A failing verdict must say what went wrong. " +
233
+ "If doing it taught you something the guide did not say — a flag it needed, a step that " +
234
+ "was wrong for this stack — publish that as its own guide with publish_guide `parent` set " +
235
+ "to this id. The author sees it as a follow-up; a verdict note is one line and gets lost.",
227
236
  inputSchema: {
228
237
  id: z.string().describe("passalong id"),
229
238
  ok: z.boolean().describe("true if the Verification steps passed"),
@@ -307,7 +316,8 @@ export async function serve() {
307
316
  const siblings = await related(meta);
308
317
  return text(
309
318
  `${lead}${r.markdown}${siblings}` +
310
- `\n\n<!-- passalong: ${r.from}; written to ${r.path}; ${took} -->`,
319
+ `\n\n<!-- passalong: ${r.from}; written to ${r.path}; ${took} -->` +
320
+ `\n${passalong.followUpNote(meta)}`,
311
321
  );
312
322
  } catch (err) {
313
323
  return fail(err);
@@ -356,7 +366,8 @@ export async function serve() {
356
366
  return text(
357
367
  `${lead}${markdown}${siblings}` +
358
368
  `\n\n<!-- passalong: ${from}; written to ${path} -->` +
359
- `\n${passalong.handoffNudge(meta)}`,
369
+ `\n${passalong.handoffNudge(meta)}` +
370
+ `\n${passalong.followUpNote(meta)}`,
360
371
  );
361
372
  } catch (err) {
362
373
  return fail(err);
package/src/passalong.js CHANGED
@@ -296,6 +296,33 @@ export async function attach(file, { name = "" } = {}) {
296
296
  return { ...shot, markdown: `![${name || basename(file)}](${shot.url})` };
297
297
  }
298
298
 
299
+ /**
300
+ * The line a guide arrives with, saying when what you do next deserves to be a guide of its own.
301
+ *
302
+ * Trailing, like the handoff nudge, so it never sits in front of the frontmatter. It is here and
303
+ * not only in the server's instructions because an agent reads the payload it is working from and
304
+ * skims everything else — the same reason the bug lead is inside the document.
305
+ *
306
+ * It says when *not* to as well. A follow-up for a guide that worked exactly as written is a copy
307
+ * that says nothing new, and a guide collecting those is worse than one with none; that answer is a
308
+ * verdict. For a bug the question is different — nothing to depart from, but a fix worth repeating
309
+ * elsewhere is a transfer guide, and the bug is where it came from.
310
+ */
311
+ export function followUpNote(meta = {}) {
312
+ if (!meta.id) return "";
313
+ if (meta.kind === "bug")
314
+ return (
315
+ "<!-- passalong: once this is fixed, if the fix is worth repeating somewhere else, publish " +
316
+ `it as a transfer guide with publish_guide parent=${meta.id} so this bug lists it. -->`
317
+ );
318
+ return (
319
+ "<!-- passalong: if you depart from this guide — change or skip a Step, adapt an ASSUMES for " +
320
+ "this stack, find a fix it did not have, hit a Gotcha it does not list — publish what you " +
321
+ `learned as its own guide with publish_guide parent=${meta.id}. If it worked exactly as ` +
322
+ "written, answer with verify_guide instead. -->"
323
+ );
324
+ }
325
+
299
326
  /** Local guides merged with synced ones (by id), newest first, optionally filtered. */
300
327
  export async function list(query = "", { remote = true, scope = "" } = {}) {
301
328
  const local = scope && scope !== "all" && scope !== "mine" ? [] : store.search(query);