@gempack/squad-mcp 0.6.4 → 0.7.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 (111) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +6 -3
  3. package/CHANGELOG.md +37 -0
  4. package/INSTALL.md +15 -0
  5. package/README.md +32 -0
  6. package/agents/product-owner.md +9 -0
  7. package/agents/senior-architect.md +12 -0
  8. package/agents/senior-dba.md +15 -1
  9. package/agents/senior-dev-reviewer.md +100 -29
  10. package/agents/senior-dev-security.md +13 -0
  11. package/agents/senior-developer.md +15 -0
  12. package/agents/senior-qa.md +13 -0
  13. package/agents/tech-lead-consolidator.md +10 -0
  14. package/agents/tech-lead-planner.md +9 -0
  15. package/commands/squad-next.md +24 -0
  16. package/commands/squad-task.md +29 -0
  17. package/commands/squad-tasks.md +21 -0
  18. package/dist/config/ownership-matrix.js +4 -20
  19. package/dist/config/ownership-matrix.js.map +1 -1
  20. package/dist/config/squad-yaml.js +3 -7
  21. package/dist/config/squad-yaml.js.map +1 -1
  22. package/dist/errors.js.map +1 -1
  23. package/dist/exec/git.d.ts +1 -1
  24. package/dist/exec/git.js +0 -0
  25. package/dist/exec/git.js.map +1 -1
  26. package/dist/format/pr-review.js +1 -3
  27. package/dist/format/pr-review.js.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/learning/format.js +1 -5
  31. package/dist/learning/format.js.map +1 -1
  32. package/dist/learning/store.js +89 -16
  33. package/dist/learning/store.js.map +1 -1
  34. package/dist/observability/logger.d.ts +2 -2
  35. package/dist/observability/logger.js +20 -20
  36. package/dist/observability/logger.js.map +1 -1
  37. package/dist/prompts/registry.js.map +1 -1
  38. package/dist/resources/agent-loader.js.map +1 -1
  39. package/dist/resources/registry.js +28 -28
  40. package/dist/tasks/select.js.map +1 -1
  41. package/dist/tasks/store.js +49 -11
  42. package/dist/tasks/store.js.map +1 -1
  43. package/dist/tools/_shared/schemas.d.ts +21 -0
  44. package/dist/tools/_shared/schemas.js +25 -0
  45. package/dist/tools/_shared/schemas.js.map +1 -0
  46. package/dist/tools/agents.d.ts +3 -3
  47. package/dist/tools/agents.js +9 -9
  48. package/dist/tools/agents.js.map +1 -1
  49. package/dist/tools/classify-work-type.d.ts +5 -5
  50. package/dist/tools/classify-work-type.js +0 -0
  51. package/dist/tools/classify-work-type.js.map +1 -1
  52. package/dist/tools/compose-advisory-bundle.js +4 -14
  53. package/dist/tools/compose-advisory-bundle.js.map +1 -1
  54. package/dist/tools/compose-prd-parse.js.map +1 -1
  55. package/dist/tools/compose-squad-workflow.js +0 -0
  56. package/dist/tools/compose-squad-workflow.js.map +1 -1
  57. package/dist/tools/consolidate.js +1 -3
  58. package/dist/tools/consolidate.js.map +1 -1
  59. package/dist/tools/detect-changed-files.d.ts +5 -6
  60. package/dist/tools/detect-changed-files.js +0 -0
  61. package/dist/tools/detect-changed-files.js.map +1 -1
  62. package/dist/tools/list-tasks.js +1 -8
  63. package/dist/tools/list-tasks.js.map +1 -1
  64. package/dist/tools/next-task.js +1 -8
  65. package/dist/tools/next-task.js.map +1 -1
  66. package/dist/tools/read-learnings.js +2 -4
  67. package/dist/tools/read-learnings.js.map +1 -1
  68. package/dist/tools/read-squad-config.js +1 -1
  69. package/dist/tools/read-squad-config.js.map +1 -1
  70. package/dist/tools/record-tasks.js.map +1 -1
  71. package/dist/tools/registry.js +2 -4
  72. package/dist/tools/registry.js.map +1 -1
  73. package/dist/tools/score-risk.d.ts +3 -3
  74. package/dist/tools/score-risk.js +15 -15
  75. package/dist/tools/score-rubric.js.map +1 -1
  76. package/dist/tools/select-squad.d.ts +5 -5
  77. package/dist/tools/select-squad.js +0 -0
  78. package/dist/tools/select-squad.js.map +1 -1
  79. package/dist/tools/slice-files-for-task.js.map +1 -1
  80. package/dist/tools/slice-files.d.ts +2 -2
  81. package/dist/tools/slice-files.js +0 -0
  82. package/dist/tools/slice-files.js.map +1 -1
  83. package/dist/tools/update-task-status.js +1 -8
  84. package/dist/tools/update-task-status.js.map +1 -1
  85. package/dist/tools/validate-plan-text.d.ts +3 -3
  86. package/dist/tools/validate-plan-text.js +0 -0
  87. package/dist/tools/validate-plan-text.js.map +1 -1
  88. package/dist/util/file-lock.d.ts +10 -0
  89. package/dist/util/file-lock.js +102 -0
  90. package/dist/util/file-lock.js.map +1 -0
  91. package/dist/util/override-allowlist.d.ts +4 -4
  92. package/dist/util/override-allowlist.js +36 -27
  93. package/dist/util/override-allowlist.js.map +1 -1
  94. package/dist/util/path-internal.js +10 -8
  95. package/dist/util/path-internal.js.map +1 -1
  96. package/dist/util/path-safety.d.ts +15 -0
  97. package/dist/util/path-safety.js +47 -13
  98. package/dist/util/path-safety.js.map +1 -1
  99. package/package.json +13 -2
  100. package/shared/Skill-Squad-Dev.md +38 -27
  101. package/shared/Skill-Squad-Review.md +49 -26
  102. package/shared/_Severity-and-Ownership.md +6 -6
  103. package/skills/brainstorm/SKILL.md +31 -20
  104. package/skills/commit-suggest/SKILL.md +32 -14
  105. package/tools/_tasks-io.mjs +25 -16
  106. package/tools/list-tasks.mjs +1 -4
  107. package/tools/next-task.mjs +4 -13
  108. package/tools/post-review.mjs +20 -30
  109. package/tools/record-learning.mjs +8 -11
  110. package/tools/record-tasks.mjs +2 -9
  111. package/tools/update-task-status.mjs +2 -9
