continuous-improvement 3.11.0 → 3.15.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.
Files changed (76) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/CHANGELOG.md +65 -1
  3. package/QUICKSTART.md +1 -1
  4. package/README.md +39 -18
  5. package/SKILL.md +1 -1
  6. package/bin/check-skill-count.mjs +32 -1
  7. package/bin/check-test-imports-only.mjs +1 -1
  8. package/bin/check-tool-count.mjs +129 -0
  9. package/bin/generate-plugin-manifests.mjs +3 -1
  10. package/bin/harvest-friction.mjs +1 -1
  11. package/bin/install.mjs +77 -3
  12. package/bin/mcp-server.mjs +66 -9
  13. package/bin/plan-pack.mjs +77 -0
  14. package/bin/unified-cli.mjs +55 -410
  15. package/commands/harvest.md +1 -1
  16. package/commands/model-forward.md +13 -0
  17. package/commands/production-readiness-review.md +53 -0
  18. package/commands/ship.md +57 -0
  19. package/commands/superpowers.md +1 -1
  20. package/hooks/companion-preference.mjs +31 -19
  21. package/hooks/gateguard.mjs +59 -25
  22. package/hooks/hook-pack.mjs +110 -0
  23. package/hooks/recall-briefing.mjs +167 -0
  24. package/lib/gateguard-state.mjs +62 -13
  25. package/lib/goal-state.mjs +13 -9
  26. package/lib/hook-pack-gate.mjs +65 -0
  27. package/lib/install-targets.mjs +121 -0
  28. package/lib/plan-review-packet.mjs +96 -0
  29. package/lib/plugin-metadata.mjs +33 -7
  30. package/lib/recall-briefing.mjs +57 -0
  31. package/lib/recall-index.mjs +2 -2
  32. package/lib/skill-distill.mjs +141 -0
  33. package/llms.txt +2 -2
  34. package/package.json +6 -4
  35. package/plugins/beginner.json +3 -3
  36. package/plugins/continuous-improvement/.claude-plugin/marketplace.json +2 -2
  37. package/plugins/continuous-improvement/.claude-plugin/plugin.json +2 -2
  38. package/plugins/continuous-improvement/README.md +1 -1
  39. package/plugins/continuous-improvement/agents/README.md +3 -3
  40. package/plugins/continuous-improvement/bin/mcp-server.mjs +66 -9
  41. package/plugins/continuous-improvement/commands/harvest.md +1 -1
  42. package/plugins/continuous-improvement/commands/model-forward.md +13 -0
  43. package/plugins/continuous-improvement/commands/production-readiness-review.md +53 -0
  44. package/plugins/continuous-improvement/commands/ship.md +57 -0
  45. package/plugins/continuous-improvement/commands/superpowers.md +1 -1
  46. package/plugins/continuous-improvement/hooks/companion-preference.mjs +31 -19
  47. package/plugins/continuous-improvement/hooks/gateguard.mjs +59 -25
  48. package/plugins/continuous-improvement/hooks/hook-pack.mjs +110 -0
  49. package/plugins/continuous-improvement/hooks/hooks.json +16 -1
  50. package/plugins/continuous-improvement/hooks/recall-briefing.mjs +167 -0
  51. package/plugins/continuous-improvement/lib/gateguard-state.mjs +62 -13
  52. package/plugins/continuous-improvement/lib/goal-state.mjs +13 -9
  53. package/plugins/continuous-improvement/lib/hook-pack-gate.mjs +65 -0
  54. package/plugins/continuous-improvement/lib/plugin-metadata.mjs +33 -7
  55. package/plugins/continuous-improvement/lib/recall-briefing.mjs +57 -0
  56. package/plugins/continuous-improvement/lib/recall-index.mjs +2 -2
  57. package/plugins/continuous-improvement/lib/skill-distill.mjs +141 -0
  58. package/plugins/continuous-improvement/skills/README.md +1 -1
  59. package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +1 -1
  60. package/plugins/continuous-improvement/skills/gateguard/SKILL.md +4 -4
  61. package/plugins/continuous-improvement/skills/goal-monitor/SKILL.md +1 -1
  62. package/plugins/continuous-improvement/skills/handoff/SKILL.md +0 -1
  63. package/plugins/continuous-improvement/skills/model-forward/SKILL.md +44 -0
  64. package/plugins/continuous-improvement/skills/superpowers/SKILL.md +1 -1
  65. package/plugins/expert.json +6 -2
  66. package/skills/README.md +4 -2
  67. package/skills/gateguard.md +4 -4
  68. package/skills/goal-monitor.md +1 -1
  69. package/skills/handoff.md +0 -1
  70. package/skills/model-forward.md +44 -0
  71. package/skills/superpowers.md +1 -1
  72. package/lib/compound-engineering.mjs +0 -831
  73. package/lib/pm-skills.mjs +0 -1274
  74. package/lib/unified-plugin.mjs +0 -924
  75. package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +0 -108
  76. package/skills/para-memory-files.md +0 -108
@@ -3,7 +3,7 @@
3
3
  * continuous-improvement MCP Server
4
4
  *
