@gempack/squad-mcp 0.3.1 → 0.6.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 +2 -2
  2. package/.claude-plugin/plugin.json +4 -2
  3. package/CHANGELOG.md +395 -8
  4. package/INSTALL.md +554 -0
  5. package/README.md +311 -25
  6. package/agents/{Skill-Squad-Dev.md → _shared/Skill-Squad-Dev.md} +30 -3
  7. package/agents/{Skill-Squad-Review.md → _shared/Skill-Squad-Review.md} +70 -0
  8. package/agents/{PO.md → product-owner.md} +33 -1
  9. package/agents/{Senior-Architect.md → senior-architect.md} +33 -1
  10. package/agents/{Senior-DBA.md → senior-dba.md} +33 -1
  11. package/agents/senior-dev-reviewer.md +640 -0
  12. package/agents/{Senior-Dev-Security.md → senior-dev-security.md} +33 -1
  13. package/agents/{Senior-Developer.md → senior-developer.md} +33 -1
  14. package/agents/{Senior-QA.md → senior-qa.md} +33 -1
  15. package/agents/{TechLead-Consolidator.md → tech-lead-consolidator.md} +7 -1
  16. package/agents/{TechLead-Planner.md → tech-lead-planner.md} +7 -1
  17. package/commands/brainstorm.md +21 -0
  18. package/commands/commit-suggest.md +12 -0
  19. package/commands/squad-review.md +10 -58
  20. package/commands/squad.md +11 -70
  21. package/dist/config/ownership-matrix.d.ts +24 -2
  22. package/dist/config/ownership-matrix.js +466 -139
  23. package/dist/config/ownership-matrix.js.map +1 -1
  24. package/dist/config/squad-yaml.d.ts +242 -0
  25. package/dist/config/squad-yaml.js +403 -0
  26. package/dist/config/squad-yaml.js.map +1 -0
  27. package/dist/errors.d.ts +1 -1
  28. package/dist/errors.js +1 -1
  29. package/dist/errors.js.map +1 -1
  30. package/dist/format/pr-review.d.ts +61 -0
  31. package/dist/format/pr-review.js +146 -0
  32. package/dist/format/pr-review.js.map +1 -0
  33. package/dist/index.js +19 -13
  34. package/dist/index.js.map +1 -1
  35. package/dist/learning/format.d.ts +29 -0
  36. package/dist/learning/format.js +55 -0
  37. package/dist/learning/format.js.map +1 -0
  38. package/dist/learning/store.d.ts +102 -0
  39. package/dist/learning/store.js +169 -0
  40. package/dist/learning/store.js.map +1 -0
  41. package/dist/resources/agent-loader.d.ts +14 -2
  42. package/dist/resources/agent-loader.js +235 -53
  43. package/dist/resources/agent-loader.js.map +1 -1
  44. package/dist/tasks/select.d.ts +64 -0
  45. package/dist/tasks/select.js +84 -0
  46. package/dist/tasks/select.js.map +1 -0
  47. package/dist/tasks/store.d.ts +338 -0
  48. package/dist/tasks/store.js +321 -0
  49. package/dist/tasks/store.js.map +1 -0
  50. package/dist/tools/agents.js +4 -1
  51. package/dist/tools/agents.js.map +1 -1
  52. package/dist/tools/compose-advisory-bundle.d.ts +5 -5
  53. package/dist/tools/compose-advisory-bundle.js +24 -12
  54. package/dist/tools/compose-advisory-bundle.js.map +1 -1
  55. package/dist/tools/compose-prd-parse.d.ts +53 -0
  56. package/dist/tools/compose-prd-parse.js +167 -0
  57. package/dist/tools/compose-prd-parse.js.map +1 -0
  58. package/dist/tools/compose-squad-workflow.d.ts +28 -10
  59. package/dist/tools/compose-squad-workflow.js +0 -0
  60. package/dist/tools/compose-squad-workflow.js.map +1 -1
  61. package/dist/tools/consolidate.d.ts +55 -4
  62. package/dist/tools/consolidate.js +87 -15
  63. package/dist/tools/consolidate.js.map +1 -1
  64. package/dist/tools/expand-task.d.ts +51 -0
  65. package/dist/tools/expand-task.js +35 -0
  66. package/dist/tools/expand-task.js.map +1 -0
  67. package/dist/tools/list-tasks.d.ts +31 -0
  68. package/dist/tools/list-tasks.js +50 -0
  69. package/dist/tools/list-tasks.js.map +1 -0
  70. package/dist/tools/next-task.d.ts +37 -0
  71. package/dist/tools/next-task.js +60 -0
  72. package/dist/tools/next-task.js.map +1 -0
  73. package/dist/tools/read-learnings.d.ts +53 -0
  74. package/dist/tools/read-learnings.js +72 -0
  75. package/dist/tools/read-learnings.js.map +1 -0
  76. package/dist/tools/read-squad-config.d.ts +23 -0
  77. package/dist/tools/read-squad-config.js +34 -0
  78. package/dist/tools/read-squad-config.js.map +1 -0
  79. package/dist/tools/record-learning.d.ts +62 -0
  80. package/dist/tools/record-learning.js +80 -0
  81. package/dist/tools/record-learning.js.map +1 -0
  82. package/dist/tools/record-tasks.d.ts +71 -0
  83. package/dist/tools/record-tasks.js +45 -0
  84. package/dist/tools/record-tasks.js.map +1 -0
  85. package/dist/tools/registry.d.ts +1 -1
  86. package/dist/tools/registry.js +71 -39
  87. package/dist/tools/registry.js.map +1 -1
  88. package/dist/tools/score-rubric.d.ts +74 -0
  89. package/dist/tools/score-rubric.js +140 -0
  90. package/dist/tools/score-rubric.js.map +1 -0
  91. package/dist/tools/slice-files-for-task.d.ts +31 -0
  92. package/dist/tools/slice-files-for-task.js +52 -0
  93. package/dist/tools/slice-files-for-task.js.map +1 -0
  94. package/dist/tools/update-task-status.d.ts +29 -0
  95. package/dist/tools/update-task-status.js +35 -0
  96. package/dist/tools/update-task-status.js.map +1 -0
  97. package/dist/util/override-allowlist.d.ts +63 -0
  98. package/dist/util/override-allowlist.js +191 -0
  99. package/dist/util/override-allowlist.js.map +1 -0
  100. package/dist/util/path-internal.d.ts +6 -0
  101. package/dist/util/path-internal.js +27 -0
  102. package/dist/util/path-internal.js.map +1 -0
  103. package/dist/util/path-safety.js +0 -0
  104. package/dist/util/path-safety.js.map +1 -1
  105. package/package.json +5 -1
  106. package/skills/brainstorm/SKILL.md +284 -0
  107. package/skills/commit-suggest/SKILL.md +255 -0
  108. package/skills/squad/SKILL.md +454 -0
  109. package/tools/post-review.mjs +212 -0
  110. package/agents/Senior-Dev-Reviewer.md +0 -104
  111. /package/agents/{_Severity-and-Ownership.md → _shared/_Severity-and-Ownership.md} +0 -0