@@ -77,8 +77,7 @@ function parseArgs(argv) {
77
77
  }
78
78
  }
79
79
  if (!out.pr) fail(2, "--pr <number> is required");
80
- if (!/^\d+$/.test(out.pr))
81
- fail(2, `--pr must be a positive integer, got "${out.pr}"`);
80
+ if (!/^\d+$/.test(out.pr)) fail(2, `--pr must be a positive integer, got "${out.pr}"`);
82
81
  return out;
83
82
  }
84
83
 
@@ -100,10 +99,7 @@ function ensureGh() {
100
99
  const r = spawnSync("gh", ["--version"], { encoding: "utf8" });
101
100
  if (r.error) {
102
101
  if (r.error.code === "ENOENT") {
103
- fail(
104
- 3,
105
- "gh CLI not found in PATH. Install: https://cli.github.com/manual/installation",
106
- );
102
+ fail(3, "gh CLI not found in PATH. Install: https://cli.github.com/manual/installation");
107
103
  }
108
104
  fail(3, `gh check failed: ${r.error.message}`);
109
105
  }
@@ -121,8 +117,19 @@ function runGh(args, body) {
121
117
  proc.stderr.on("data", (d) => (stderr += d));
122
118
  proc.on("error", reject);
123
119
  proc.on("close", (code) => resolve({ code, stdout, stderr }));
124
- proc.stdin.write(body);
125
- proc.stdin.end();
120
+ proc.stdin.on("error", reject);
121
+ // Respect backpressure: if the kernel pipe is full, write() returns false
122
+ // and we must wait for "drain" before continuing. Pre-fix this code wrote
123
+ // a large body without awaiting drain, which on small pipe buffers
124
+ // truncated the body silently (gh exits 0 with the prefix only).
125
+ const ok = proc.stdin.write(body, (err) => {
126
+ if (err) reject(err);
127
+ });
128
+ if (ok) {
129
+ proc.stdin.end();
130
+ } else {
131
+ proc.stdin.once("drain", () => proc.stdin.end());
132
+ }
126
133
  });
127
134
  }
128
135
 
@@ -145,11 +152,7 @@ async function main() {
145
152
  } catch (err) {
146
153
  fail(2, `invalid JSON on stdin: ${err.message}`);
147
154
  }
