@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
@@ -1,8 +1,8 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import os from 'node:os';
4
- import { SquadError } from '../errors.js';
5
- import { rejectIfMalformed, realpathOrSelf } from './path-internal.js';
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import { SquadError } from "../errors.js";
5
+ import { rejectIfMalformed, realpathOrSelf } from "./path-internal.js";
6
6
  let allowlistCache = null;
7
7
  /**
8
8
  * Test-only: clears the memoized allowlist so env-var changes take effect.
@@ -12,16 +12,16 @@ export function __resetOverrideAllowlistCache() {
12
12
  allowlistCache = null;
13
13
  }
14
14
  function isUnsafeOverrideEnabled() {
15
- return process.env.SQUAD_AGENTS_ALLOW_UNSAFE === '1';
15
+ return process.env.SQUAD_AGENTS_ALLOW_UNSAFE === "1";
16
16
  }
17
17
  function isUncOrDeviceNamespace(absolute) {
18
- if (process.platform !== 'win32')
18
+ if (process.platform !== "win32")
19
19
  return false;
20
- if (absolute.startsWith('\\\\?\\'))
20
+ if (absolute.startsWith("\\\\?\\"))
21
21
  return true;
22
- if (absolute.startsWith('\\\\.\\'))
22
+ if (absolute.startsWith("\\\\.\\"))
23
23
  return true;
24
- if (absolute.startsWith('\\\\'))
24
+ if (absolute.startsWith("\\\\"))
25
25
  return true;
26
26
  return false;
27
27
  }
@@ -31,15 +31,15 @@ async function buildAllowlist() {
31
31
  const roots = [];
32
32
  const seen = new Set();
33
33
  const candidates = [
34
- { source: 'home', raw: os.homedir() },
35
- { source: 'cwd', raw: process.cwd() },
34
+ { source: "home", raw: os.homedir() },
35
+ { source: "cwd", raw: process.cwd() },
36
36
  ];
37
- if (process.platform === 'win32') {
38
- candidates.push({ source: 'appdata', raw: process.env.APPDATA });
39
- candidates.push({ source: 'localappdata', raw: process.env.LOCALAPPDATA });
37
+ if (process.platform === "win32") {
38
+ candidates.push({ source: "appdata", raw: process.env.APPDATA });
39
+ candidates.push({ source: "localappdata", raw: process.env.LOCALAPPDATA });
40
40
  }
41
41
  else {
42
- candidates.push({ source: 'xdg_config_home', raw: process.env.XDG_CONFIG_HOME });
42
+ candidates.push({ source: "xdg_config_home", raw: process.env.XDG_CONFIG_HOME });
43
43
  }
44
44
  for (const c of candidates) {
45
45
  if (!c.raw)
@@ -69,13 +69,13 @@ function isInsideRoot(candidate, root) {
69
69
  if (candidate === root)
70
70
  return true;
71
71
  const rel = path.relative(root, candidate);
72
- if (rel === '' || rel === '.')
72
+ if (rel === "" || rel === ".")
73
73
  return true;
74
74
  if (path.isAbsolute(rel))
75
75
  return false;
76
- if (rel === '..')
76
+ if (rel === "..")
77
77
  return false;
78
- if (rel.startsWith('..' + path.sep))
78
+ if (rel.startsWith(".." + path.sep))
79
79
  return false;
80
80
  return true;
81
81
  }
@@ -103,14 +103,14 @@ export async function validateOverrideDir(rawDir) {
103
103
  try {
104
104
  rejectIfMalformed(rawDir);
105
105
  }
106
- catch (err) {
107
- return { ok: false, reason: 'malformed', rejectedPath: rawDir };
106
+ catch {
107
+ return { ok: false, reason: "malformed", rejectedPath: rawDir };
108
108
  }
109
109
  if (!path.isAbsolute(rawDir)) {
110
- return { ok: false, reason: 'not_absolute', rejectedPath: rawDir };
110
+ return { ok: false, reason: "not_absolute", rejectedPath: rawDir };
111
111
  }
112
112
  if (isUncOrDeviceNamespace(rawDir)) {
113
- return { ok: false, reason: 'unc_or_device_namespace', rejectedPath: rawDir };
113
+ return { ok: false, reason: "unc_or_device_namespace", rejectedPath: rawDir };
114
114
  }
115
115
  const lexical = path.normalize(rawDir);
116
116
  const real = await realpathOrSelf(lexical);
@@ -129,9 +129,16 @@ export async function validateOverrideDir(rawDir) {
129
129
  break;
130
130
  }
131
131
  }
132
- const reason = lexicalMatchExists ? 'symlink_escape' : 'outside_allowlist';
132
+ const reason = lexicalMatchExists
133
+ ? "symlink_escape"
134
+ : "outside_allowlist";
133
135
  if (unsafe) {
134
- return { ok: true, resolvedPath: real, allowlistMatch: 'unsafe_override', unsafeOverride: true };
136
+ return {
137
+ ok: true,
138
+ resolvedPath: real,
139
+ allowlistMatch: "unsafe_override",
140
+ unsafeOverride: true,
141
+ };
135
142
  }
136
143
  return { ok: false, reason, rejectedPath: rawDir };
137
144
  }
@@ -140,7 +147,7 @@ export async function validateOverrideDir(rawDir) {
140
147
  * Caller decides whether to throw or downgrade to a warn-and-fallback.
141
148
  */
