@heretyc/subagent-mcp 2.12.19 → 2.12.21

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
@@ -27,7 +27,7 @@ of raw file context. The main invariants are:
27
27
 
28
28
  ### What You Need First
29
29
 
30
- - Node.js 18 or newer (`node --version`)
30
+ - Node.js 20 or newer (`node --version`)
31
31
  - `claude` CLI, installed and signed in (`claude --version`)
32
32
  - `codex` CLI, installed and signed in (`codex --version`; optional if you only
33
33
  use Claude)
@@ -54,7 +54,8 @@ Installing the package only ships the program. It does not connect anything on
54
54
  its own. `subagent-mcp setup` finds your Claude Code or Codex install and
55
55
  registers both the server and the per-turn orchestration hooks. For Claude Code
56
56
  it also registers or wraps `statusLine` so the hook can read Claude's
57
- authoritative context percentage without replacing your custom statusline.
57
+ authoritative context percentage without replacing your custom statusline, and
58
+ deploys the `handoff-resume` Agent Skill to your Claude user scope.
58
59
  Preview first with `subagent-mcp setup --dry-run`.
59
60
 
60
61
  ### Restart, Then Turn On The Invariant
package/dist/doctor.js CHANGED
@@ -11,9 +11,9 @@ import { verifyWiring } from "./setup.js";
11
11
  export async function runDoctor() {
12
12
  console.log("subagent-mcp doctor (checks wiring, including Claude statusLine; repairs missing MCP registrations via vendor CLIs)\n");
13
13
  const major = Number(process.versions.node.split(".")[0]);
14
- console.log(` ${major >= 18 ? "PASS" : "FAIL"} node version — ${process.versions.node}` +
15
- (major >= 18 ? "" : " (Node >= 18 required)"));
16
- let failed = major < 18 ? 1 : 0;
14
+ console.log(` ${major >= 20 ? "PASS" : "FAIL"} node version — ${process.versions.node}` +
15
+ (major >= 20 ? "" : " (Node >= 20 required)"));
16
+ let failed = major < 20 ? 1 : 0;
17
17
  for (const r of verifyWiring(undefined, true)) {
18
18
  console.log(` ${r.ok ? "PASS" : "FAIL"} ${r.label} — ${r.detail}`);
19
19
  if (!r.ok)
package/dist/index.js CHANGED
@@ -572,7 +572,7 @@ const ORCHESTRATION_INSTRUCTIONS = "subagent-mcp - CANONICAL OPERATING MODEL (fu
572
572
  const SUBAGENT_INSTRUCTIONS = "SUB-AGENT SESSION: you are a child process launched by subagent-mcp. Follow the parent prompt. Do not treat yourself as the orchestrator, do not re-trigger orchestration carryover, and do not launch further sub-agents unless the parent prompt explicitly assigns that. launch_agent is code-capped at 2 spawn levels below the main orchestrator: depth 1 may launch depth 2 workers; depth 2 workers cannot spawn further.\n\nMODEL SELECTION MODE (parallel to orchestration-mode, set via the model-selection-mode tool). DEFAULT is \"smart\" and is used whenever unset: in smart, launch_agent REJECTS any call supplying provider/model/effort selectors and the server auto-picks the best model. \"user-approved-overrides\" opens a 30-MINUTE window where selectors are HONORED, enforced LAZILY (the mode reverts to smart on the next launch_agent call after 30 minutes) and re-enabling does NOT extend an active window. HONOR-BASED: you MUST NOT set \"user-approved-overrides\" without explicit interactive USER authorization via the structured-question tool (AskUserQuestion on Claude / request-user-input on Codex); never enable it on your own initiative.";
573
573
  const server = new McpServer({
574
574
  name: "subagent-mcp",
575
- version: "2.12.19",
575
+ version: "2.12.21",
576
576
  description: "Launches always-interactive local Claude and Codex sub-agent sessions and is the orchestrator's sole launch channel. Claude runs via the Claude Agent SDK over the local Claude Code executable; Codex via `codex app-server` over stdio. The server never calls Anthropic or OpenAI HTTP APIs directly.",
577
577
  }, {
578
578
  instructions: process.env.SUBAGENT_MCP_SUBAGENT === "1"
@@ -1696,7 +1696,7 @@ server.tool("orchestration-mode", "Toggle or query per-project ORCHESTRATION MOD
1696
1696
  ],
1697
1697
  };
1698
1698
  }));
