@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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +4 -2
- package/CHANGELOG.md +395 -8
- package/INSTALL.md +554 -0
- package/README.md +311 -25
- package/agents/{Skill-Squad-Dev.md → _shared/Skill-Squad-Dev.md} +30 -3
- package/agents/{Skill-Squad-Review.md → _shared/Skill-Squad-Review.md} +70 -0
- package/agents/{PO.md → product-owner.md} +33 -1
- package/agents/{Senior-Architect.md → senior-architect.md} +33 -1
- package/agents/{Senior-DBA.md → senior-dba.md} +33 -1
- package/agents/senior-dev-reviewer.md +640 -0
- package/agents/{Senior-Dev-Security.md → senior-dev-security.md} +33 -1
- package/agents/{Senior-Developer.md → senior-developer.md} +33 -1
- package/agents/{Senior-QA.md → senior-qa.md} +33 -1
- package/agents/{TechLead-Consolidator.md → tech-lead-consolidator.md} +7 -1
- package/agents/{TechLead-Planner.md → tech-lead-planner.md} +7 -1
- package/commands/brainstorm.md +21 -0
- package/commands/commit-suggest.md +12 -0
- package/commands/squad-review.md +10 -58
- package/commands/squad.md +11 -70
- package/dist/config/ownership-matrix.d.ts +24 -2
- package/dist/config/ownership-matrix.js +466 -139
- package/dist/config/ownership-matrix.js.map +1 -1
- package/dist/config/squad-yaml.d.ts +242 -0
- package/dist/config/squad-yaml.js +403 -0
- package/dist/config/squad-yaml.js.map +1 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/format/pr-review.d.ts +61 -0
- package/dist/format/pr-review.js +146 -0
- package/dist/format/pr-review.js.map +1 -0
- package/dist/index.js +19 -13
- package/dist/index.js.map +1 -1
- package/dist/learning/format.d.ts +29 -0
- package/dist/learning/format.js +55 -0
- package/dist/learning/format.js.map +1 -0
- package/dist/learning/store.d.ts +102 -0
- package/dist/learning/store.js +169 -0
- package/dist/learning/store.js.map +1 -0
- package/dist/resources/agent-loader.d.ts +14 -2
- package/dist/resources/agent-loader.js +235 -53
- package/dist/resources/agent-loader.js.map +1 -1
- package/dist/tasks/select.d.ts +64 -0
- package/dist/tasks/select.js +84 -0
- package/dist/tasks/select.js.map +1 -0
- package/dist/tasks/store.d.ts +338 -0
- package/dist/tasks/store.js +321 -0
- package/dist/tasks/store.js.map +1 -0
- package/dist/tools/agents.js +4 -1
- package/dist/tools/agents.js.map +1 -1
- package/dist/tools/compose-advisory-bundle.d.ts +5 -5
- package/dist/tools/compose-advisory-bundle.js +24 -12
- package/dist/tools/compose-advisory-bundle.js.map +1 -1
- package/dist/tools/compose-prd-parse.d.ts +53 -0
- package/dist/tools/compose-prd-parse.js +167 -0
- package/dist/tools/compose-prd-parse.js.map +1 -0
- package/dist/tools/compose-squad-workflow.d.ts +28 -10
- package/dist/tools/compose-squad-workflow.js +0 -0
- package/dist/tools/compose-squad-workflow.js.map +1 -1
- package/dist/tools/consolidate.d.ts +55 -4
- package/dist/tools/consolidate.js +87 -15
- package/dist/tools/consolidate.js.map +1 -1
- package/dist/tools/expand-task.d.ts +51 -0
- package/dist/tools/expand-task.js +35 -0
- package/dist/tools/expand-task.js.map +1 -0
- package/dist/tools/list-tasks.d.ts +31 -0
- package/dist/tools/list-tasks.js +50 -0
- package/dist/tools/list-tasks.js.map +1 -0
- package/dist/tools/next-task.d.ts +37 -0
- package/dist/tools/next-task.js +60 -0
- package/dist/tools/next-task.js.map +1 -0
- package/dist/tools/read-learnings.d.ts +53 -0
- package/dist/tools/read-learnings.js +72 -0
- package/dist/tools/read-learnings.js.map +1 -0
- package/dist/tools/read-squad-config.d.ts +23 -0
- package/dist/tools/read-squad-config.js +34 -0
- package/dist/tools/read-squad-config.js.map +1 -0
- package/dist/tools/record-learning.d.ts +62 -0
- package/dist/tools/record-learning.js +80 -0
- package/dist/tools/record-learning.js.map +1 -0
- package/dist/tools/record-tasks.d.ts +71 -0
- package/dist/tools/record-tasks.js +45 -0
- package/dist/tools/record-tasks.js.map +1 -0
- package/dist/tools/registry.d.ts +1 -1
- package/dist/tools/registry.js +71 -39
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/score-rubric.d.ts +74 -0
- package/dist/tools/score-rubric.js +140 -0
- package/dist/tools/score-rubric.js.map +1 -0
- package/dist/tools/slice-files-for-task.d.ts +31 -0
- package/dist/tools/slice-files-for-task.js +52 -0
- package/dist/tools/slice-files-for-task.js.map +1 -0
- package/dist/tools/update-task-status.d.ts +29 -0
- package/dist/tools/update-task-status.js +35 -0
- package/dist/tools/update-task-status.js.map +1 -0
- package/dist/util/override-allowlist.d.ts +63 -0
- package/dist/util/override-allowlist.js +191 -0
- package/dist/util/override-allowlist.js.map +1 -0
- package/dist/util/path-internal.d.ts +6 -0
- package/dist/util/path-internal.js +27 -0
- package/dist/util/path-internal.js.map +1 -0
- package/dist/util/path-safety.js +0 -0
- package/dist/util/path-safety.js.map +1 -1
- package/package.json +5 -1
- package/skills/brainstorm/SKILL.md +284 -0
- package/skills/commit-suggest/SKILL.md +255 -0
- package/skills/squad/SKILL.md +454 -0
- package/tools/post-review.mjs +212 -0
- package/agents/Senior-Dev-Reviewer.md +0 -104
- /package/agents/{_Severity-and-Ownership.md → _shared/_Severity-and-Ownership.md} +0 -0
|
@@ -1,36 +1,49 @@
|
|
|
1
|
-
import { promises as fs } from
|
|
2
|
-
import path from
|
|
3
|
-
import os from
|
|
4
|
-
import { fileURLToPath } from
|
|
5
|
-
import { AGENTS } from
|
|
6
|
-
import { SquadError } from
|
|
7
|
-
import { logger } from
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { AGENTS } from "../config/ownership-matrix.js";
|
|
6
|
+
import { SquadError } from "../errors.js";
|
|
7
|
+
import { logger } from "../observability/logger.js";
|
|
8
|
+
import { validateOverrideDir, validateOverrideFile, rejectionToError, getAllowlistSize, __resetOverrideAllowlistCache, } from "../util/override-allowlist.js";
|
|
8
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
10
|
const AGENT_FILE_MAP = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
'product-owner': "product-owner.md",
|
|
12
|
+
"tech-lead-planner": "tech-lead-planner.md",
|
|
13
|
+
"tech-lead-consolidator": "tech-lead-consolidator.md",
|
|
14
|
+
"senior-architect": "senior-architect.md",
|
|
15
|
+
"senior-dba": "senior-dba.md",
|
|
16
|
+
"senior-developer": "senior-developer.md",
|
|
17
|
+
"senior-dev-reviewer": "senior-dev-reviewer.md",
|
|
18
|
+
"senior-dev-security": "senior-dev-security.md",
|
|
19
|
+
"senior-qa": "senior-qa.md",
|
|
19
20
|
};
|
|
20
|
-
export const SHARED_FILES = [
|
|
21
|
+
export const SHARED_FILES = [
|
|
22
|
+
"_shared/_Severity-and-Ownership.md",
|
|
23
|
+
"_shared/Skill-Squad-Dev.md",
|
|
24
|
+
"_shared/Skill-Squad-Review.md",
|
|
25
|
+
];
|
|
21
26
|
function defaultLocalDir() {
|
|
22
|
-
if (process.platform ===
|
|
23
|
-
const appdata = process.env.APPDATA ?? path.join(os.homedir(),
|
|
24
|
-
return path.join(appdata,
|
|
27
|
+
if (process.platform === "win32") {
|
|
28
|
+
const appdata = process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming");
|
|
29
|
+
return path.join(appdata, "squad-mcp", "agents");
|
|
25
30
|
}
|
|
26
|
-
const xdg = process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(),
|
|
27
|
-
return path.join(xdg,
|
|
31
|
+
const xdg = process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config");
|
|
32
|
+
return path.join(xdg, "squad-mcp", "agents");
|
|
28
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns the configured override directory and whether it was set explicitly
|
|
36
|
+
* via `SQUAD_AGENTS_DIR`. Empty string is treated as unset.
|
|
37
|
+
*/
|
|
29
38
|
export function getLocalDir() {
|
|
30
|
-
|
|
39
|
+
const env = process.env.SQUAD_AGENTS_DIR;
|
|
40
|
+
if (env !== undefined && env !== "") {
|
|
41
|
+
return { rawDir: env, explicit: true };
|
|
42
|
+
}
|
|
43
|
+
return { rawDir: defaultLocalDir(), explicit: false };
|
|
31
44
|
}
|
|
32
45
|
export function getEmbeddedDir() {
|
|
33
|
-
return path.resolve(__dirname,
|
|
46
|
+
return path.resolve(__dirname, "..", "..", "agents");
|
|
34
47
|
}
|
|
35
48
|
async function exists(p) {
|
|
36
49
|
try {
|
|
@@ -41,82 +54,251 @@ async function exists(p) {
|
|
|
41
54
|
return false;
|
|
42
55
|
}
|
|
43
56
|
}
|
|
57
|
+
async function isDirectory(p) {
|
|
58
|
+
try {
|
|
59
|
+
const s = await fs.stat(p);
|
|
60
|
+
return s.isDirectory();
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
44
66
|
let embeddedAsserted = false;
|
|
45
|
-
let overrideWarnEmitted = false;
|
|
46
67
|
let overrideActiveAnnounced = false;
|
|
68
|
+
let overrideMissingWarnEmitted = false;
|
|
69
|
+
let permWarnEmitted = false;
|
|
70
|
+
const overrideValidationCache = new Map();
|
|
71
|
+
/**
|
|
72
|
+
* Test-only: reset all module-level caches and one-shot flags.
|
|
73
|
+
* Production code MUST NOT call this.
|
|
74
|
+
*/
|
|
75
|
+
export function __resetAgentLoaderForTests() {
|
|
76
|
+
embeddedAsserted = false;
|
|
77
|
+
overrideActiveAnnounced = false;
|
|
78
|
+
overrideMissingWarnEmitted = false;
|
|
79
|
+
permWarnEmitted = false;
|
|
80
|
+
overrideValidationCache.clear();
|
|
81
|
+
__resetOverrideAllowlistCache();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create the override directory with user-only permissions.
|
|
85
|
+
* On Unix, mkdir's mode is masked by umask, so an explicit chmod follows.
|
|
86
|
+
* Chmod failures propagate — initLocalConfig must not silently succeed when the
|
|
87
|
+
* security invariant (mode 0o700) cannot be met.
|
|
88
|
+
* On Windows, fs.mkdir mode is ignored; APPDATA inherits user-only DACL by default.
|
|
89
|
+
* Custom paths outside APPDATA on Windows fall back to whatever the parent grants.
|
|
90
|
+
*/
|
|
91
|
+
async function createSecureDir(dir) {
|
|
92
|
+
await fs.mkdir(dir, { recursive: true, mode: 0o700 });
|
|
93
|
+
if (process.platform !== "win32") {
|
|
94
|
+
await fs.chmod(dir, 0o700);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Copy a file with user-only read/write permissions on Unix.
|
|
99
|
+
* fs.copyFile preserves the source mode (0o644 from the bundle), so an explicit
|
|
100
|
+
* chmod is required for 0o600 semantics. Failure propagates so the operator
|
|
101
|
+
* sees the security invariant breakage, rather than silent success.
|
|
102
|
+
*/
|
|
103
|
+
async function copyFileSecure(src, dst) {
|
|
104
|
+
await fs.copyFile(src, dst);
|
|
105
|
+
if (process.platform !== "win32") {
|
|
106
|
+
await fs.chmod(dst, 0o600);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Warn once per process if the override directory is world-writable. Group-write
|
|
111
|
+
* is allowed (single-user box convention); only world-write triggers the warning.
|
|
112
|
+
* Skipped on Windows: fs.stat does not surface DACL semantics.
|
|
113
|
+
*
|
|
114
|
+
* The "once" flag is claimed BEFORE the await so concurrent first-load calls do
|
|
115
|
+
* not produce duplicate warnings.
|
|
116
|
+
*/
|
|
117
|
+
async function checkOverrideDirPerms(dir) {
|
|
118
|
+
if (process.platform === "win32")
|
|
119
|
+
return;
|
|
120
|
+
if (permWarnEmitted)
|
|
121
|
+
return;
|
|
122
|
+
permWarnEmitted = true;
|
|
123
|
+
try {
|
|
124
|
+
const s = await fs.stat(dir);
|
|
125
|
+
if ((s.mode & 0o002) !== 0) {
|
|
126
|
+
logger.warn("override directory is world-writable", {
|
|
127
|
+
details: {
|
|
128
|
+
configured_path: dir,
|
|
129
|
+
mode: "0o" + (s.mode & 0o777).toString(8),
|
|
130
|
+
recommendation: `chmod 700 ${dir}`,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// stat already validated upstream; ignore failure here
|
|
137
|
+
}
|
|
138
|
+
}
|
|
47
139
|
async function ensureEmbeddedDir() {
|
|
48
140
|
if (embeddedAsserted)
|
|
49
141
|
return;
|
|
50
142
|
const dir = getEmbeddedDir();
|
|
51
143
|
if (!(await exists(dir))) {
|
|
52
|
-
throw new SquadError(
|
|
144
|
+
throw new SquadError("AGENT_DIR_MISSING", `embedded agents directory missing at ${dir}`);
|
|
53
145
|
}
|
|
54
146
|
embeddedAsserted = true;
|
|
55
147
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Resolve and validate the active override directory.
|
|
150
|
+
*
|
|
151
|
+
* Returns:
|
|
152
|
+
* - validated `ValidationOk` (override active for this resolution).
|
|
153
|
+
* - `null` when there is no active override (use embedded). The "no active
|
|
154
|
+
* override" cases include: directory does not exist on disk; default
|
|
155
|
+
* platform dir failed validation (rare — these always live under an
|
|
156
|
+
* allowlisted root in practice).
|
|
157
|
+
*
|
|
158
|
+
* Throws `OVERRIDE_REJECTED` only when `SQUAD_AGENTS_DIR` was set explicitly
|
|
159
|
+
* AND the directory exists but fails policy (outside allowlist, UNC, symlink
|
|
160
|
+
* escape, etc.). A missing explicit-env directory still soft-fails with a
|
|
161
|
+
* one-shot warn — this preserves the prior contract.
|
|
162
|
+
*/
|
|
163
|
+
async function resolveOverride() {
|
|
164
|
+
const { rawDir, explicit } = getLocalDir();
|
|
165
|
+
const cached = overrideValidationCache.get(rawDir);
|
|
166
|
+
if (cached !== undefined)
|
|
167
|
+
return cached;
|
|
168
|
+
if (!(await isDirectory(rawDir))) {
|
|
169
|
+
if (explicit && !overrideMissingWarnEmitted) {
|
|
170
|
+
overrideMissingWarnEmitted = true;
|
|
171
|
+
logger.warn("SQUAD_AGENTS_DIR set but directory not found; falling back to embedded defaults", {
|
|
172
|
+
details: { configured_path: rawDir },
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
overrideValidationCache.set(rawDir, null);
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const result = await validateOverrideDir(rawDir);
|
|
179
|
+
if (!result.ok) {
|
|
180
|
+
if (explicit) {
|
|
181
|
+
const size = await getAllowlistSize();
|
|
182
|
+
const err = rejectionToError(result, size);
|
|
183
|
+
logger.warn("SQUAD_AGENTS_DIR rejected", {
|
|
184
|
+
error_code: err.code,
|
|
185
|
+
details: { reason: result.reason, configured_path: rawDir },
|
|
186
|
+
});
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
// Platform-default rejection: log warn, fall back silently. Rare.
|
|
190
|
+
logger.warn("platform default agent directory failed validation", {
|
|
191
|
+
details: { reason: result.reason, configured_path: rawDir },
|
|
192
|
+
});
|
|
193
|
+
overrideValidationCache.set(rawDir, null);
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
if (!overrideActiveAnnounced) {
|
|
197
|
+
overrideActiveAnnounced = true;
|
|
198
|
+
const fields = {
|
|
199
|
+
resolved_path: result.resolvedPath,
|
|
200
|
+
allowlist_match: result.allowlistMatch,
|
|
201
|
+
has_unsafe_override: result.unsafeOverride,
|
|
202
|
+
source: explicit ? "env" : "platform_default",
|
|
203
|
+
};
|
|
204
|
+
if (result.unsafeOverride) {
|
|
205
|
+
logger.warn("agent override active (unsafe escape hatch)", {
|
|
206
|
+
details: fields,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
logger.info("agent override active", { details: fields });
|
|
211
|
+
}
|
|
62
212
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
213
|
+
await checkOverrideDirPerms(result.resolvedPath);
|
|
214
|
+
overrideValidationCache.set(rawDir, result);
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Validate an agent name against the AGENT_FILE_MAP. Prevents agent-name
|
|
219
|
+
* traversal (e.g. `../../../etc/passwd`) at the loader boundary.
|
|
220
|
+
*/
|
|
221
|
+
function assertKnownAgent(name) {
|
|
222
|
+
if (!Object.prototype.hasOwnProperty.call(AGENT_FILE_MAP, name)) {
|
|
223
|
+
throw new SquadError("UNKNOWN_AGENT", `unknown agent: ${name}`, { name });
|
|
66
224
|
}
|
|
67
|
-
overrideActiveAnnounced = true;
|
|
68
225
|
}
|
|
69
226
|
export async function resolveAgentFile(name) {
|
|
70
227
|
await ensureEmbeddedDir();
|
|
71
|
-
|
|
228
|
+
assertKnownAgent(name);
|
|
72
229
|
const file = AGENT_FILE_MAP[name];
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
75
|
-
|
|
230
|
+
const override = await resolveOverride();
|
|
231
|
+
if (override) {
|
|
232
|
+
const overrideFile = await validateOverrideFile(override.resolvedPath, file);
|
|
233
|
+
if (overrideFile)
|
|
234
|
+
return overrideFile;
|
|
235
|
+
// File missing or per-file escape — silent fallback to embedded for this file.
|
|
236
|
+
}
|
|
76
237
|
return path.join(getEmbeddedDir(), file);
|
|
77
238
|
}
|
|
78
239
|
export async function resolveSharedFile(file) {
|
|
79
240
|
await ensureEmbeddedDir();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
241
|
+
if (!SHARED_FILES.includes(file)) {
|
|
242
|
+
throw new SquadError("INVALID_INPUT", `shared file not allowed: ${file}`, {
|
|
243
|
+
file,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
const override = await resolveOverride();
|
|
247
|
+
if (override) {
|
|
248
|
+
const overrideFile = await validateOverrideFile(override.resolvedPath, file);
|
|
249
|
+
if (overrideFile)
|
|
250
|
+
return overrideFile;
|
|
251
|
+
}
|
|
84
252
|
return path.join(getEmbeddedDir(), file);
|
|
85
253
|
}
|
|
86
254
|
export async function readAgentDefinition(name) {
|
|
87
255
|
const filePath = await resolveAgentFile(name);
|
|
88
|
-
return fs.readFile(filePath,
|
|
256
|
+
return fs.readFile(filePath, "utf8");
|
|
89
257
|
}
|
|
90
258
|
export async function listAvailableAgents() {
|
|
91
|
-
|
|
92
|
-
|
|
259
|
+
// Trigger validation so misconfigured overrides surface here too.
|
|
260
|
+
let overridden = false;
|
|
261
|
+
try {
|
|
262
|
+
const result = await resolveOverride();
|
|
263
|
+
overridden = result !== null;
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
// OVERRIDE_REJECTED bubbles up to the caller via the resolve call below
|
|
267
|
+
// when individual agent files are read. For listing, treat as no override.
|
|
268
|
+
overridden = false;
|
|
269
|
+
}
|
|
93
270
|
return Object.values(AGENTS).map((a) => ({
|
|
94
271
|
name: a.name,
|
|
95
272
|
role: a.role,
|
|
96
273
|
owns: a.owns,
|
|
97
274
|
conventions: a.conventions,
|
|
98
275
|
file: AGENT_FILE_MAP[a.name],
|
|
99
|
-
overridden
|
|
276
|
+
overridden,
|
|
100
277
|
}));
|
|
101
278
|
}
|
|
102
279
|
export async function initLocalConfig(force = false) {
|
|
103
280
|
await ensureEmbeddedDir();
|
|
104
|
-
const
|
|
105
|
-
await
|
|
281
|
+
const { rawDir } = getLocalDir();
|
|
282
|
+
await createSecureDir(rawDir);
|
|
106
283
|
const created = [];
|
|
107
284
|
const skipped = [];
|
|
108
285
|
// SECURITY: file names come from hardcoded constants only; never accept user-supplied names here.
|
|
109
286
|
const sources = [...Object.values(AGENT_FILE_MAP), ...SHARED_FILES];
|
|
110
287
|
for (const file of sources) {
|
|
111
|
-
const dst = path.join(
|
|
288
|
+
const dst = path.join(rawDir, file);
|
|
112
289
|
if ((await exists(dst)) && !force) {
|
|
113
290
|
skipped.push(file);
|
|
114
291
|
continue;
|
|
115
292
|
}
|
|
293
|
+
// Shared docs live under _shared/; ensure the parent dir exists before copyFile.
|
|
294
|
+
const parent = path.dirname(dst);
|
|
295
|
+
if (parent !== rawDir) {
|
|
296
|
+
await createSecureDir(parent);
|
|
297
|
+
}
|
|
116
298
|
const src = path.join(getEmbeddedDir(), file);
|
|
117
|
-
await
|
|
299
|
+
await copyFileSecure(src, dst);
|
|
118
300
|
created.push(file);
|
|
119
301
|
}
|
|
120
|
-
return { created, skipped, dir };
|
|
302
|
+
return { created, skipped, dir: rawDir };
|
|
121
303
|
}
|
|
122
304
|
//# sourceMappingURL=agent-loader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loader.js","sourceRoot":"","sources":["../../src/resources/agent-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,EAAkB,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-loader.js","sourceRoot":"","sources":["../../src/resources/agent-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { AgentName } from "../config/ownership-matrix.js";
|
|
2
|
+
import type { Task, TaskStatus } from "./store.js";
|
|
3
|
+
/**
|
|
4
|
+
* Pure selection helpers over the in-memory tasks list. Stateless. Used by
|
|
5
|
+
* the next_task and list_tasks MCP tools.
|
|
6
|
+
*/
|
|
7
|
+
export interface ListTasksOptions {
|
|
8
|
+
/** Filter to one or more statuses. */
|
|
9
|
+
status?: TaskStatus[];
|
|
10
|
+
/**
|
|
11
|
+
* When set, return only tasks whose `agent_hints` includes ANY of these
|
|
12
|
+
* agents. Tasks without agent_hints are repo-wide and always pass.
|
|
13
|
+
*/
|
|
14
|
+
agent?: AgentName;
|
|
15
|
+
/**
|
|
16
|
+
* When set, return only tasks whose `scope` glob matches at least one of
|
|
17
|
+
* these paths. Tasks without scope are repo-wide and always pass.
|
|
18
|
+
*/
|
|
19
|
+
changed_files?: string[];
|
|
20
|
+
/** Cap result count. Default unlimited. */
|
|
21
|
+
limit?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function listTasks(tasks: Task[], opts?: ListTasksOptions): Task[];
|
|
24
|
+
export interface NextTaskOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Treat these statuses as "complete" for dependency checks. Defaults to
|
|
27
|
+
* just `done`. A task whose deps are all `done` is considered ready.
|
|
28
|
+
*/
|
|
29
|
+
done_statuses?: TaskStatus[];
|
|
30
|
+
/**
|
|
31
|
+
* Statuses considered eligible for selection. Defaults to `pending`.
|
|
32
|
+
* Use `["pending", "blocked"]` to also surface blocked tasks (with a hint
|
|
33
|
+
* the caller can show the user — handled outside this function).
|
|
34
|
+
*/
|
|
35
|
+
candidate_statuses?: TaskStatus[];
|
|
36
|
+
agent?: AgentName;
|
|
37
|
+
changed_files?: string[];
|
|
38
|
+
}
|
|
39
|
+
export interface NextTaskResult {
|
|
40
|
+
task: Task | null;
|
|
41
|
+
/** Reason "task is null": no candidates, or all blocked by deps. */
|
|
42
|
+
reason: "no_candidates" | "all_blocked" | "ok";
|
|
43
|
+
/**
|
|
44
|
+
* Tasks that match candidate filters but have unmet dependencies. Useful
|
|
45
|
+
* for the caller to show "X is next when Y completes".
|
|
46
|
+
*/
|
|
47
|
+
blocked: Array<{
|
|
48
|
+
task: Task;
|
|
49
|
+
missing_deps: number[];
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Pick the next ready task. A task is ready when:
|
|
54
|
+
* - its status is in `candidate_statuses` (default `["pending"]`)
|
|
55
|
+
* - every id in its `dependencies` refers to a task whose status is in
|
|
56
|
+
* `done_statuses` (default `["done"]`)
|
|
57
|
+
* - it passes the agent / changed_files filters
|
|
58
|
+
*
|
|
59
|
+
* Tiebreakers (in order): priority (high < medium < low), then id ascending.
|
|
60
|
+
*
|
|
61
|
+
* Returns the task plus a structured result so the caller can distinguish
|
|
62
|
+
* "no candidates" from "all blocked by deps" (different UX).
|
|
63
|
+
*/
|
|
64
|
+
export declare function nextTask(tasks: Task[], opts?: NextTaskOptions): NextTaskResult;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { matchesGlob } from "../config/squad-yaml.js";
|
|
2
|
+
export function listTasks(tasks, opts = {}) {
|
|
3
|
+
let out = tasks;
|
|
4
|
+
if (opts.status && opts.status.length > 0) {
|
|
5
|
+
const set = new Set(opts.status);
|
|
6
|
+
out = out.filter((t) => set.has(t.status));
|
|
7
|
+
}
|
|
8
|
+
if (opts.agent !== undefined) {
|
|
9
|
+
const wantedAgent = opts.agent;
|
|
10
|
+
out = out.filter((t) => {
|
|
11
|
+
if (!t.agent_hints || t.agent_hints.length === 0)
|
|
12
|
+
return true;
|
|
13
|
+
return t.agent_hints.includes(wantedAgent);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
if (opts.changed_files && opts.changed_files.length > 0) {
|
|
17
|
+
const files = opts.changed_files;
|
|
18
|
+
out = out.filter((t) => {
|
|
19
|
+
if (!t.scope)
|
|
20
|
+
return true;
|
|
21
|
+
return files.some((f) => matchesGlob(t.scope, f));
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (opts.limit !== undefined && opts.limit > 0) {
|
|
25
|
+
out = out.slice(0, opts.limit);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
const PRIORITY_RANK = {
|
|
30
|
+
high: 0,
|
|
31
|
+
medium: 1,
|
|
32
|
+
low: 2,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Pick the next ready task. A task is ready when:
|
|
36
|
+
* - its status is in `candidate_statuses` (default `["pending"]`)
|
|
37
|
+
* - every id in its `dependencies` refers to a task whose status is in
|
|
38
|
+
* `done_statuses` (default `["done"]`)
|
|
39
|
+
* - it passes the agent / changed_files filters
|
|
40
|
+
*
|
|
41
|
+
* Tiebreakers (in order): priority (high < medium < low), then id ascending.
|
|
42
|
+
*
|
|
43
|
+
* Returns the task plus a structured result so the caller can distinguish
|
|
44
|
+
* "no candidates" from "all blocked by deps" (different UX).
|
|
45
|
+
*/
|
|
46
|
+
export function nextTask(tasks, opts = {}) {
|
|
47
|
+
const doneSet = new Set(opts.done_statuses ?? ["done"]);
|
|
48
|
+
const candidateStatuses = opts.candidate_statuses ?? ["pending"];
|
|
49
|
+
// Build done-id index over the FULL task list — deps may point at any task,
|
|
50
|
+
// not just ones passing the filters.
|
|
51
|
+
const doneIds = new Set(tasks.filter((t) => doneSet.has(t.status)).map((t) => t.id));
|
|
52
|
+
// Filter to candidates (status + agent + scope).
|
|
53
|
+
const filterOpts = { status: candidateStatuses };
|
|
54
|
+
if (opts.agent !== undefined)
|
|
55
|
+
filterOpts.agent = opts.agent;
|
|
56
|
+
if (opts.changed_files !== undefined)
|
|
57
|
+
filterOpts.changed_files = opts.changed_files;
|
|
58
|
+
const candidates = listTasks(tasks, filterOpts);
|
|
59
|
+
if (candidates.length === 0) {
|
|
60
|
+
return { task: null, reason: "no_candidates", blocked: [] };
|
|
61
|
+
}
|
|
62
|
+
const ready = [];
|
|
63
|
+
const blocked = [];
|
|
64
|
+
for (const t of candidates) {
|
|
65
|
+
const missing = t.dependencies.filter((d) => !doneIds.has(d));
|
|
66
|
+
if (missing.length === 0) {
|
|
67
|
+
ready.push(t);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
blocked.push({ task: t, missing_deps: missing });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (ready.length === 0) {
|
|
74
|
+
return { task: null, reason: "all_blocked", blocked };
|
|
75
|
+
}
|
|
76
|
+
ready.sort((a, b) => {
|
|
77
|
+
const p = PRIORITY_RANK[a.priority] - PRIORITY_RANK[b.priority];
|
|
78
|
+
if (p !== 0)
|
|
79
|
+
return p;
|
|
80
|
+
return a.id - b.id;
|
|
81
|
+
});
|
|
82
|
+
return { task: ready[0], reason: "ok", blocked };
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/tasks/select.ts"],"names":[],"mappings":"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"}
|