@@ -0,0 +1,140 @@
1
+ import { z } from "zod";
2
+ import { AGENT_NAMES_TUPLE, AGENTS, DEFAULT_RUBRIC_WEIGHTS, } from "../config/ownership-matrix.js";
3
+ /**
4
+ * Per-agent dimension score from an advisory pass. Scores are 0-100 (higher is
5
+ * better). Reports without a score (e.g. legacy clients, unsupported agents,
6
+ * `not_evaluated: true`) are simply omitted from the rubric.
7
+ */
8
+ const dimensionScoreSchema = z.object({
9
+ agent: z.enum(AGENT_NAMES_TUPLE),
10
+ score: z.number().min(0).max(100),
11
+ rationale: z.string().max(2048).optional(),
12
+ });
13
+ /**
14
+ * Repo override of weights. Keys are agent names; values 0-100. The set of
15
+ * supplied keys must sum to 100 (validated). Agents absent from this object
16
+ * fall back to DEFAULT_RUBRIC_WEIGHTS for that name. Useful when a project
17
+ * wants to ignore a dimension entirely (set its weight to 0 and redistribute).
18
+ */
19
+ const weightOverridesSchema = z
20
+ .record(z.enum(AGENT_NAMES_TUPLE), z.number().min(0).max(100))
21
+ .optional();
22
+ const schema = z.object({
23
+ scores: z.array(dimensionScoreSchema).max(50),
24
+ weights: weightOverridesSchema,
25
+ threshold: z.number().min(0).max(100).optional().default(75),
26
+ });
27
+ const BAR_WIDTH = 20;
28
+ function renderBar(score) {
29
+ const filled = Math.round((score / 100) * BAR_WIDTH);
30
+ return "█".repeat(filled) + "░".repeat(BAR_WIDTH - filled);
31
+ }
32
+ function formatScorecard(out) {
33
+ const header = `SQUAD RUBRIC — weighted ${out.weighted_score.toFixed(1)} / 100 (threshold ${out.threshold})`;
34
+ const verdictLine = out.passes_threshold ? "PASS" : "BELOW THRESHOLD";
35
+ const lines = out.dimensions.map((d) => {
36
+ const flag = d.below_threshold ? " ⚠" : " ";
37
+ const dim = d.dimension.padEnd(20);
38
+ const bar = renderBar(d.score);
39
+ const score = String(d.score).padStart(3);
40
+ const weight = `×${d.weight.toString().padStart(2)}%`;
41
+ return `${dim} ${bar} ${score} ${weight} ${d.agent}${flag}`;
42
+ });
43
+ return [header, "─".repeat(70), ...lines, "─".repeat(70), verdictLine].join("\n");
44
+ }
45
+ /**
46
+ * Compute the weighted-rubric scorecard from per-agent dimension scores.
47
+ *
48
+ * Math:
49
+ * - Reduce supplied scores to the subset of agents present.
50
+ * - Resolve weights: override (if provided AND keys sum to 100) > default.
51
+ * - For each scored agent, contribution = score * weight / 100.
52
+ * - weighted_score = sum of contributions normalised so weights sum to 100
53
+ * across the agents that ACTUALLY scored. (If only 6 of 9 agents scored,
54
+ * the rubric renormalises across those 6 instead of leaving 3 dimensions
55
+ * contributing 0 to the weighted average.)
56
+ * - Dimensions below `threshold` are flagged.
57
+ *
58
+ * Returns a RubricOutput; meta-agents (weight 0) and unscored agents are listed
59
+ * in `ignored_agents`.
60
+ */
61
+ export function scoreRubric(input) {
62
+ const overrides = input.weights;
63
+ let weights;
64
+ let weightsSource;
65
+ if (overrides && Object.keys(overrides).length > 0) {
66
+ const overrideSum = Object.values(overrides).reduce((acc, v) => acc + v, 0);
67
+ if (Math.abs(overrideSum - 100) > 0.01) {
68
+ throw new Error(`weights override must sum to 100, got ${overrideSum}. Supplied: ${JSON.stringify(overrides)}`);
69
+ }
70
+ weights = { ...DEFAULT_RUBRIC_WEIGHTS, ...overrides };
71
+ weightsSource = "override";
72
+ }
73
+ else {
74
+ weights = { ...DEFAULT_RUBRIC_WEIGHTS };
75
+ weightsSource = "default";
76
+ }
77
+ // Build the dimension list from scores actually supplied.
78
+ const scoredAgents = new Set(input.scores.map((s) => s.agent));
79
+ const ignored = [];
80
+ for (const agentName of AGENT_NAMES_TUPLE) {
81
+ if (!scoredAgents.has(agentName)) {
82
+ // Either unscored OR weight 0 (meta-agent). Both go to ignored, distinguished by weight.
83
+ ignored.push(agentName);
84
+ }
85
+ }
86
+ // Effective weight base: sum of weights across agents that actually scored AND have weight > 0.
87
+ // We renormalise to this base so the weighted score reflects only the dimensions evaluated.
88
+ let weightBase = 0;
89
+ for (const s of input.scores) {
90
+ weightBase += weights[s.agent] ?? 0;
91
+ }
92
+ const dimensions = [];
93
+ let weightedScore = 0;
94
+ if (weightBase > 0) {
95
+ for (const s of input.scores) {
96
+ const w = weights[s.agent] ?? 0;
97
+ if (w === 0) {
98
+ // Meta-agent that somehow emitted a score — ignore from rubric, surface in ignored.
99
+ if (!ignored.includes(s.agent))
100
+ ignored.push(s.agent);
101
+ continue;
102
+ }
103
+ const normalisedWeight = (w / weightBase) * 100;
104
+ const contribution = (s.score * normalisedWeight) / 100;
105
+ dimensions.push({
106
+ agent: s.agent,
107
+ dimension: AGENTS[s.agent].dimension,
108
+ score: s.score,
109
+ weight: Math.round(normalisedWeight * 10) / 10,
110
+ contribution: Math.round(contribution * 10) / 10,
111
+ rationale: s.rationale,
112
+ below_threshold: s.score < input.threshold,
113
+ });
114
+ weightedScore += contribution;
115
+ }
116
+ }
117
+ weightedScore = Math.round(weightedScore * 10) / 10;
118
+ // Sort dimensions by descending weight so the most important come first.
119
+ dimensions.sort((a, b) => b.weight - a.weight);
120
+ const partial = {
121
+ weighted_score: weightedScore,
122
+ threshold: input.threshold,
123
+ passes_threshold: weightedScore >= input.threshold,
124
+ dimensions,
125
+ ignored_agents: ignored,
126
+ weights_source: weightsSource,
127
+ };
128
+ return { ...partial, scorecard_text: formatScorecard(partial) };
129
+ }
130
+ export const scoreRubricTool = {
131
+ name: "score_rubric",
132
+ description: "Compute a weighted multi-dimensional rubric scorecard from per-agent advisory scores (0-100). " +
133
+ "Each agent represents one dimension (Architecture, Security, Testing, etc.) with a default weight; " +
134
+ "weights can be overridden per-repo via .squad.yaml. Returns weighted_score, per-dimension breakdown, " +
135
+ "pass/fail vs threshold (default 75), and a pre-formatted ASCII scorecard. " +
136
+ "Renormalises across agents that actually scored, so a partial advisory pass produces a meaningful score.",
137
+ schema,
138
+ handler: scoreRubric,
139
+ };
140
+ //# sourceMappingURL=score-rubric.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score-rubric.js","sourceRoot":"","sources":["../../src/tools/score-rubric.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+ import type { ToolDef } from "./registry.js";
3
+ declare const schema: z.ZodObject<{
4
+ workspace_root: z.ZodString;
5
+ task_id: z.ZodNumber;
6
+ files: z.ZodArray<z.ZodString, "many">;
7
+ }, "strip", z.ZodTypeAny, {
8
+ files: string[];
9
+ workspace_root: string;
10
+ task_id: number;
11
+ }, {
12
+ files: string[];
13
+ workspace_root: string;
14
+ task_id: number;
15
+ }>;
16
+ type Input = z.infer<typeof schema>;
17
+ export interface SliceFilesForTaskOutput {
18
+ task_id: number;
19
+ scope: string | null;
20
+ matched: string[];
21
+ unmatched: string[];
22
+ }
23
+ /**
24
+ * Filter a file list down to those that fall inside a task's scope glob.
25
+ * When the task has no scope (repo-wide), all files match. Wraps the same
26
+ * `matchesGlob` primitive used by skip_paths and learnings scope filters —
27
+ * single source of glob semantics across squad-mcp.
28
+ */
29
+ export declare function sliceFilesForTaskTool(input: Input): Promise<SliceFilesForTaskOutput>;
30
+ export declare const sliceFilesForTaskToolDef: ToolDef<typeof schema>;
31
+ export {};
@@ -0,0 +1,52 @@
1
+ import { z } from "zod";
2
+ import { readTasks } from "../tasks/store.js";
3
+ import { matchesGlob, readSquadYaml } from "../config/squad-yaml.js";
4
+ import { resolveSafePath, createSafePathContext } from "../util/path-safety.js";
5
+ import { SquadError } from "../errors.js";
6
+ const schema = z.object({
7
+ workspace_root: z.string().min(1).max(4096),
8
+ task_id: z.number().int().positive(),
9
+ files: z.array(z.string().min(1).max(4096)).max(10_000),
10
+ });
11
+ /**
12
+ * Filter a file list down to those that fall inside a task's scope glob.
13
+ * When the task has no scope (repo-wide), all files match. Wraps the same
14
+ * `matchesGlob` primitive used by skip_paths and learnings scope filters —
15
+ * single source of glob semantics across squad-mcp.
16
+ */
17
+ export async function sliceFilesForTaskTool(input) {
18
+ const ctx = createSafePathContext();
19
+ const safeRoot = await resolveSafePath(input.workspace_root, ".", ctx);
20
+ const config = await readSquadYaml(safeRoot);
21
+ const file = await readTasks(safeRoot, { configuredPath: config.tasks.path });
22
+ const task = file.tasks.find((t) => t.id === input.task_id);
23
+ if (!task) {
24
+ throw new SquadError("INVALID_INPUT", `task ${input.task_id} not found in store`);
25
+ }
26
+ if (!task.scope) {
27
+ return {
28
+ task_id: input.task_id,
29
+ scope: null,
30
+ matched: [...input.files],
31
+ unmatched: [],
32
+ };
33
+ }
34
+ const matched = [];
35
+ const unmatched = [];
36
+ for (const f of input.files) {
37
+ if (matchesGlob(task.scope, f)) {
38
+ matched.push(f);
39
+ }
40
+ else {
41
+ unmatched.push(f);
42
+ }
43
+ }
44
+ return { task_id: input.task_id, scope: task.scope, matched, unmatched };
45
+ }
46
+ export const sliceFilesForTaskToolDef = {
47
+ name: "slice_files_for_task",
48
+ description: "Filter a file list to those matching a task's `scope` glob. Without a scope, the task is repo-wide and all files match. Same glob primitive as skip_paths and learnings scope.",
49
+ schema,
50
+ handler: sliceFilesForTaskTool,
51
+ };
52
+ //# sourceMappingURL=slice-files-for-task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slice-files-for-task.js","sourceRoot":"","sources":["../../src/tools/slice-files-for-task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IAC3C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACpC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;CACxD,CAAC,CAAC;AAWH;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAY;IAEZ,MAAM,GAAG,GAAG,qBAAqB,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAE7C,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,UAAU,CAClB,eAAe,EACf,QAAQ,KAAK,CAAC,OAAO,qBAAqB,CAC3C,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,KAAK,EAAE,IAAI;YACX,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;YACzB,SAAS,EAAE,EAAE;SACd,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,MAAM,wBAAwB,GAA2B;IAC9D,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACT,gLAAgL;IAClL,MAAM;IACN,OAAO,EAAE,qBAAqB;CAC/B,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import type { ToolDef } from "./registry.js";
3
+ import { type Task } from "../tasks/store.js";
4
+ declare const schema: z.ZodObject<{
5
+ workspace_root: z.ZodString;
6
+ task_id: z.ZodNumber;
7
+ /** When set, update that subtask's status instead of the parent task's. */
8
+ subtask_id: z.ZodOptional<z.ZodNumber>;
9
+ status: z.ZodEnum<["pending", "in-progress", "review", "done", "blocked", "cancelled"]>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ status: "pending" | "in-progress" | "review" | "done" | "blocked" | "cancelled";
12
+ workspace_root: string;
13
+ task_id: number;
14
+ subtask_id?: number | undefined;
15
+ }, {
16
+ status: "pending" | "in-progress" | "review" | "done" | "blocked" | "cancelled";
17
+ workspace_root: string;
18
+ task_id: number;
19
+ subtask_id?: number | undefined;
20
+ }>;
21
+ type Input = z.infer<typeof schema>;
22
+ export interface UpdateTaskStatusOutput {
23
+ updated: true;
24
+ file: string;
25
+ task: Task;
26
+ }
27
+ export declare function updateTaskStatusTool(input: Input): Promise<UpdateTaskStatusOutput>;
28
+ export declare const updateTaskStatusToolDef: ToolDef<typeof schema>;
29
+ export {};
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ import { updateTaskStatus } from "../tasks/store.js";
3
+ import { readSquadYaml } from "../config/squad-yaml.js";
4
+ import { resolveSafePath, createSafePathContext } from "../util/path-safety.js";
5
+ const schema = z.object({
6
+ workspace_root: z.string().min(1).max(4096),
7
+ task_id: z.number().int().positive(),
8
+ /** When set, update that subtask's status instead of the parent task's. */
9
+ subtask_id: z.number().int().positive().optional(),
10
+ status: z.enum([
11
+ "pending",
12
+ "in-progress",
13
+ "review",
14
+ "done",
15
+ "blocked",
16
+ "cancelled",
17
+ ]),
18
+ });
19
+ export async function updateTaskStatusTool(input) {
20
+ const ctx = createSafePathContext();
21
+ const safeRoot = await resolveSafePath(input.workspace_root, ".", ctx);
22
+ const config = await readSquadYaml(safeRoot);
23
+ const result = await updateTaskStatus(safeRoot, input.task_id, input.status, {
24
+ ...(input.subtask_id !== undefined && { subtaskId: input.subtask_id }),
25
+ configuredPath: config.tasks.path,
26
+ });
27
+ return { updated: true, file: result.filePath, task: result.task };
28
+ }
29
+ export const updateTaskStatusToolDef = {
30
+ name: "update_task_status",
31
+ description: "Flip a task (or subtask) status: pending / in-progress / review / done / blocked / cancelled. Stamps updated_at. Atomic write. Throws when the task / subtask id is unknown.",
32
+ schema,
33
+ handler: updateTaskStatusTool,
34
+ };
35
+ //# sourceMappingURL=update-task-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-task-status.js","sourceRoot":"","sources":["../../src/tools/update-task-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAa,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEhF,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IAC3C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACpC,2EAA2E;IAC3E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAClD,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC;QACb,SAAS;QACT,aAAa;QACb,QAAQ;QACR,MAAM;QACN,SAAS;QACT,WAAW;KACZ,CAAC;CACH,CAAC,CAAC;AAUH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAY;IAEZ,MAAM,GAAG,GAAG,qBAAqB,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE;QAC3E,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;QACtE,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;KAClC,CAAC,CAAC;IAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAA2B;IAC7D,IAAI,EAAE,oBAAoB;IAC1B,WAAW,EACT,8KAA8K;IAChL,MAAM;IACN,OAAO,EAAE,oBAAoB;CAC9B,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { SquadError } from '../errors.js';
2
+ /**
3
+ * Validates that a directory chosen as the agent-override location lives under
4
+ * a known user-controlled prefix, and that per-file resolutions inside it stay
5
+ * under that directory after symlink resolution.
6
+ *
7
+ * This module is distinct from `path-safety.ts` because the abstraction differs:
8
+ * - `path-safety` validates many files against ONE workspace root.
9
+ * - `override-allowlist` validates ONE directory against MANY allowed prefixes.
10
+ * Merging the two would give `resolveSafePath` two operating modes selected by
11
+ * argument shape (SRP violation). Keep them separate.
12
+ *
13
+ * TOCTOU posture: identical to `path-safety.ts`. A symlink can be swapped between
14
+ * `realpath()` and `fs.readFile()`. Acceptable for a single-user dev tool — an
15
+ * attacker with write access to a user-allowlisted root has already won.
16
+ */
17
+ export type OverrideRejectionReason = 'malformed' | 'not_absolute' | 'unc_or_device_namespace' | 'outside_allowlist' | 'symlink_escape';
18
+ export interface AllowlistRoot {
19
+ source: 'home' | 'appdata' | 'localappdata' | 'xdg_config_home' | 'cwd';
20
+ lexical: string;
21
+ real: string;
22
+ }
23
+ export interface ValidationOk {
24
+ ok: true;
25
+ resolvedPath: string;
26
+ allowlistMatch: AllowlistRoot['source'] | 'unsafe_override';
27
+ unsafeOverride: boolean;
28
+ }
29
+ export interface ValidationFail {
30
+ ok: false;
31
+ reason: OverrideRejectionReason;
32
+ rejectedPath: string;
33
+ }
34
+ export type ValidationResult = ValidationOk | ValidationFail;
35
+ /**
36
+ * Test-only: clears the memoized allowlist so env-var changes take effect.
37
+ * Production code should never call this.
38
+ */
39
+ export declare function __resetOverrideAllowlistCache(): void;
40
+ /**
41
+ * Validate an override directory.
42
+ *
43
+ * Returns the resolved (realpath) directory on success. Throws `OVERRIDE_REJECTED`
44
+ * for policy violations (UNC, malformed, not absolute, outside allowlist, symlink
45
+ * escape) UNLESS `SQUAD_AGENTS_ALLOW_UNSAFE=1` is set, in which case the violation
46
+ * is bypassed (still rejects malformed inputs hard — those are not policy choices).
47
+ */
48
+ export declare function validateOverrideDir(rawDir: string): Promise<ValidationResult>;
49
+ /**
50
+ * Convert a `ValidationFail` into a structured `OVERRIDE_REJECTED` error.
51
+ * Caller decides whether to throw or downgrade to a warn-and-fallback.
52
+ */
53
+ export declare function rejectionToError(fail: ValidationFail, allowlistSize: number): SquadError;
54
+ export declare function getAllowlistSize(): Promise<number>;
55
+ /**
56
+ * Validate that a candidate file path inside a previously-validated override
57
+ * directory does not escape (after symlink resolution).
58
+ *
59
+ * Returns the file's realpath on success, or `null` if the file does not exist
60
+ * or escapes the directory. Per-file escape is NOT a policy-level error — the
61
+ * caller falls back to embedded for that file only and continues.
62
+ */
63
+ export declare function validateOverrideFile(validatedDirReal: string, fileName: string): Promise<string | null>;
@@ -0,0 +1,191 @@
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
+ let allowlistCache = null;
7
+ /**
8
+ * Test-only: clears the memoized allowlist so env-var changes take effect.
9
+ * Production code should never call this.
10
+ */
11
+ export function __resetOverrideAllowlistCache() {
12
+ allowlistCache = null;
13
+ }
14
+ function isUnsafeOverrideEnabled() {
15
+ return process.env.SQUAD_AGENTS_ALLOW_UNSAFE === '1';
16
+ }
17
+ function isUncOrDeviceNamespace(absolute) {
18
+ if (process.platform !== 'win32')
19
+ return false;
20
+ if (absolute.startsWith('\\\\?\\'))
21
+ return true;
22
+ if (absolute.startsWith('\\\\.\\'))
23
+ return true;
24
+ if (absolute.startsWith('\\\\'))
25
+ return true;
26
+ return false;
27
+ }
28
+ async function buildAllowlist() {
29
+ if (allowlistCache !== null)
30
+ return allowlistCache;
31
+ const roots = [];
32
+ const seen = new Set();
33
+ const candidates = [
34
+ { source: 'home', raw: os.homedir() },
35
+ { source: 'cwd', raw: process.cwd() },
36
+ ];
37
+ if (process.platform === 'win32') {
38
+ candidates.push({ source: 'appdata', raw: process.env.APPDATA });
39
+ candidates.push({ source: 'localappdata', raw: process.env.LOCALAPPDATA });
40
+ }
41
+ else {
42
+ candidates.push({ source: 'xdg_config_home', raw: process.env.XDG_CONFIG_HOME });
43
+ }
44
+ for (const c of candidates) {
45
+ if (!c.raw)
46
+ continue;
47
+ if (!path.isAbsolute(c.raw))
48
+ continue;
49
+ try {
50
+ rejectIfMalformed(c.raw);
51
+ }
52
+ catch {
53
+ // hostile env var (e.g. APPDATA injected with NUL) — silently skip from allowlist
54
+ continue;
55
+ }
56
+ if (isUncOrDeviceNamespace(c.raw))
57
+ continue;
58
+ const lexical = path.normalize(c.raw);
59
+ const real = await realpathOrSelf(lexical);
60
+ if (seen.has(real))
61
+ continue;
62
+ seen.add(real);
63
+ roots.push({ source: c.source, lexical, real });
64
+ }
65
+ allowlistCache = roots;
66
+ return roots;
67
+ }
68
+ function isInsideRoot(candidate, root) {
69
+ if (candidate === root)
70
+ return true;
71
+ const rel = path.relative(root, candidate);
72
+ if (rel === '' || rel === '.')
73
+ return true;
74
+ if (path.isAbsolute(rel))
75
+ return false;
76
+ if (rel === '..')
77
+ return false;
78
+ if (rel.startsWith('..' + path.sep))
79
+ return false;
80
+ return true;
81
+ }
82
+ function findAllowlistMatch(candidateLexical, candidateReal, roots) {
83
+ // Lexical AND realpath both must be inside the same allowlist entry.
84
+ // (Either alone is a known bypass: a symlinked-out lexical-allowed path,
85
+ // or a realpath-allowed path that lexically points elsewhere.)
86
+ for (const r of roots) {
87
+ if (isInsideRoot(candidateLexical, r.lexical) && isInsideRoot(candidateReal, r.real)) {
88
+ return r;
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+ /**
94
+ * Validate an override directory.
95
+ *
96
+ * Returns the resolved (realpath) directory on success. Throws `OVERRIDE_REJECTED`
97
+ * for policy violations (UNC, malformed, not absolute, outside allowlist, symlink
98
+ * escape) UNLESS `SQUAD_AGENTS_ALLOW_UNSAFE=1` is set, in which case the violation
99
+ * is bypassed (still rejects malformed inputs hard — those are not policy choices).
100
+ */
101
+ export async function validateOverrideDir(rawDir) {
102
+ // Hard rejections — never bypassed by the escape hatch.
103
+ try {
104
+ rejectIfMalformed(rawDir);
105
+ }
106
+ catch (err) {
107
+ return { ok: false, reason: 'malformed', rejectedPath: rawDir };
108
+ }
109
+ if (!path.isAbsolute(rawDir)) {
110
+ return { ok: false, reason: 'not_absolute', rejectedPath: rawDir };
111
+ }
112
+ if (isUncOrDeviceNamespace(rawDir)) {
113
+ return { ok: false, reason: 'unc_or_device_namespace', rejectedPath: rawDir };
114
+ }
115
+ const lexical = path.normalize(rawDir);
116
+ const real = await realpathOrSelf(lexical);
117
+ const unsafe = isUnsafeOverrideEnabled();
118
+ const roots = await buildAllowlist();
119
+ const match = findAllowlistMatch(lexical, real, roots);
120
+ if (match) {
121
+ return { ok: true, resolvedPath: real, allowlistMatch: match.source, unsafeOverride: false };
122
+ }
123
+ // Distinguish lexical-only escape (likely symlink) from outright outside-allowlist.
124
+ // If lexical matches some root but realpath does not, the user did `ln -s /tmp/x ~/.squad`.
125
+ let lexicalMatchExists = false;
126
+ for (const r of roots) {
127
+ if (isInsideRoot(lexical, r.lexical)) {
128
+ lexicalMatchExists = true;
129
+ break;
130
+ }
131
+ }
132
+ const reason = lexicalMatchExists ? 'symlink_escape' : 'outside_allowlist';
133
+ if (unsafe) {
134
+ return { ok: true, resolvedPath: real, allowlistMatch: 'unsafe_override', unsafeOverride: true };
135
+ }
136
+ return { ok: false, reason, rejectedPath: rawDir };
137
+ }
138
+ /**
139
+ * Convert a `ValidationFail` into a structured `OVERRIDE_REJECTED` error.
140
+ * Caller decides whether to throw or downgrade to a warn-and-fallback.
141
+ */
142
+ export function rejectionToError(fail, allowlistSize) {
143
+ return new SquadError('OVERRIDE_REJECTED', `override directory rejected: ${fail.reason}`, {
144
+ reason: fail.reason,
145
+ path: fail.rejectedPath,
146
+ allowlist_size: allowlistSize,
147
+ });
148
+ }
149
+ export async function getAllowlistSize() {
150
+ const roots = await buildAllowlist();
151
+ return roots.length;
152
+ }
153
+ /**
154
+ * Validate that a candidate file path inside a previously-validated override
155
+ * directory does not escape (after symlink resolution).
156
+ *
157
+ * Returns the file's realpath on success, or `null` if the file does not exist
158
+ * or escapes the directory. Per-file escape is NOT a policy-level error — the
159
+ * caller falls back to embedded for that file only and continues.
160
+ */
161
+ export async function validateOverrideFile(validatedDirReal, fileName) {
162
+ try {
163
+ rejectIfMalformed(fileName);
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ // Lexical: file name must not contain traversal segments.
169
+ const normalized = path.normalize(fileName);
170
+ if (path.isAbsolute(normalized))
171
+ return null;
172
+ if (normalized === '..' || normalized.startsWith('..' + path.sep) || normalized.includes(path.sep + '..' + path.sep)) {
173
+ return null;
174
+ }
175
+ const candidate = path.resolve(validatedDirReal, normalized);
176
+ // Lexical containment.
177
+ if (!isInsideRoot(candidate, validatedDirReal))
178
+ return null;
179
+ // Existence check before realpath.
180
+ try {
181
+ await fs.access(candidate);
182
+ }
183
+ catch {
184
+ return null;
185
+ }
186
+ const real = await realpathOrSelf(candidate);
187
+ if (!isInsideRoot(real, validatedDirReal))
188
+ return null;
189
+ return real;
190
+ }
191
+ //# sourceMappingURL=override-allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"override-allowlist.js","sourceRoot":"","sources":["../../src/util/override-allowlist.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Internal helpers shared between path-safety.ts and override-allowlist.ts.
3
+ * Exported only for intra-`util/` reuse; do not import from outside src/util/.
4
+ */
5
+ export declare function rejectIfMalformed(file: string): void;
6
+ export declare function realpathOrSelf(p: string): Promise<string>;
@@ -0,0 +1,27 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { SquadError } from '../errors.js';
3
+ /**
4
+ * Internal helpers shared between path-safety.ts and override-allowlist.ts.
5
+ * Exported only for intra-`util/` reuse; do not import from outside src/util/.
6
+ */
7
+ export function rejectIfMalformed(file) {
8
+ if (file.includes('\0')) {
9
+ throw new SquadError('PATH_INVALID', 'file path contains NUL byte', { file });
10
+ }
11
+ if (file.startsWith('~')) {
12
+ throw new SquadError('PATH_INVALID', 'file path starts with ~ (tilde expansion not supported)', { file });
13
+ }
14
+ const adsIndex = file.indexOf(':', 2);
15
+ if (adsIndex !== -1) {
16
+ throw new SquadError('PATH_INVALID', 'file path contains ADS marker (:) after drive letter', { file });
17
+ }
18
+ }
19
+ export async function realpathOrSelf(p) {
20
+ try {
21
+ return await fs.realpath(p);
22
+ }
23
+ catch {
24
+ return p;
25
+ }
26
+ }
27
+ //# sourceMappingURL=path-internal.js.map
@@ -0,0 +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"}
Binary file
@@ -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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"}