5
5
  * Exposes instincts, observations, and reflection as MCP tools + resources.
6
- * Two modes: beginner (3 tools) and expert (all tools).
6
+ * Two modes: beginner (4 tools) and expert (all tools).
7
7
  *
8
8
  * Usage:
9
9
  * node bin/mcp-server.mjs # default: beginner mode
@@ -13,15 +13,15 @@
13
13
  import { execSync } from "node:child_process";
14
14
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
15
15
  import { homedir } from "node:os";
16
- import { basename, dirname, join } from "node:path";
16
+ import { basename, dirname, join, resolve } from "node:path";
17
17
  import { createInterface } from "node:readline";
18
18
  import { fileURLToPath } from "node:url";
19
19
  import { createHash } from "node:crypto";
20
20
  import { PACKAGE_NAME, VERSION, getToolDefinitions, isPluginMode, } from "../lib/plugin-metadata.mjs";
21
21
  import { formatDriftReport, parseGoalFromPlan, scoreObservations, } from "../lib/goal-state.mjs";
22
22
  import { buildIndex, formatRecallHits, parseSince, query as queryRecall, } from "../lib/recall-index.mjs";
23
- import { draftFromCandidate, extractTrajectories, findCandidates, formatCandidates, serializeDraft, } from "../lib/skill-distill.mjs";
24
- import { MAX_CLEARED_FILES, clearFiles, resolveSessionDir, } from "../lib/gateguard-state.mjs";
23
+ import { draftFromCandidate, draftFromWorkflowRun, extractTrajectories, findCandidates, formatCandidates, serializeDraft, workflowRunFromObservations, } from "../lib/skill-distill.mjs";
24
+ import { MAX_CLEARED_FILES, canonicalizeFileKey, clearFiles, resolveInstinctsRoot, resolveSessionDir, } from "../lib/gateguard-state.mjs";
25
25
  function getHomeDir() {
26
26
  return process.env.HOME || process.env.USERPROFILE || homedir();
27
27
  }
@@ -508,10 +508,11 @@ function handleTool(name, params) {
508
508
  }