148
- if (
149
- !consolidation ||
150
- typeof consolidation !== "object" ||
151
- !consolidation.verdict
152
- ) {
155
+ if (!consolidation || typeof consolidation !== "object" || !consolidation.verdict) {
153
156
  fail(
154
157
  2,
155
158
  "stdin JSON missing required `verdict` field — expected output of apply_consolidation_rules",
@@ -169,14 +172,7 @@ async function main() {
169
172
  body = body.replace(/\n\n---\n[\s\S]*$/, "\n");
170
173
  }
171
174
 
172
- const ghArgs = [
173
- "pr",
174
- "review",
175
- opts.pr,
176
- `--${payload.action}`,
177
- "--body-file",
178
- "-",
179
- ];
175
+ const ghArgs = ["pr", "review", opts.pr, `--${payload.action}`, "--body-file", "-"];
180
176
  if (opts.repo) ghArgs.push("--repo", opts.repo);
181
177
 
182
178
  if (opts.dryRun) {
@@ -186,25 +182,19 @@ async function main() {
186
182
  );
187
183
  process.stdout.write(body);
188
184
  process.stdout.write(`EOF\n`);
189
- process.stdout.write(
190
- `\n# Action: ${payload.action}\n# Summary: ${payload.summary}\n`,
191
- );
185
+ process.stdout.write(`\n# Action: ${payload.action}\n# Summary: ${payload.summary}\n`);
192
186
  process.exit(0);
193
187
  }
194
188
 
195
189
  ensureGh();
196
190
  const r = await runGh(ghArgs, body);
197
191
  if (r.code !== 0) {
198
- process.stderr.write(
199
- `gh ${payload.action} failed (exit ${r.code}):\n${r.stderr}`,
200
- );
192
+ process.stderr.write(`gh ${payload.action} failed (exit ${r.code}):\n${r.stderr}`);
201
193
  process.exit(4);
202
194
  }
203
195
  // gh prints the review URL on success; surface it to the caller.
204
196
  if (r.stdout) process.stdout.write(r.stdout);
205
- process.stdout.write(
206
- `\nposted: ${payload.action} on PR #${opts.pr} | ${payload.summary}\n`,
207
- );
197
+ process.stdout.write(`\nposted: ${payload.action} on PR #${opts.pr} | ${payload.summary}\n`);
208
198
  }
209
199
 
210
200
  main().catch((err) => {
@@ -32,6 +32,7 @@
32
32
 
33
33
  import { promises as fs } from "node:fs";
34
34
  import path from "node:path";
35
+ import { ensureRelativeInsideRoot } from "./_tasks-io.mjs";
35
36
 
36
37
  const args = process.argv.slice(2);
37
38
 
@@ -57,13 +58,11 @@ function parseArgs(argv) {
57
58
  const a = argv[i];
58
59
  switch (a) {
59
60
  case "--accept":
60
- if (out.decision)
61
- fail(2, "--accept and --reject are mutually exclusive");
61
+ if (out.decision) fail(2, "--accept and --reject are mutually exclusive");
62
62
  out.decision = "accept";
63
63
  break;
64
64
  case "--reject":
65
- if (out.decision)
66
- fail(2, "--accept and --reject are mutually exclusive");
65
+ if (out.decision) fail(2, "--accept and --reject are mutually exclusive");
67
66
  out.decision = "reject";
68
67
  break;
69
68
  case "--agent":
@@ -127,16 +126,14 @@ async function main() {
127
126
  if (opts.branch) entry.branch = opts.branch;
128
127
  if (opts.scope) entry.scope = opts.scope;
129
128
 
130
- const target = path.resolve(
131
- opts.workspace,
132
- opts.file ?? ".squad/learnings.jsonl",
133
- );
129
+ if (opts.file !== undefined) {
130
+ ensureRelativeInsideRoot(opts.workspace, opts.file, "learnings.path");
131
+ }
132
+ const target = path.resolve(opts.workspace, opts.file ?? ".squad/learnings.jsonl");
134
133
  await fs.mkdir(path.dirname(target), { recursive: true });
135
134
  await fs.appendFile(target, JSON.stringify(entry) + "\n", "utf8");
136
135
 
137
- process.stdout.write(
138
- `recorded: ${opts.decision} on ${opts.agent} — "${opts.finding}"\n`,
139
- );
136
+ process.stdout.write(`recorded: ${opts.decision} on ${opts.agent} — "${opts.finding}"\n`);
140
137
  process.stdout.write(`file: ${target}\n`);
141
138
  }
142
139
 
@@ -25,12 +25,7 @@
25
25
  // validates the full zod schema.
26
26
 
27
27
  import { promises as fs } from "node:fs";
28
- import {
29
- readTasksFile,
30
- writeTasksFile,
31
- VALID_PRIORITIES,
32
- fail,
33
- } from "./_tasks-io.mjs";
28
+ import { readTasksFile, writeTasksFile, VALID_PRIORITIES, fail } from "./_tasks-io.mjs";
34
29
 
35
30
  const args = process.argv.slice(2);
36
31
  const PROG = "record-tasks";
@@ -101,9 +96,7 @@ function validateInputs(inputs) {
101
96
 
102
97
  async function main() {
103
98
  const opts = parseArgs(args);
104
- const raw = opts.input
105
- ? await fs.readFile(opts.input, "utf8")
106
- : await readStdin();
99
+ const raw = opts.input ? await fs.readFile(opts.input, "utf8") : await readStdin();
107
100
 
108
101
  let inputs;
109
102
  try {
@@ -16,12 +16,7 @@
16
16
  // 0 success
17
17
  // 2 invalid input or task/subtask not found
18
18
 
19
- import {
20
- readTasksFile,
21
- writeTasksFile,
22
- VALID_STATUSES,
23
- fail,
24
- } from "./_tasks-io.mjs";
19
+ import { readTasksFile, writeTasksFile, VALID_STATUSES, fail } from "./_tasks-io.mjs";
25
20
 
26
21
  const args = process.argv.slice(2);
27
22
  const PROG = "update-task-status";
@@ -87,9 +82,7 @@ async function main() {
87
82
  const original = data.tasks[idx];
88
83
 
89
84
  if (opts.subtask !== null) {
90
- const sIdx = (original.subtasks ?? []).findIndex(
91
- (s) => s.id === opts.subtask,
92
- );
85
+ const sIdx = (original.subtasks ?? []).findIndex((s) => s.id === opts.subtask);
93
86
  if (sIdx < 0) {
94
87
  fail(PROG, 2, `subtask ${opts.subtask} not found on task ${opts.task}`);
95
88
  }