1699
- // Tool 8: model-selection-mode
1699
+ // Tool 9: model-selection-mode
1700
1700
  server.tool("model-selection-mode", "Set or query per-project MODEL SELECTION MODE, which gates launch_agent's `provider`/`model`/`effort` selectors. `mode`: \"smart\" or \"user-approved-overrides\"; omit to query. \"smart\" is the DEFAULT (used whenever unset): launch_agent REJECTS any call supplying provider/model/effort and the server auto-picks the best model for the task_category. \"user-approved-overrides\" opens a 30-MINUTE window where selectors are HONORED, enforced LAZILY (reverts to smart on the next launch_agent call after the 30 min elapse); re-enabling does NOT extend an active window. HONOR-BASED, parallel to orchestration-mode: you MUST NOT set \"user-approved-overrides\" without explicit interactive USER authorization via the structured-question tool (AskUserQuestion on Claude / request-user-input on Codex; a plain yes/no if neither exists). This tool CANNOT verify that authorization — never enable on your own initiative. PERSISTENCE: state keyed by cwd; both the mode and the override-window timestamp survive server restarts (remaining window is restored, not reset).", {
1701
1701
  mode: z.enum(["smart", "user-approved-overrides"]).optional(),
1702
1702
  }, withMaintenance(async (params) => {
package/dist/setup.js CHANGED
@@ -41,6 +41,12 @@ export function serverPaths(root = INSTALL_ROOT) {
41
41
  codexHook: `${f}/dist/hooks/orchestration-codex.js`,
42
42
  };
43
43
  }
44
+ export function handoffResumeSkillPaths(root = INSTALL_ROOT, home = homedir()) {
45
+ return {
46
+ source: join(root, "skills", "handoff-resume", "SKILL.md"),
47
+ target: join(home, ".claude", "skills", "handoff-resume", "SKILL.md"),
48
+ };
49
+ }
44
50
  function statuslineCommand(shimPath, innerCommand = "") {
45
51
  const inner = innerCommand.trim();
46
52
  return `node "${shimPath}"${inner ? ` ${quoteStatuslineInnerArg(inner)}` : ""}`;
@@ -480,6 +486,51 @@ function describe(status, what) {
480
486
  else
481
487
  console.log(` ${what}: pointed at a stale path — repaired.`);
482
488
  }
489
+ export function deployHandoffResumeSkill(root = INSTALL_ROOT, home = homedir()) {
490
+ const { source, target } = handoffResumeSkillPaths(root, home);
491
+ if (!existsSync(source)) {
492
+ return {
493
+ changed: false,
494
+ status: "missing-source",
495
+ source,
496
+ target,
497
+ detail: `source missing at ${source}; reinstall @heretyc/subagent-mcp, then run subagent-mcp setup`,
498
+ };
499
+ }
500
+ const desired = readFileSync(source, "utf8");
501
+ if (existsSync(target) && readFileSync(target, "utf8") === desired) {
502
+ return { changed: false, status: "ok", source, target, detail: "deployed" };
503
+ }
504
+ const status = existsSync(target) ? "repaired" : "added";
505
+ if (!DRY_RUN) {
506
+ mkdirSync(dirname(target), { recursive: true });
507
+ writeFileSync(target, desired);
508
+ }
509
+ return { changed: true, status, source, target, detail: status === "added" ? "deployed" : "restored" };
510
+ }
511
+ export function verifyHandoffResumeSkill(root = INSTALL_ROOT, home = homedir()) {
512
+ const { source, target } = handoffResumeSkillPaths(root, home);
513
+ if (!existsSync(source)) {
514
+ return {
515
+ label: "claude: handoff-resume skill",
516
+ ok: false,
517
+ detail: "source missing from install - reinstall @heretyc/subagent-mcp",
518
+ };
519
+ }
520
+ if (!existsSync(target)) {
521
+ return {
522
+ label: "claude: handoff-resume skill",
523
+ ok: false,
524
+ detail: "missing - run subagent-mcp setup",
525
+ };
526
+ }
527
+ const ok = readFileSync(target, "utf8") === readFileSync(source, "utf8");
528
+ return {
529
+ label: "claude: handoff-resume skill",
530
+ ok,
531
+ detail: ok ? "deployed" : "stale - run subagent-mcp setup",
532
+ };
533
+ }
483
534
  export function vendorWireSpecs(p = serverPaths(), home = homedir()) {
484
535
  const claudeFile = join(home, ".claude.json");
485
536
  const codexDir = join(home, ".codex");
@@ -585,12 +636,33 @@ function wireClaude() {
585
636
  catch (e) {
586
637
  fail("claude", `could not write the settings.json hook: ${e.message}`);
587
638
  }
639
+ // 3) Claude Agent Skill for resuming saved handoffs.
640
+ try {
641
+ const r = deployHandoffResumeSkill(INSTALL_ROOT);
642
+ if (r.status === "missing-source") {
643
+ fail("claude", r.detail);
644
+ }
645
+ else {
646
+ if (r.status === "ok")
647
+ console.log(" handoff-resume skill: already correct.");
648
+ else if (r.status === "added")
649
+ console.log(" handoff-resume skill: added.");
650
+ else
651
+ console.log(" handoff-resume skill: restored from package copy.");
652
+ if (r.changed && DRY_RUN)
653
+ console.log(" (dry-run: not written)");
654
+ }
655
+ }
656
+ catch (e) {
657
+ fail("claude", `could not deploy the handoff-resume skill: ${e.message}`);
658
+ }
588
659
  }
589
660
  function wireCodex() {
590
661
  console.log("\n--- Codex CLI ---");
591
662
  const p = serverPaths();
592
663
  const codexDir = join(homedir(), ".codex");
593
664
  const specs = vendorWireSpecs(p);
665
+ // Codex has no Agent Skill mechanism; MCP instructions carry handoff guidance.
594
666
  // 1) config.toml — MCP server block (created if the file is missing).
595
667
  try {
596
668
  const existed = existsSync(specs.codex.configFile);
@@ -696,6 +768,7 @@ export function verifyWiring(root = INSTALL_ROOT, repair = false) {
696
768
  : "wired; waiting for Claude statusLine signal"
697
769
  : `${sl.status === "repaired" ? "stale path" : "not wired"} - run: subagent-mcp setup`,
698
770
  });
771
+ results.push(verifyHandoffResumeSkill(root, home));
699
772
  }
700
773
  else if (hasClaudeConfig) {
701
774
  const cj = readJson(join(home, ".claude.json"), {});
@@ -722,6 +795,7 @@ export function verifyWiring(root = INSTALL_ROOT, repair = false) {
722
795
  : "wired; waiting for Claude statusLine signal"
723
796
  : `${sl.status === "repaired" ? "stale path" : "not wired"} - run: subagent-mcp setup`,
724
797
  });
798
+ results.push(verifyHandoffResumeSkill(root, home));
725
799
  }
726
800
  const hasCodexCli = findOnPath("codex") !== null;
727
801
  const hasCodex = hasCodexCli || existsSync(join(home, ".codex"));
@@ -770,8 +844,8 @@ export async function runSetup() {
770
844
  console.log(`subagent-mcp setup${DRY_RUN ? " (dry-run)" : ""}`);
771
845
  console.log(`Install root: ${INSTALL_ROOT}\n`);
772
846
  const major = Number(process.versions.node.split(".")[0]);
773
- if (major < 18) {
774
- console.error(`ERROR: Node ${process.versions.node} is too old Node >= 18 required.`);
847
+ if (major < 20) {
848
+ console.error(`ERROR: Node ${process.versions.node} is too old. Node >= 20 required.`);
775
849
  process.exit(1);
776
850
  }
777
851
  const missing = verifyInstall();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heretyc/subagent-mcp",
3
- "version": "2.12.19",
3
+ "version": "2.12.21",
4
4
  "description": "MCP server that launches and manages always-interactive Claude Code and Codex sub-agent sessions (no direct Anthropic/OpenAI API).",
5
5
  "keywords": [
6
6
  "mcp",
@@ -25,6 +25,7 @@
25
25
  "files": [
26
26
  "dist",
27
27
  "directives",
28
+ "skills/handoff-resume",
28
29
  "scripts/postinstall.mjs",
29
30
  "LICENSE",
30
31
  "NOTICE",
@@ -61,7 +62,7 @@
61
62
  "typescript": "^7.0.2"
62
63
  },
63
64
  "engines": {
64
- "node": ">=18"
65
+ "node": ">=20"
65
66
  },
66
67
  "publishConfig": {
67
68
  "registry": "https://registry.npmjs.org",
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: handoff-resume
3
+ version: 1.0.0
4
+ description: Resume prior work from a saved subagent-mcp handoff when the user says "handoff-resume", "resume handoff", or "resume work"; call handoff-read, confirm intent with exactly 5 structured questions before acting, and know the handoff-write/read/clear lifecycle.
5
+ author: Lexi Blackburn (https://github.com/Heretyc/)
6
+ created: 2026-07-11
7
+ updated: 2026-07-11
8
+ ---
9
+
10
+ # Handoff Resume
11
+
12
+ When triggered, call the `handoff-read` MCP tool for the current cwd, then confirm the user's intent with EXACTLY 5 structured questions before acting on the saved handoff. `handoff-write` saves a compact resume record once 50% context utilization unlocks it. `handoff-read` retrieves the saved record for this cwd and binds reminder re-append behavior to this reading session. `handoff-clear` deletes the saved record and overflow file, if any, for this cwd.