Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
fetch-depth: 0
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
node-version: ${{ matrix.node }}
Expand All @@ -43,7 +45,7 @@ jobs:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
repository: cursor/plugins
ref: 7366ac128bdf95f45e6734f412b49a4031800169
ref: f5bdd6826fd0a0d9cbc4347134c3a74a200b9d9d
path: .upstream/cursor-plugins
sparse-checkout: pstack
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
Expand Down
18 changes: 9 additions & 9 deletions profiles/skill-manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": 1,
"sources": {
"pstack": "7366ac128bdf95f45e6734f412b49a4031800169",
"pstack": "f5bdd6826fd0a0d9cbc4347134c3a74a200b9d9d",
"mattpocock/skills": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76"
},
"files": {
Expand Down Expand Up @@ -205,14 +205,14 @@
"skills/meta-mode/playbooks/autopilot-full.md": {
"upstream": "pstack",
"source": "skills/poteto-mode/playbooks/autopilot-full.md",
"sourceDigest": "52f69170bd7fa6b436992d90d3ef7fba893201e0b497297b416e9aea0e567d5f",
"targetDigest": "0a649471ca2e98d91e2a83c05437ff6c5e4137769df8e12352cc8651c9c27579"
"sourceDigest": "2042a89a0399b5fe700110bc03746899536c10f0df186e9fb15bbd4a2f6dfce5",
"targetDigest": "be9eeb3df8df26671d5e134b14b337d9b2fa311e096d1ee6c66c06c6c55c047b"
},
"skills/meta-mode/playbooks/autopilot-stack.md": {
"upstream": "pstack",
"source": "skills/poteto-mode/playbooks/autopilot-stack.md",
"sourceDigest": "66364cd3a2286cbecfb73d3a7bf7d1fa387ede8525d37ef22b69d4ac03c2c5b2",
"targetDigest": "eb6f902e29a3546d50d95a6f5989654a5ecaa83c94a07a91495e812a923c803f"
"sourceDigest": "60e0d997f7b369004a02089c71b9091d3f8e9bc0b4a3c1142598380faa7722fd",
"targetDigest": "7a3dd0ab570560e1051e38fd16711914dacd476202be358e25c0f34c917a2b45"
},
"skills/meta-mode/playbooks/babysit.md": {
"upstream": "pstack",
Expand Down Expand Up @@ -253,8 +253,8 @@
"skills/meta-mode/playbooks/multi-phase-plan.md": {
"upstream": "pstack",
"source": "skills/poteto-mode/playbooks/multi-phase-plan.md",
"sourceDigest": "63426a55519fbc4fb9f00baf5cc7b1148f70dfb62ad360a0f6533d287dd36edf",
"targetDigest": "62c9a4b1d6bd6e5ad718af0d4972432773afa5af10ae05b8b751f0fc117ac78f"
"sourceDigest": "b823e05b64bbef84ae5169717c5fab1d9ab5079625996271e3aa7abcdce7b8ad",
"targetDigest": "51f824fa3caae6bd0fd69852f66387ef2e203e6c15f8f8982cf20d0d22965bf1"
},
"skills/meta-mode/playbooks/opening-a-pr.md": {
"upstream": "pstack",
Expand Down Expand Up @@ -342,8 +342,8 @@
"skills/meta-mode/SKILL.md": {
"upstream": "pstack",
"source": "skills/poteto-mode/SKILL.md",
"sourceDigest": "6bbf35cb2111c358461c7ba90f210dad4573f3a3ada92f6459eac0c69d83b01a",
"targetDigest": "798df0dae0ca4959b81d6465b1c3c392ffc5cefd98f5b0834a53262eb1b2fa86"
"sourceDigest": "b3c505602b82fb3641a3983e9c46fb974881faa12ece1af804fae27afb7be532",
"targetDigest": "4efa5f64e1f6bd01fd08eb6fb720ab4c84c7f3d787fff9df71d0e07ab65b73fe"
},
"skills/no-comments/SKILL.md": {
"upstream": "pstack",
Expand Down
6 changes: 3 additions & 3 deletions profiles/upstream-manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"source": "https://github.com/cursor/plugins/tree/main/pstack",
"commit": "7366ac128bdf95f45e6734f412b49a4031800169",
"commit": "f5bdd6826fd0a0d9cbc4347134c3a74a200b9d9d",
"artifacts": {
"agents": {
"agents/comment-reviewer.md": "c0fd0383008da45fc78cfac17b9007d62c42f87ad1c8d5c2fb658b1fd01f7c82",
Expand Down Expand Up @@ -108,8 +108,8 @@
"target": "2f04984c34d64ad8119eac43f24298d480528b14a9876d672aee0c942aa0c2da"
},
"meta-mode": {
"source": "9319963075ef537e1d83edc4814f6bc6a7c90779ea261227934c984a0a5e88fb",
"target": "798df0dae0ca4959b81d6465b1c3c392ffc5cefd98f5b0834a53262eb1b2fa86"
"source": "d5817d996f6da294c86cacb2bd1b0c40c85968844a6afd194fe69efa8654878f",
"target": "4efa5f64e1f6bd01fd08eb6fb720ab4c84c7f3d787fff9df71d0e07ab65b73fe"
},
"no-comments": {
"source": "5c5b0882297d704c3a9720c52b7a793c68b013eaf717989f0945624efdfe2b05",
Expand Down
2 changes: 1 addition & 1 deletion profiles/upstreams.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"pstack": {
"repository": "https://github.com/cursor/plugins/tree/main/pstack",
"commit": "7366ac128bdf95f45e6734f412b49a4031800169",
"commit": "f5bdd6826fd0a0d9cbc4347134c3a74a200b9d9d",
"renames": {
"poteto-mode": "meta-mode",
"setup-pstack": "setup-mstack",
Expand Down
10 changes: 7 additions & 3 deletions scripts/install-migration.test.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { execFileSync } from "node:child_process";
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
Expand Down Expand Up @@ -91,12 +92,15 @@ test("disabled discovery migration does not inspect unknown custom copies", (t)
test("digest provenance includes actual released canonical and Claude adapter content", () => {
const data = JSON.parse(readFileSync(join(repository, "profiles", "legacy-skill-digests.json"), "utf8"));
assert.deepEqual(data.sources, ["v0.2.0", "v0.2.1", "v0.3.0", "v0.4.0"]);
// Ownership digests cover released versions; the working tree may carry
// unreleased edits, so read the latest released tag instead of the live file.
const releasedVersion = JSON.parse(execFileSync("git", ["show", "v0.4.1:package.json"], { encoding: "utf8" })).version;
const released = (name) => execFileSync("git", ["show", `v${releasedVersion}:skills/${name}/SKILL.md`], { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
for (const name of ["meta-mode", "show-me-your-work"]) {
const text = readFileSync(join(repository, "skills", name, "SKILL.md"), "utf8").replaceAll("\r\n", "\n");
const hash = createHash("sha256").update(text).digest("hex");
const hash = createHash("sha256").update(released(name).replaceAll("\r\n", "\n")).digest("hex");
assert.equal(data.skills[name].includes(hash), true, name);
}
const canonical = readFileSync(join(repository, "skills", "show-me-your-work", "SKILL.md"), "utf8").replaceAll("\r\n", "\n");
const canonical = released("show-me-your-work").replaceAll("\r\n", "\n");
const claude = canonical.replace(
"metadata:\n requirements: Node.js 18 or newer for scripts/log.mjs\n",
'compatibility: "Node.js 18 or newer is required for scripts/log.mjs."\n',
Expand Down
12 changes: 9 additions & 3 deletions scripts/migration-integration.test.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, relative, resolve } from "node:path";
import { spawnSync } from "node:child_process";
import test from "node:test";

const installer = resolve("scripts", "install.mjs");
// Legacy fixtures must match released content the digest list covers; the
// working tree can carry unreleased edits. The installer stages from the
// working tree, so post-install assertions read the live file instead.
const releasedVersion = JSON.parse(execFileSync("git", ["show", "v0.4.1:package.json"], { encoding: "utf8" })).version;
const releasedCanonical = execFileSync("git", ["show", `v${releasedVersion}:skills/meta-mode/SKILL.md`], { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
const canonical = readFileSync(resolve("skills", "meta-mode", "SKILL.md"), "utf8");

function snapshot(root) {
Expand Down Expand Up @@ -37,7 +43,7 @@ function fixture(t) {
mkdirSync(dirname(path), { recursive: true });
writeFileSync(path, content);
}
function installOld(harness, { content = canonical, receipt = false, name = "meta-mode" } = {}) {
function installOld(harness, { content = releasedCanonical, receipt = false, name = "meta-mode" } = {}) {
const path = join(roots[harness], name);
write(join(path, "SKILL.md"), content);
write(join(path, "local-support.txt"), `${harness} supporting content`);
Expand Down Expand Up @@ -116,7 +122,7 @@ test("a later retirement failure restores previously retired copies and Claude c
assert.match(result.stderr, /Rollback results:/);
assert.ok(result.stdout.includes(`backup: ${opencode} ->`), "OpenCode retirement must have committed before the injected failure");
for (const [harness, target] of [["opencode", opencode], ["pi", pi], ["claude", claude]]) {
assert.equal(readFileSync(join(target, "SKILL.md"), "utf8"), canonical);
assert.equal(readFileSync(join(target, "SKILL.md"), "utf8"), releasedCanonical);
assert.equal(readFileSync(join(target, "local-support.txt"), "utf8"), `${harness} supporting content`);
}
assert.equal(existsSync(join(f.roots.shared, "meta-mode")), false);
Expand All @@ -128,7 +134,7 @@ test("migration archives authenticated crashed stages and preserves unselected o
const remoteStage = join(f.roots.opencode, ".mstack-stage.old");
const unselectedStage = join(f.roots.pi, ".mstack-stage.unselected");
const emptyStage = join(f.roots.shared, ".harness-skills-stage-empty");
f.write(join(localStage, "SKILL.md"), canonical);
f.write(join(localStage, "SKILL.md"), releasedCanonical);
f.write(join(localStage, "support.txt"), "Preserve crashed local support");
f.write(join(remoteStage, "SKILL.md"), "---\nname: meta-mode\ndescription: Customized installed copy\n---\nRemote stage body\n");
f.write(join(remoteStage, ".mstack-install.json"), JSON.stringify({ package: "@3metajun/mstack", schemaVersion: 1 }));
Expand Down
2 changes: 1 addition & 1 deletion skills/meta-mode/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ A large or cross-cutting effort (a migration across many call sites, an ambitiou
- **Autonomous run.** A long task to drive to completion without stopping ("run until done", "/loop until X"). `playbooks/autonomous-run.md`.
- **Orchestrate.** A standing project handed to one coordinator chat: multi-day, many stacked PRs, dozens to hundreds of subagents, minimal human turns ("run this whole project", "own this migration until it lands"). Distinct from Autonomous run, which drives one task to a predicate. Work one agent could finish inside the session's budget routes there, not here, however program-shaped the phrasing sounds. `playbooks/orchestrate.md`.
- **Autopilot-full.** A queue of independent PRs run to merged with full autonomy. One owner per PR carries build through merge, and the root swarm-verifies each merge-ready head before its owner merges ("autopilot this queue", "full autopilot", one-owner-per-PR programs). `playbooks/autopilot-full.md`.
- **Autopilot-stack.** A queue of changes built and verified with full autonomy, delivered as one linear reviewed base-branch stack the operator lands herself ("autopilot-stack", "stack them, don't ship", "build the stack, I'll land it"). `playbooks/autopilot-stack.md`.
- **Autopilot-stack.** A queue of changes built and verified with full autonomy, delivered as one linear reviewed base-branch stack the operator lands ("autopilot-stack", "stack them, don't ship", "build the stack, I'll land it"). `playbooks/autopilot-stack.md`.
- **Session pickup.** Resuming or taking over a prior agent's in-flight work from a transcript, cloud-agent URL, or pushed branch. `playbooks/session-pickup.md`.
- **Pause safely.** Suspending in-flight work cleanly so it can be resumed, on an explicit pause, going offline, a Harness restart, or imminent context compaction. The complement to Session pickup. Full steps: `playbooks/pause-safely.md`.
- **Multi-phase or multi-PR plan.** Work that spans phases or stacked PRs. `playbooks/multi-phase-plan.md`.
Expand Down
6 changes: 3 additions & 3 deletions skills/meta-mode/playbooks/autopilot-full.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

**You own the verdicts, never the PRs. One owner runs each PR from build to merge, and nothing merges without your clean swarm verdict.** For "autopilot this queue", "full autopilot", and one-owner-per-PR programs. Orchestrate runs a standing program whose coordinator lands verified work itself and whose workers never merge. Here each PR's owner carries the whole lifecycle through the merge, and the root keeps only verification, countersigns, and audits.

1. **Mark the operator's items and honor state-then-wait.** Items the operator names stay hers. She reviews and she clicks, and no owner merges one. When she asks for the protocol or the plan to be stated, deliver the statement and stop. Execution starts only on her explicit go. On that go, arm a `/goal` with the full program objective. The goal continues across turns until the queue is done.
1. **Mark the operator's items and honor state-then-wait.** Items the operator names stay with the operator. The operator reviews and clicks, and no owner merges one. When the operator asks for the protocol or the plan to be stated, deliver the statement and stop. Execution starts only on the operator's explicit go. On that go, arm a `/goal` with the full program objective. The goal continues across turns until the queue is done.
2. **Spawn one owner per PR with the full lifecycle and an early trail.** Resolve the forge once for the program. GitHub CLI (`gh`) is the default. If `command -v origin` succeeds and Origin can resolve the repository, use `origin pr ...` for PR create, edit, view, watch, and merge operations. Otherwise stay on `gh` and record the fallback. Never require Graphite (`gt`). One remote worker per PR owns the build, first push, ready PR, proof on the real artifact, review-comment triage, prose cleanup with `unslop`, the **no-comments** skill, a rebase onto current trunk, the babysit loop to green (`playbooks/babysit.md`), and the merge itself. Every owner starts a `decisions.tsv` trail per the **show-me-your-work** skill, pushes its first branch snapshot, and opens the PR ready, never draft. Open the PR before self-proof so the URL, decisions, and checks form a durable trail. Keep `decisions.tsv` uncommitted and return it with the reports. The rebase always precedes babysit and never waits for drift or conflicts. The merge is the one step an owner may not take alone. Step 4 gates it.
3. **Run owners in true parallel and never stack.** Many owners at once when PRs are self-contained: one writer per branch, disjoint files, cross-PR drift absorbed by rebase. Only genuinely overlapping work serializes. Self-contained PRs branch straight off main, and sequenced work is merge-then-branch. One exception: an owner that must split a genuinely dependent change may hold a short private base-branch stack.
4. **Swarm-verify every merge-ready head before its merge.** At the owner's merge-ready head SHA, fan out parallel independent verifiers per the **swarm** skill and aggregate to one verdict. The lanes re-run the gates at that SHA and prove the load-bearing behavior on the real surface. Audit the receipts and the diff, distrusting the PR body. **Regression lane against trunk.** Run the same load-bearing scenario on current trunk. If trunk does not have the feature, record that fact and gate the behavior the diff adds plus the end state the user waits for instead of pretending trunk can produce it. The live lane is the floor, and a verdict without it is not clean. No merge without the root's clean verdict. Findings go back to the owner for fix-forward, and the new head gets a fresh swarm and a fresh verdict.
5. **On a clean verdict the owner merges and takes the next item.** The owner merges only from a head freshly rebased onto trunk. The merge-ready report is made at a trunk-current head, and the swarm verdict pins that SHA. If trunk moves again before the merge, the patch-id rule in `playbooks/shipping.md` governs re-verification. A new head voids the verdict unless the patch-id is unchanged. The owner squash-merges its own PR through the resolved forge and picks up its next self-contained item from the queue. The operator's full-autonomy grant plus the root's clean verdict is the merge authorization that babysitting alone never has. Operator-named items stop at merge-ready and wait for her click.
5. **On a clean verdict the owner merges and takes the next item.** The owner merges only from a head freshly rebased onto trunk. The merge-ready report is made at a trunk-current head, and the swarm verdict pins that SHA. If trunk moves again before the merge, the patch-id rule in `playbooks/shipping.md` governs re-verification. A new head voids the verdict unless the patch-id is unchanged. The owner squash-merges its own PR through the resolved forge and picks up its next self-contained item from the queue. The operator's full-autonomy grant plus the root's clean verdict is the merge authorization that babysitting alone never has. Operator-named items stop at merge-ready and wait for the operator's click.
6. **Run the root layer.** A genuinely new raise of a pinned gate or budget value (a limit CI only lets tighten) needs your fresh countersign, granted only after verifier proof. Absorbing values that already landed on main is drift, not a raise. Run an audit tick over all owners roughly every 30 minutes. A local root arms each tick as a real terminal `/loop`. The loop uses a monitored-shell 30-minute sleep and emits an output-notification sentinel. A cloud root uses the existing cloud-sleeper wake chain instead. Never leave the cadence to memory or lossy completion notifications. At each tick, re-read `<mstack-skills>/meta-mode/playbooks/autopilot-full.md` from the active skill installation, then re-read the armed `/goal`. Audit the operation against both. Fix drift during that tick. Probe each owner with a generic liveness or status check, and collect the decision trails. Count only side effects as progress: commits, pushes, PR or check deltas, and store reports. Treat a lane that passes its expected runtime without a side effect as stuck. Stand it down and dispatch a replacement at once. Do not wait for a polite return. When merges batch, run a retro pass and a post-merge bot-comment sweep.
7. **Stand down instantly on the operator's stop.** Her hold or stand-down reaches every owner as a zero-writes order immediately. Owners hold their briefs until she releases them.
7. **Stand down instantly on the operator's stop.** The operator's hold or stand-down reaches every owner as a zero-writes order immediately. Owners hold their briefs until the operator releases them.

**Reply:** the queue with each PR's owner, state, and head SHA. Each verdict and the swarm that produced it. What merged and what each owner took next. Countersigns granted and why. Open operator gates. Where the collected decision trails live.
Loading