142
149
  export function rejectionToError(fail, allowlistSize) {
143
- return new SquadError('OVERRIDE_REJECTED', `override directory rejected: ${fail.reason}`, {
150
+ return new SquadError("OVERRIDE_REJECTED", `override directory rejected: ${fail.reason}`, {
144
151
  reason: fail.reason,
145
152
  path: fail.rejectedPath,
146
153
  allowlist_size: allowlistSize,
@@ -169,7 +176,9 @@ export async function validateOverrideFile(validatedDirReal, fileName) {
169
176
  const normalized = path.normalize(fileName);
170
177
  if (path.isAbsolute(normalized))
171
178
  return null;
172
- if (normalized === '..' || normalized.startsWith('..' + path.sep) || normalized.includes(path.sep + '..' + path.sep)) {
179
+ if (normalized === ".." ||
180
+ normalized.startsWith(".." + path.sep) ||
181
+ normalized.includes(path.sep + ".." + path.sep)) {
173
182
  return null;
174
183
  }
175
184
  const candidate = path.resolve(validatedDirReal, normalized);
@@ -1 +1 @@
1
- {"version":3,"file":"override-allowlist.js","sourceRoot":"","sources":["../../src/util/override-allowlist.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"override-allowlist.js","sourceRoot":"","sources":["../../src/util/override-allowlist.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,21 @@
1
- import { promises as fs } from 'node:fs';
2
- import { SquadError } from '../errors.js';
1
+ import { promises as fs } from "node:fs";
2
+ import { SquadError } from "../errors.js";
3
3
  /**
4
4
  * Internal helpers shared between path-safety.ts and override-allowlist.ts.
5
5
  * Exported only for intra-`util/` reuse; do not import from outside src/util/.
6
6
  */
7
7
  export function rejectIfMalformed(file) {
8
- if (file.includes('\0')) {
9
- throw new SquadError('PATH_INVALID', 'file path contains NUL byte', { file });
8
+ if (file.includes("\0")) {
9
+ throw new SquadError("PATH_INVALID", "file path contains NUL byte", { file });
10
10
  }
11
- if (file.startsWith('~')) {
12
- throw new SquadError('PATH_INVALID', 'file path starts with ~ (tilde expansion not supported)', { file });
11
+ if (file.startsWith("~")) {
12
+ throw new SquadError("PATH_INVALID", "file path starts with ~ (tilde expansion not supported)", { file });
13
13
  }
14
- const adsIndex = file.indexOf(':', 2);
14
+ const adsIndex = file.indexOf(":", 2);
15
15
  if (adsIndex !== -1) {
16
- throw new SquadError('PATH_INVALID', 'file path contains ADS marker (:) after drive letter', { file });
16
+ throw new SquadError("PATH_INVALID", "file path contains ADS marker (:) after drive letter", {
17
+ file,
18
+ });
17
19
  }
18
20
  }
19
21
  export async function realpathOrSelf(p) {
@@ -1 +1 @@
1
- {"version":3,"file":"path-internal.js","sourceRoot":"","sources":["../../src/util/path-internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;GAGG;AAEH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,6BAA6B,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,yDAAyD,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5G,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACtC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,sDAAsD,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACzG,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,CAAS;IAC5C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"path-internal.js","sourceRoot":"","sources":["../../src/util/path-internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;GAGG;AAEH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,6BAA6B,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,UAAU,CAClB,cAAc,EACd,yDAAyD,EACzD,EAAE,IAAI,EAAE,CACT,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACtC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,sDAAsD,EAAE;YAC3F,IAAI;SACL,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,CAAS;IAC5C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
@@ -3,6 +3,21 @@ export interface SafePathContext {
3
3
  rootRealCache: Map<string, string>;
4
4
  }
5
5
  export declare function createSafePathContext(): SafePathContext;
6
+ /**
7
+ * Lexical-only containment check for a config-supplied relative path
8
+ * (e.g. `.squad.yaml` `learnings.path` / `tasks.path`).
9
+ *
10
+ * Sync; no filesystem access. Throws PATH_TRAVERSAL_DENIED if `configuredPath`
11
+ * is absolute, or escapes `workspaceRoot` after lexical normalization. Used at
12
+ * the boundary where the LLM-controllable config first becomes a real fs path
13
+ * — without this, `.squad.yaml` with `learnings.path: ../../etc/whatever` gives
14
+ * an arbitrary-write primitive (CWE-22).
15
+ *
16
+ * Does NOT resolve symlinks. The config itself lives inside the workspace, so
17
+ * TOCTOU symlink swap is not in this gateway's threat model — the writer side
18
+ * (resolveSafePath) handles that for the data write path.
19
+ */
20
+ export declare function ensureRelativeInsideRoot(workspaceRoot: string, configuredPath: string, settingName: string): void;
6
21
  /**
7
22
  * Resolve a user-supplied file path safely against a workspace root.
8
23
  *
@@ -1,11 +1,39 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { SquadError } from '../errors.js';
4
- import { rejectIfMalformed, realpathOrSelf } from './path-internal.js';
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { SquadError } from "../errors.js";
4
+ import { rejectIfMalformed, realpathOrSelf } from "./path-internal.js";
5
5
  export const MAX_BYTES = 16_384;
6
6
  export function createSafePathContext() {
7
7
  return { rootRealCache: new Map() };
8
8
  }
9
+ /**
10
+ * Lexical-only containment check for a config-supplied relative path
11
+ * (e.g. `.squad.yaml` `learnings.path` / `tasks.path`).
12
+ *
13
+ * Sync; no filesystem access. Throws PATH_TRAVERSAL_DENIED if `configuredPath`
14
+ * is absolute, or escapes `workspaceRoot` after lexical normalization. Used at
15
+ * the boundary where the LLM-controllable config first becomes a real fs path
16
+ * — without this, `.squad.yaml` with `learnings.path: ../../etc/whatever` gives
17
+ * an arbitrary-write primitive (CWE-22).
18
+ *
19
+ * Does NOT resolve symlinks. The config itself lives inside the workspace, so
20
+ * TOCTOU symlink swap is not in this gateway's threat model — the writer side
21
+ * (resolveSafePath) handles that for the data write path.
22
+ */
23
+ export function ensureRelativeInsideRoot(workspaceRoot, configuredPath, settingName) {
24
+ if (path.isAbsolute(configuredPath)) {
25
+ throw new SquadError("PATH_TRAVERSAL_DENIED", `${settingName} must be a workspace-relative path, not absolute`, { setting: settingName, configuredPath });
26
+ }
27
+ const rootAbs = path.resolve(workspaceRoot);
28
+ const candidateAbs = path.resolve(rootAbs, configuredPath);
29
+ const rel = path.relative(rootAbs, candidateAbs);
30
+ if (path.isAbsolute(rel) || rel === ".." || rel.startsWith(".." + path.sep)) {
31
+ throw new SquadError("PATH_TRAVERSAL_DENIED", `${settingName} escapes workspace_root`, {
32
+ setting: settingName,
33
+ configuredPath,
34
+ });
35
+ }
36
+ }
9
37
  /**
10
38
  * Resolve a user-supplied file path safely against a workspace root.
11
39
  *
@@ -20,13 +48,15 @@ export function createSafePathContext() {
20
48
  export async function resolveSafePath(workspaceRoot, file, ctx) {
21
49
  rejectIfMalformed(file);
22
50
  if (workspaceRoot === undefined) {
23
- if (path.isAbsolute(file) || file.includes('..')) {
24
- throw new SquadError('PATH_REQUIRES_WORKSPACE', 'absolute or traversal-bearing path requires workspace_root', { file });
51
+ if (path.isAbsolute(file) || file.includes("..")) {
52
+ throw new SquadError("PATH_REQUIRES_WORKSPACE", "absolute or traversal-bearing path requires workspace_root", { file });
25
53
  }
26
54
  return file;
27
55
  }
28
56
  if (!path.isAbsolute(workspaceRoot)) {
29
- throw new SquadError('PATH_INVALID', 'workspace_root must be absolute', { workspaceRoot });
57
+ throw new SquadError("PATH_INVALID", "workspace_root must be absolute", {
58
+ workspaceRoot,
59
+ });
30
60
  }
31
61
  const rootNormalized = path.normalize(workspaceRoot);
32
62
  let rootReal = ctx.rootRealCache.get(rootNormalized);
@@ -37,8 +67,12 @@ export async function resolveSafePath(workspaceRoot, file, ctx) {
37
67
  const fileNormalized = path.normalize(file);
38
68
  const candidateAbs = path.resolve(rootReal, fileNormalized);
39
69
  const lexicalRel = path.relative(rootReal, candidateAbs);
40
- if (path.isAbsolute(lexicalRel) || lexicalRel === '..' || lexicalRel.startsWith('..' + path.sep)) {
41
- throw new SquadError('PATH_TRAVERSAL_DENIED', 'path escapes workspace_root (lexical)', { file });
70
+ if (path.isAbsolute(lexicalRel) ||
71
+ lexicalRel === ".." ||
72
+ lexicalRel.startsWith(".." + path.sep)) {
73
+ throw new SquadError("PATH_TRAVERSAL_DENIED", "path escapes workspace_root (lexical)", {
74
+ file,
75
+ });
42
76
  }
43
77
  let candidateExists = false;
44
78
  try {
@@ -51,8 +85,8 @@ export async function resolveSafePath(workspaceRoot, file, ctx) {
51
85
  if (candidateExists) {
52
86
  const candidateReal = await realpathOrSelf(candidateAbs);
53
87
  const realRel = path.relative(rootReal, candidateReal);
54
- if (path.isAbsolute(realRel) || realRel === '..' || realRel.startsWith('..' + path.sep)) {
55
- throw new SquadError('PATH_TRAVERSAL_DENIED', 'path escapes workspace_root (after realpath)', { file });
88
+ if (path.isAbsolute(realRel) || realRel === ".." || realRel.startsWith(".." + path.sep)) {
89
+ throw new SquadError("PATH_TRAVERSAL_DENIED", "path escapes workspace_root (after realpath)", { file });
56
90
  }
57
91
  return candidateReal;
58
92
  }
@@ -67,7 +101,7 @@ export async function resolveSafePath(workspaceRoot, file, ctx) {
67
101
  export async function readSnippet(absPath) {
68
102
  let fh;
69
103
  try {
70
- fh = await fs.open(absPath, 'r');
104
+ fh = await fs.open(absPath, "r");
71
105
  }
72
106
  catch {
73
107
  return null;
@@ -76,7 +110,7 @@ export async function readSnippet(absPath) {
76
110
  const buf = Buffer.alloc(MAX_BYTES);
77
111
  const { bytesRead } = await fh.read(buf, 0, MAX_BYTES, 0);
78
112
  return {
79
- content: buf.slice(0, bytesRead).toString('utf8'),
113
+ content: buf.slice(0, bytesRead).toString("utf8"),
80
114
  truncated: bytesRead === MAX_BYTES,
81
115
  };
82
116
  }
@@ -1 +1 @@
1
- {"version":3,"file":"path-safety.js","sourceRoot":"","sources":["../../src/util/path-safety.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"path-safety.js","sourceRoot":"","sources":["../../src/util/path-safety.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gempack/squad-mcp",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
4
4
  "description": "MCP server for the squad-dev workflow: classification, risk scoring, agent selection, advisory orchestration",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -37,7 +37,12 @@
37
37
  "dev": "tsx src/index.ts",
38
38
  "test": "vitest run",
39
39
  "test:watch": "vitest",
40
- "lint": "tsc --noEmit",
40
+ "test:coverage": "vitest run --coverage",
41
+ "smoke": "node tests/smoke.mjs",
42
+ "typecheck": "tsc --noEmit",
43
+ "lint": "tsc --noEmit && eslint .",
44
+ "format": "prettier --write .",
45
+ "format:check": "prettier --check .",
41
46
  "prepublishOnly": "npm run build"
42
47
  },
43
48
  "files": [
@@ -75,8 +80,14 @@
75
80
  "devDependencies": {
76
81
  "@types/js-yaml": "^4.0.9",
77
82
  "@types/node": "^22.0.0",
83
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
84
+ "@typescript-eslint/parser": "^8.0.0",
85
+ "@vitest/coverage-v8": "^2.1.0",
86
+ "eslint": "^9.0.0",
87
+ "prettier": "^3.3.0",
78
88
  "tsx": "^4.19.0",
79
89
  "typescript": "^5.6.0",
90
+ "typescript-eslint": "^8.0.0",
80
91
  "vitest": "^2.1.0"
81
92
  }
82
93
  }
@@ -1,24 +1,26 @@
1
1
  # Skill: Squad Dev
2
2
 
3
3
  ## Objective
4
+
4
5
  Development skill that takes a user prompt, builds an implementation plan, runs gated advisory with specialized agents, implements, and consolidates via TechLead-Consolidator. Codex is optional (`/squad --codex`) and may be auto-suggested when the plan is high-risk.
5
6
 
6
7
  ## Skill Name
8
+
7
9
  `/squad`
8
10
 
9
11
  ## Agent Registry
10
12
 
11
- | subagent_type | Purpose |
12
- | -------------------------- | ------------------------------------------- |
13
- | `po` | Business value, UX, requirements fit |
14
- | `tech-lead-planner` | Pre-implementation trade-offs and viability |
15
- | `tech-lead-consolidator` | Post-implementation final verdict |
16
- | `senior-architect` | Boundaries, DI, scalability |
17
- | `senior-dba` | Queries, migrations, EF, cache |
18
- | `senior-developer` | Correctness, robustness, APIs, observability|
19
- | `senior-dev-reviewer` | Readability, idioms, naming |
20
- | `senior-dev-security` | OWASP, authz, sensitive data |
21
- | `senior-qa` | Test coverage, strategy, reliability |
13
+ | subagent_type | Purpose |
14
+ | ------------------------ | -------------------------------------------- |
15
+ | `po` | Business value, UX, requirements fit |
16
+ | `tech-lead-planner` | Pre-implementation trade-offs and viability |
17
+ | `tech-lead-consolidator` | Post-implementation final verdict |
18
+ | `senior-architect` | Boundaries, DI, scalability |
19
+ | `senior-dba` | Queries, migrations, EF, cache |
20
+ | `senior-developer` | Correctness, robustness, APIs, observability |
21
+ | `senior-dev-reviewer` | Readability, idioms, naming |
22
+ | `senior-dev-security` | OWASP, authz, sensitive data |
23
+ | `senior-qa` | Test coverage, strategy, reliability |
22
24
 
23
25
  ## General Flow
24
26
 
@@ -86,11 +88,13 @@ Summary + modified files + tests + validations + rollback plan + next steps.
86
88
  ## Phase Details
87
89
 
88
90
  ### Phase 0 — Pre-Check
91
+
89
92
  1. Run `git status`; capture current branch.
90
93
  2. If uncommitted, unrelated changes are present, warn and ask the user before proceeding.
91
94
  3. Record starting SHA for the delivery report.
92
95
 
93
96
  ### Phase 1 — Understanding and Risk
97
+
94
98
  - Read `$ARGUMENTS`; detect `--codex`.
95
99
  - Classify type: Feature / Bug Fix / Refactor / Performance / Security / Business Rule.
96
100
  - Explore the codebase (Glob, Grep, Read) to locate the affected area and patterns.
@@ -188,6 +192,7 @@ Be direct. If the plan is good, say so. Do not invent problems.
188
192
  Absorb relevant suggestions and show an adjusted-plan diff summary.
189
193
 
190
194
  ### Phase 4 — Gate 1: User Approval
195
+
191
196
  Present the final plan and wait for explicit approval. Do not proceed without it.
192
197
 
193
198
  ### Phase 5 — Advisory Squad
@@ -204,6 +209,7 @@ Present the final plan and wait for explicit approval. Do not proceed without it
204
209
  | Business Rule | po, senior-developer, senior-qa | +senior-dba if data-bound |
205
210
 
206
211
  **Hard conditionals based on touched files:**
212
+
207
213
  - Query / Migration / EF / Cache → `senior-dba` required
208
214
  - DI / Boundaries / new project or module → `senior-architect` required
209
215
  - Endpoint / Auth / Middleware → `senior-dev-security` required
@@ -237,13 +243,16 @@ Stay inside your ownership. Forward anything outside your scope.
237
243
  Send all selected agents in a single message with multiple tool calls so they run in parallel.
238
244
 
239
245
  ### Phase 6 — Gate 2: Blocker Halt
246
+
240
247
  - Any advisory Blocker → HALT. Surface blockers and ask the user how to proceed (revise plan, accept risk, abort).
241
248
  - Major/Minor → proceed, capturing them as acceptance criteria for implementation.
242
249
 
243
250
  ### Phase 7 — Escalation Round (optional)
251
+
244
252
  If an advisory agent forwarded a Blocker/Major to an agent that was not selected, spawn that missing agent with only that forwarded item (not a full review).
245
253
 
246
254
  ### Phase 8 — Implementation
255
+
247
256
  - Follow the plan and advisory acceptance criteria.
248
257
  - Read → Edit/Write each file. Respect project patterns.
249
258
  - Method names in English. No emojis.
@@ -285,6 +294,7 @@ Be direct. If it is good, say so. Do not request cosmetic refactors.
285
294
  Spawn `tech-lead-consolidator` with every advisory report and the delivered delta. Consolidator produces the final verdict and rollback plan.
286
295
 
287
296
  ### Phase 11 — Gate 3: Reject Loop (max 2 iterations)
297
+
288
298
  - APPROVED / CHANGES REQUIRED (non-blocker) → apply fixes, then deliver.
289
299
  - REJECTED → apply the fix list, re-run affected agents on the delta, re-consolidate.
290
300
  - After 2 iterations, stop and hand the situation to the user.
@@ -338,13 +348,13 @@ Spawn `tech-lead-consolidator` with every advisory report and the delivered delt
338
348
 
339
349
  ## Skill Parameters
340
350
 
341
- | Parameter | Type | Default | Description |
342
- |-----------|--------|---------|-------------|
343
- | --codex | flag | off | Enable Codex for plan validation and implementation review |
351
+ | Parameter | Type | Default | Description |
352
+ | --------- | ------ | ------- | ---------------------------------------------------------------------------------- |
353
+ | --codex | flag | off | Enable Codex for plan validation and implementation review |
344
354
  | --quick | flag | off | Quick mode (see below). Trades depth for speed. Mutually exclusive with `--codex`. |
345
- | squad | string | auto | Specific squad or "auto" for detection |
346
- | plan-only | bool | false | Build the plan only, do not execute |
347
- | verbose | bool | false | Show individual agent reports inline |
355
+ | squad | string | auto | Specific squad or "auto" for detection |
356
+ | plan-only | bool | false | Build the plan only, do not execute |
357
+ | verbose | bool | false | Show individual agent reports inline |
348
358
 
349
359
  ## Quick Mode (`--quick`)
350
360
 
@@ -352,16 +362,16 @@ Reduced agent set, terse prompts, condensed delivery. Suitable for small fixes,
352
362
 
353
363
  Phase deltas vs. normal mode:
354
364
 
355
- | Phase | Normal | Quick |
356
- |-------|--------|-------|
357
- | Plan | Full plan with risks/decisions/tests | Condensed: objective, files, top 1-2 risks. Skip alternatives table. |
358
- | Codex plan validation | Opt-in via `--codex` | Force-disabled. `--quick --codex` is rejected. |
359
- | User approval gate | Always required | Auto-proceed when risk Low AND scope ≤3 files AND no security/data path. Otherwise still gates. |
360
- | Squad | Auto-detect 3-7 specialists + tech-lead | Hard cap: 1 specialist + tech-lead. Specialist = work-type primary. |
361
- | Agent prompts | Full template | "Flag only Blocker/Major. ≤200 words. No long template. If clean, reply 'No issues in scope.'" |
362
- | Codex review | Opt-in | Skipped (force-disabled with `--quick`) |
363
- | Tech-lead consolidator | Always | Skipped when zero Blocker/Major from specialist |
364
- | Delivery | Full report | Condensed: objective, files, tests, residual risks |
365
+ | Phase | Normal | Quick |
366
+ | ---------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------- |
367
+ | Plan | Full plan with risks/decisions/tests | Condensed: objective, files, top 1-2 risks. Skip alternatives table. |
368
+ | Codex plan validation | Opt-in via `--codex` | Force-disabled. `--quick --codex` is rejected. |
369
+ | User approval gate | Always required | Auto-proceed when risk Low AND scope ≤3 files AND no security/data path. Otherwise still gates. |
370
+ | Squad | Auto-detect 3-7 specialists + tech-lead | Hard cap: 1 specialist + tech-lead. Specialist = work-type primary. |
371
+ | Agent prompts | Full template | "Flag only Blocker/Major. ≤200 words. No long template. If clean, reply 'No issues in scope.'" |
372
+ | Codex review | Opt-in | Skipped (force-disabled with `--quick`) |
373
+ | Tech-lead consolidator | Always | Skipped when zero Blocker/Major from specialist |
374
+ | Delivery | Full report | Condensed: objective, files, tests, residual risks |
365
375
 
366
376
  Critical-change auto-fallback: if scope touches `auth`, `crypto`, `permissions`, `Program.cs`, `Startup.cs`, migrations, EF mappings, or `appsettings`, fall back to normal mode with warning `Quick mode disabled — change touches security/data layer. Running full workflow.`.
367
377
 
@@ -387,6 +397,7 @@ Critical-change auto-fallback: if scope touches `auth`, `crypto`, `permissions`,
387
397
  ```
388
398
 
389
399
  ## Inviolable Rules
400
+
390
401
  1. Every implementation starts from a plan (approved explicitly, or auto-proceeded under `--quick` when risk Low).
391
402
  2. Codex only runs with user consent (flag or confirmed auto-suggestion). Never combined with `--quick`.
392
403
  3. TechLead-Consolidator always delivers the final verdict in normal mode. Under `--quick`, skipped only when the specialist reports zero Blocker/Major findings.