509
509
  case "ci_gateguard_clear": {
510
510
  // Beginner-available on purpose: the GateGuard hook fires for every
511
- // install, so the clearance action must too. Resolves the session dir via
512
- // gateguard-state (canonical), the same way the hook does, so the marker
513
- // lands where the hook looks regardless of how each process spelled the
514
- // project root.
511
+ // install, so the clearance action must too. The hook's block reason now
512
+ // prints state_path (the session-scoped state file); honoring it writes
513
+ // the marker exactly where the hook looks. Without it the MCP server can't
514
+ // know the caller's session, so it falls back to the canonical session dir
515
+ // — correct only on the legacy unscoped path.
515
516
  const rawList = Array.isArray(params.file_paths) ? params.file_paths : [];
516
517
  const listPaths = rawList.filter((value) => typeof value === "string" && value.length > 0);
517
518
  const single = getString(params.file_path).trim();
@@ -519,7 +520,24 @@ function handleTool(name, params) {
519
520
  if (paths.length === 0) {
520
521
  return error("file_paths is required — pass the file path(s) named in the GateGuard block reason, e.g. { file_paths: [\"src/x.ts\"] }.");
521
522
  }
522
- const sessionDir = resolveSessionDir();
523
+ // state_path is a model-controlled argument, so it could be a traversal
524
+ // string (`../../etc/...`). dirname leaves `..` segments for the OS to
525
+ // resolve at write time, so without a bound this is an arbitrary-write
526
+ // primitive. Resolve + canonicalize, then require containment within the
527
+ // instincts root (the only tree the hook ever prints a state_path inside).
528
+ const rawStatePath = getString(params.state_path).trim();
529
+ let sessionDir;
530
+ if (rawStatePath) {
531
+ const resolvedKey = canonicalizeFileKey(resolve(rawStatePath));
532
+ const rootKey = canonicalizeFileKey(resolveInstinctsRoot());
533
+ if (resolvedKey !== rootKey && !resolvedKey.startsWith(`${rootKey}/`)) {
534
+ return error("state_path must resolve inside ~/.claude/instincts/. Pass it verbatim from the GateGuard block reason.");
535
+ }
536
+ sessionDir = dirname(resolve(rawStatePath));
537
+ }
538
+ else {
539
+ sessionDir = resolveSessionDir();
540
+ }
523
541
  const { cleared, skippedForCap } = clearFiles(sessionDir, paths);
524
542
  const lines = [
525
543
  "## GateGuard clearance",
@@ -837,6 +855,45 @@ function handleTool(name, params) {
837
855
  "```",
838
856
  ].join("\n"));
839
857
  }
858
+ case "ci_distill_from_workflow": {
859
+ if (MODE !== "expert") {
860
+ return error("ci_distill_from_workflow requires expert mode");
861
+ }
862
+ const run = workflowRunFromObservations(readDistillObservations(project.hash));
863
+ if (!run) {
864
+ return text("No completed-and-verified Workflow run found in this project's observations. " +
865
+ "A run qualifies when a `Workflow` tool call is followed by a passing verify/test/build in the same feed. " +
866
+ "Run a workflow, verify its output, then try `ci_distill_from_workflow` again.");
867
+ }
868
+ const draftInstinct = draftFromWorkflowRun(run);
869
+ if (!isSafeDraftId(draftInstinct.id)) {
870
+ return error(`Internal error: generated draft id "${draftInstinct.id}" failed the safety check.`);
871
+ }
872
+ const draft = serializeDraft(draftInstinct);
873
+ const draftsDir = join(INSTINCTS_DIR, project.hash, "drafts");
874
+ const draftPath = join(draftsDir, `${draftInstinct.id}.yaml`);
875
+ try {
876
+ mkdirSync(draftsDir, { recursive: true });
877
+ writeFileSync(draftPath, draft);
878
+ }
879
+ catch (err) {
880
+ return error(`Failed to write draft to ${draftPath}: ${err instanceof Error ? err.message : String(err)}`);
881
+ }
882
+ return text([
883
+ "## Draft written from a verified workflow run",
884
+ "",
885
+ `**Workflow:** ${run.name}`,
886
+ `**Path:** ${draftPath}`,
887
+ "",
888
+ "Edit the body to capture the real recipe (preconditions, concrete steps, gotchas), then promote with:",
889
+ "",
890
+ ` ci_distill_promote id=${draftInstinct.id}`,
891
+ "",
892
+ "```yaml",
893
+ draft.trimEnd(),
894
+ "```",
895
+ ].join("\n"));
896
+ }
840
897
  case "ci_distill_promote": {
841
898
  if (MODE !== "expert") {
842
899
  return error("ci_distill_promote requires expert mode");
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * plan-pack (`ci-plan-pack`).
4
+ *
5
+ * Turn a plan doc into a commentable review packet a colleague can mark up.
6
+ *
7
+ * node bin/plan-pack.mjs <plan.md> write <plan>.review.md
8
+ * node bin/plan-pack.mjs <plan.md> --stdout print the packet to stdout
9
+ * node bin/plan-pack.mjs <plan.md> --gh-issue write the packet, then print a
10
+ * ready-to-run `gh issue create`
11
+ * command (does NOT auto-post)
12
+ */
13
+ import { readFileSync, writeFileSync } from "node:fs";
14
+ import { extname } from "node:path";
15
+ import { pathToFileURL } from "node:url";
16
+ import { buildReviewPacket } from "../lib/plan-review-packet.mjs";
17
+ function getErrorMessage(error) {
18
+ return error instanceof Error ? error.message : String(error);
19
+ }
20
+ function reviewPathFor(source) {
21
+ const ext = extname(source);
22
+ return ext ? `${source.slice(0, -ext.length)}.review${ext}` : `${source}.review.md`;
23
+ }
24
+ function packetTitle(packet) {
25
+ const match = /^# Review packet: (.*)$/m.exec(packet);
26
+ return match ? match[1].trim() : "Plan review";
27
+ }
28
+ const HELP = `
29
+ plan-pack (ci-plan-pack) - turn a plan doc into a commentable review packet
30
+
31
+ Usage: ci-plan-pack <plan.md> [--stdout] [--gh-issue]
32
+
33
+ Options:
34
+ --stdout Print the packet to stdout instead of writing a file
35
+ --gh-issue Write the packet, then print a 'gh issue create' command
36
+ (does not post anything - you run it)
37
+
38
+ Examples:
39
+ ci-plan-pack docs/plans/2026-06-15-plan-pack.md
40
+ ci-plan-pack docs/plans/2026-06-15-plan-pack.md --stdout
41
+ `;
42
+ function main() {
43
+ const args = process.argv.slice(2);
44
+ if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
45
+ console.log(HELP);
46
+ process.exit(args.length === 0 ? 1 : 0);
47
+ }
48
+ const toStdout = args.includes("--stdout");
49
+ const ghIssue = args.includes("--gh-issue");
50
+ const source = args.find((a) => !a.startsWith("-"));
51
+ if (!source) {
52
+ throw new Error("Usage: ci-plan-pack <plan.md> [--stdout] [--gh-issue]");
53
+ }
54
+ const markdown = readFileSync(source, "utf8");
55
+ const packet = buildReviewPacket(markdown, { source });
56
+ if (toStdout) {
57
+ process.stdout.write(packet.endsWith("\n") ? packet : `${packet}\n`);
58
+ return;
59
+ }
60
+ const outPath = reviewPathFor(source);
61
+ writeFileSync(outPath, packet.endsWith("\n") ? packet : `${packet}\n`);
62
+ console.log(`Wrote review packet: ${outPath}`);
63
+ if (ghIssue) {
64
+ const title = packetTitle(packet);
65
+ console.log("\nTo open it for comments on GitHub, run:");
66
+ console.log(` gh issue create --title "${title}" --body-file "${outPath}"`);
67
+ }
68
+ }
69
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
70
+ try {
71
+ main();
72
+ }
73
+ catch (error) {
74
+ console.error(`Error: ${getErrorMessage(error)}`);
75
+ process.exit(1);
76
+ }
77
+ }