Skip to content
SlashClone

A session log that parallel agents never conflict on

@slashclone/parallel-session-log

Keep a project log that several Claude Code sessions can write at once without merge conflicts. Each session writes its own dated file, an index is generated instead of hand edited, and a small CI check makes sure every entry carries the line your team requires. Writes the files for you to review; never commits or pushes.

SkillDevOpsv0.1.0 (latest)
Activity
New: be the first to try it
  1. 1#!/usr/bin/env node
  2. 2// Fails when a change adds a session log without the required line.
  3. 3//
  4. 4// Sessions log in their own file, docs/progress/YYYY-MM-DD-slug.md. Each file added or changed
  5. 5// needs that name and the required line. Entries still added to the old single log,
  6. 6// docs/PROGRESS.md, are checked the same way, so pull requests opened before the switch pass.
  7. 7//
  8. 8// Usage: node .github/scripts/check-session-log.mjs <base-ref>
  9. 9// Compares the files at <base-ref> with the working tree. Node standard library only.
  10. 10// Edit LOG, DIR, LABEL and the headings in IGNORED to match your project.
  11. 11import { execFileSync } from "node:child_process";
  12. 12import { existsSync, readFileSync } from "node:fs";
  13. 14const LOG = "docs/PROGRESS.md";
  14. 15const DIR = "docs/progress";
  15. 16const LABEL = "Summary"; // the required line is "**Summary:** ..." with some text after it
  16. 17const IGNORED = ["Template", "Sessions", "History"]; // headings in the old log that are not entries
  17. 18const NAME = /^(\d{4}-\d{2}-\d{2})-[a-z0-9]+(?:-[a-z0-9]+)*\.md$/;
  18. 19const REQUIRED = new RegExp(`^\\*\\*${LABEL}:\\*\\*\\s*\\S`, "m");
  19. 20const base = process.argv[2];
  20. 21if (!base) {
  21. 22 console.error("usage: check-session-log.mjs <base-ref>");
  22. 23 process.exit(2);
  23. 26const lines = (args) => execFileSync("git", args, { encoding: "utf8" }).split("\n").filter(Boolean);
  24. 27const problems = [];
  25. 29// 1. Session files: every file added or changed in the folder (the template aside).
  26. 30const paths = new Set([
  27. 31 ...lines(["diff", "--name-only", "--diff-filter=AMR", base, "--", `${DIR}/`]),
  28. 32 ...lines(["ls-files", "--others", "--exclude-standard", "--", `${DIR}/`]),
  29. 33]);
  30. 34for (const path of paths) {
  31. 35 const name = path.slice(DIR.length + 1);
  32. 36 if (name === "_TEMPLATE.md" || !existsSync(path)) continue;
  33. 37 if (!NAME.test(name)) problems.push(`${path}: name it YYYY-MM-DD-slug.md`);
  34. 38 else if (!REQUIRED.test(readFileSync(path, "utf8")))
  35. 39 problems.push(`${path}: needs a "**${LABEL}:**" line`);
  36. 42// 2. The old single log: new "## " entries need the line too. Fenced blocks are skipped.
  37. 43function entries(text) {
  38. 44 const out = new Map();
  39. 45 let heading = null;
  40. 46 let inFence = false;
  41. 47 for (const line of text.split("\n")) {
  42. 48 if (line.startsWith("```")) inFence = !inFence;
  43. 49 if (!inFence && line.startsWith("## ")) {
  44. 50 heading = line.slice(3).trim();
  45. 51 out.set(heading, "");
  46. 52 continue;
  47. 53 }
  48. 54 if (heading !== null) out.set(heading, out.get(heading) + line + "\n");
  49. 55 }
  50. 56 for (const h of IGNORED) out.delete(h);
  51. 57 return out;
  52. 59if (existsSync(LOG)) {
  53. 60 let before = "";
  54. 61 try {
  55. 62 before = execFileSync("git", ["show", `${base}:${LOG}`], { encoding: "utf8" });
  56. 63 } catch {
  57. 64 // The file is new on this branch: every entry in it is new.
  58. 65 }
  59. 66 const old = entries(before);
  60. 67 for (const [heading, body] of entries(readFileSync(LOG, "utf8")))
  61. 68 if (!old.has(heading) && !REQUIRED.test(body))
  62. 69 problems.push(`${LOG}: the new entry "## ${heading}" needs a "**${LABEL}:**" line`);
  63. 72if (problems.length > 0) {
  64. 73 console.error("Session logs are missing something:");
  65. 74 for (const problem of problems) console.error(` - ${problem}`);
  66. 75 process.exit(1);
  67. 77console.log("Every new session log is named right and has its required line.");

Cookies that keep you signed in and remember these choices are always on. Everything else is off until you turn it on.