@gempack/squad-mcp 0.6.0 → 0.6.1
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/plugin.json +1 -1
- package/CHANGELOG.md +11 -0
- package/README.md +2 -3
- package/dist/index.js +1 -1
- package/dist/resources/agent-loader.d.ts +7 -0
- package/dist/resources/agent-loader.js +35 -13
- package/dist/resources/agent-loader.js.map +1 -1
- package/dist/tools/consolidate.js +1 -1
- package/dist/tools/consolidate.js.map +1 -1
- package/package.json +8 -1
- package/skills/squad/SKILL.md +2 -2
- package/tools/_tasks-io.mjs +69 -0
- package/tools/list-tasks.mjs +110 -0
- package/tools/next-task.mjs +131 -0
- package/tools/record-learning.mjs +145 -0
- package/tools/record-tasks.mjs +186 -0
- package/tools/update-task-status.mjs +114 -0
- /package/{agents/_shared → shared}/Skill-Squad-Dev.md +0 -0
- /package/{agents/_shared → shared}/Skill-Squad-Review.md +0 -0
- /package/{agents/_shared → shared}/_Severity-and-Ownership.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "squad",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Squad-dev workflow as a Claude Code plugin: classification, risk scoring, agent selection, advisory orchestration. Bundles an MCP server, native subagents, and the /squad and /squad-review slash commands.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": {
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Fixed — Plugin manifest validation: shared docs lifted out of `agents/`
|
|
11
|
+
|
|
12
|
+
Claude Code's `/plugin install` rejected the v0.6.0 plugin with `Validation errors: agents: Invalid input`. The plugin manifest's `agents: "./agents/"` directive iterated every `.md` file under `agents/`, including the three `_shared/*.md` reference docs (severity matrix + skill specs) — they lack subagent frontmatter and fail validation.
|
|
13
|
+
|
|
14
|
+
- Moved `agents/_shared/` → top-level `shared/` so the plugin's agent validator only sees real subagent files.
|
|
15
|
+
- `src/resources/agent-loader.ts` adds `getEmbeddedSharedDir()` (resolves to `<repo>/shared/`); `SHARED_FILES` now lists bare filenames; `resolveSharedFile` reads from the new dir; `initLocalConfig` mirrors shared docs to `<localOverrideDir>/shared/<file>` (was `<localOverrideDir>/_shared/<file>`).
|
|
16
|
+
- `src/tools/consolidate.ts`, `skills/squad/SKILL.md`, `README.md` — references updated to `shared/_Severity-and-Ownership.md`.
|
|
17
|
+
- `package.json` now ships the `shared/` dir + the new task CLI helpers (`tools/_tasks-io.mjs`, `tools/{list,next,record,update}-task*.mjs`) and `tools/record-learning.mjs` in the published tarball (was missing).
|
|
18
|
+
|
|
19
|
+
Migration for users with an existing local override at `~/.config/squad-mcp/agents/_shared/`: run `init_local_config` again to mirror to the new `shared/` sub-directory, or move the files manually. Override resolution in v0.6.1 looks at `<localOverrideDir>/shared/<file>`; old `_shared/` overrides fall through to embedded defaults.
|
|
20
|
+
|
|
10
21
|
### Added — Tasks: PRD-decomposed atomic work units (anti-bloat for the squad)
|
|
11
22
|
|
|
12
23
|
Borrows the core idea from claude-task-master and adapts it to squad-mcp's primitives. A PRD is decomposed by the host LLM into atomic tasks; each task carries optional `scope` (glob) and `agent_hints`; the squad runs against ONE task's scope at a time. Less context per pass, fewer tokens, less drift.
|
package/README.md
CHANGED
|
@@ -406,9 +406,8 @@ Run the `init_local_config` tool once to seed the local directory with editable
|
|
|
406
406
|
squad-mcp/
|
|
407
407
|
├── .claude-plugin/ # Claude Code plugin manifest + marketplace
|
|
408
408
|
├── .github/workflows/ # CI + release workflows
|
|
409
|
-
├── agents/ # Native subagents +
|
|
410
|
-
|
|
411
|
-
│ └── _shared/ # severity matrix + skill specs (not loaded as subagents)
|
|
409
|
+
├── agents/ # Native subagents (one .md per subagent, kebab-case + frontmatter)
|
|
410
|
+
├── shared/ # Severity matrix + skill specs (resources, not subagents — kept outside agents/ for the plugin manifest validator)
|
|
412
411
|
├── commands/ # Slash commands (/squad, /squad-review, /brainstorm, /commit-suggest)
|
|
413
412
|
├── skills/ # Bundled skills
|
|
414
413
|
│ ├── squad/ # single skill, two modes (implement | review)
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { listResources, readResource } from "./resources/registry.js";
|
|
|
7
7
|
import { listPrompts, getPrompt } from "./prompts/registry.js";
|
|
8
8
|
import { logger, setupProcessHandlers } from "./observability/logger.js";
|
|
9
9
|
setupProcessHandlers();
|
|
10
|
-
const SERVER_VERSION = "0.6.
|
|
10
|
+
const SERVER_VERSION = "0.6.1";
|
|
11
11
|
const server = new Server({
|
|
12
12
|
name: "squad-mcp",
|
|
13
13
|
version: SERVER_VERSION,
|
|
@@ -9,6 +9,13 @@ export declare function getLocalDir(): {
|
|
|
9
9
|
explicit: boolean;
|
|
10
10
|
};
|
|
11
11
|
export declare function getEmbeddedDir(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Path to the shared docs directory at repo root (`<repo>/shared/`). Lives
|
|
14
|
+
* outside `agents/` so the Claude Code plugin manifest's agent validator does
|
|
15
|
+
* not see non-agent files. Mirrors to `<localOverrideDir>/shared/` when the
|
|
16
|
+
* user runs init_local_config.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getEmbeddedSharedDir(): string;
|
|
12
19
|
/**
|
|
13
20
|
* Test-only: reset all module-level caches and one-shot flags.
|
|
14
21
|
* Production code MUST NOT call this.
|
|
@@ -8,7 +8,7 @@ import { logger } from "../observability/logger.js";
|
|
|
8
8
|
import { validateOverrideDir, validateOverrideFile, rejectionToError, getAllowlistSize, __resetOverrideAllowlistCache, } from "../util/override-allowlist.js";
|
|
9
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
const AGENT_FILE_MAP = {
|
|
11
|
-
|
|
11
|
+
"product-owner": "product-owner.md",
|
|
12
12
|
"tech-lead-planner": "tech-lead-planner.md",
|
|
13
13
|
"tech-lead-consolidator": "tech-lead-consolidator.md",
|
|
14
14
|
"senior-architect": "senior-architect.md",
|
|
@@ -19,9 +19,9 @@ const AGENT_FILE_MAP = {
|
|
|
19
19
|
"senior-qa": "senior-qa.md",
|
|
20
20
|
};
|
|
21
21
|
export const SHARED_FILES = [
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
22
|
+
"_Severity-and-Ownership.md",
|
|
23
|
+
"Skill-Squad-Dev.md",
|
|
24
|
+
"Skill-Squad-Review.md",
|
|
25
25
|
];
|
|
26
26
|
function defaultLocalDir() {
|
|
27
27
|
if (process.platform === "win32") {
|
|
@@ -45,6 +45,15 @@ export function getLocalDir() {
|
|
|
45
45
|
export function getEmbeddedDir() {
|
|
46
46
|
return path.resolve(__dirname, "..", "..", "agents");
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Path to the shared docs directory at repo root (`<repo>/shared/`). Lives
|
|
50
|
+
* outside `agents/` so the Claude Code plugin manifest's agent validator does
|
|
51
|
+
* not see non-agent files. Mirrors to `<localOverrideDir>/shared/` when the
|
|
52
|
+
* user runs init_local_config.
|
|
53
|
+
*/
|
|
54
|
+
export function getEmbeddedSharedDir() {
|
|
55
|
+
return path.resolve(__dirname, "..", "..", "shared");
|
|
56
|
+
}
|
|
48
57
|
async function exists(p) {
|
|
49
58
|
try {
|
|
50
59
|
await fs.access(p);
|
|
@@ -245,11 +254,12 @@ export async function resolveSharedFile(file) {
|
|
|
245
254
|
}
|
|
246
255
|
const override = await resolveOverride();
|
|
247
256
|
if (override) {
|
|
248
|
-
|
|
257
|
+
// Override mirrors source layout: `<localOverrideDir>/shared/<file>`.
|
|
258
|
+
const overrideFile = await validateOverrideFile(override.resolvedPath, path.join("shared", file));
|
|
249
259
|
if (overrideFile)
|
|
250
260
|
return overrideFile;
|
|
251
261
|
}
|
|
252
|
-
return path.join(
|
|
262
|
+
return path.join(getEmbeddedSharedDir(), file);
|
|
253
263
|
}
|
|
254
264
|
export async function readAgentDefinition(name) {
|
|
255
265
|
const filePath = await resolveAgentFile(name);
|
|
@@ -283,21 +293,33 @@ export async function initLocalConfig(force = false) {
|
|
|
283
293
|
const created = [];
|
|
284
294
|
const skipped = [];
|
|
285
295
|
// SECURITY: file names come from hardcoded constants only; never accept user-supplied names here.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
296
|
+
// Agent files mirror to <rawDir>/<file>.md.
|
|
297
|
+
// Shared docs mirror to <rawDir>/shared/<file>.md (matches the source layout
|
|
298
|
+
// since the dir was lifted out of agents/ in v0.6.1 to satisfy the Claude
|
|
299
|
+
// Code plugin manifest validator).
|
|
300
|
+
const targets = [
|
|
301
|
+
...Object.values(AGENT_FILE_MAP).map((file) => ({
|
|
302
|
+
src: path.join(getEmbeddedDir(), file),
|
|
303
|
+
dst: path.join(rawDir, file),
|
|
304
|
+
rel: file,
|
|
305
|
+
})),
|
|
306
|
+
...SHARED_FILES.map((file) => ({
|
|
307
|
+
src: path.join(getEmbeddedSharedDir(), file),
|
|
308
|
+
dst: path.join(rawDir, "shared", file),
|
|
309
|
+
rel: path.join("shared", file),
|
|
310
|
+
})),
|
|
311
|
+
];
|
|
312
|
+
for (const { src, dst, rel } of targets) {
|
|
289
313
|
if ((await exists(dst)) && !force) {
|
|
290
|
-
skipped.push(
|
|
314
|
+
skipped.push(rel);
|
|
291
315
|
continue;
|
|
292
316
|
}
|
|
293
|
-
// Shared docs live under _shared/; ensure the parent dir exists before copyFile.
|
|
294
317
|
const parent = path.dirname(dst);
|
|
295
318
|
if (parent !== rawDir) {
|
|
296
319
|
await createSecureDir(parent);
|
|
297
320
|
}
|
|
298
|
-
const src = path.join(getEmbeddedDir(), file);
|
|
299
321
|
await copyFileSecure(src, dst);
|
|
300
|
-
created.push(
|
|
322
|
+
created.push(rel);
|
|
301
323
|
}
|
|
302
324
|
return { created, skipped, dir: rawDir };
|
|
303
325
|
}
|
|
@@ -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;AACpD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,6BAA6B,GAE9B,MAAM,+BAA+B,CAAC;AAEvC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,MAAM,cAAc,GAA8B;IAChD,eAAe,EAAE,kBAAkB;IACnC,mBAAmB,EAAE,sBAAsB;IAC3C,wBAAwB,EAAE,2BAA2B;IACrD,kBAAkB,EAAE,qBAAqB;IACzC,YAAY,EAAE,eAAe;IAC7B,kBAAkB,EAAE,qBAAqB;IACzC,qBAAqB,EAAE,wBAAwB;IAC/C,qBAAqB,EAAE,wBAAwB;IAC/C,WAAW,EAAE,cAAc;CAC5B,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,
|
|
1
|
+
{"version":3,"file":"agent-loader.js","sourceRoot":"","sources":["../../src/resources/agent-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -135,7 +135,7 @@ export function applyConsolidationRules(input) {
|
|
|
135
135
|
}
|
|
136
136
|
export const applyConsolidationRulesTool = {
|
|
137
137
|
name: "apply_consolidation_rules",
|
|
138
|
-
description: "Aggregate advisory reports and emit a verdict per the rules in
|
|
138
|
+
description: "Aggregate advisory reports and emit a verdict per the rules in shared/_Severity-and-Ownership.md. " +
|
|
139
139
|
"Blocker -> REJECTED. Unjustified Major -> REJECTED. Otherwise CHANGES_REQUIRED or APPROVED. " +
|
|
140
140
|
"When reports carry per-dimension scores (0-100), also returns a weighted rubric scorecard " +
|
|
141
141
|
"(see score_rubric). Optional `min_score` downgrades APPROVED to CHANGES_REQUIRED if the " +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consolidate.js","sourceRoot":"","sources":["../../src/tools/consolidate.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"consolidate.js","sourceRoot":"","sources":["../../src/tools/consolidate.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.
|
|
3
|
+
"version": "0.6.1",
|
|
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",
|
|
@@ -43,9 +43,16 @@
|
|
|
43
43
|
"files": [
|
|
44
44
|
"dist",
|
|
45
45
|
"agents",
|
|
46
|
+
"shared",
|
|
46
47
|
"commands",
|
|
47
48
|
"skills",
|
|
48
49
|
"tools/post-review.mjs",
|
|
50
|
+
"tools/record-learning.mjs",
|
|
51
|
+
"tools/_tasks-io.mjs",
|
|
52
|
+
"tools/list-tasks.mjs",
|
|
53
|
+
"tools/next-task.mjs",
|
|
54
|
+
"tools/record-tasks.mjs",
|
|
55
|
+
"tools/update-task-status.mjs",
|
|
49
56
|
".claude-plugin",
|
|
50
57
|
"README.md",
|
|
51
58
|
"INSTALL.md",
|
package/skills/squad/SKILL.md
CHANGED
|
@@ -178,7 +178,7 @@ You are participating in an advisory review.
|
|
|
178
178
|
{learnings.rendered — omit this whole section if rendered is empty}
|
|
179
179
|
|
|
180
180
|
## Your perspective
|
|
181
|
-
As {agent role}, produce findings tagged Blocker / Major / Minor / Suggestion per
|
|
181
|
+
As {agent role}, produce findings tagged Blocker / Major / Minor / Suggestion per shared/_Severity-and-Ownership.md.
|
|
182
182
|
For each finding: severity, file:line, observation, recommendation.
|
|
183
183
|
If a similar finding appears in "Past team decisions" above with verdict REJECTED,
|
|
184
184
|
do not re-raise it unless the diff materially changes the rationale. Acknowledge
|
|
@@ -194,7 +194,7 @@ Use the calibration table in your role file (see ## Score section). Honest 65
|
|
|
194
194
|
is more useful than generous 80 — the rubric is auditable.
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
Each agent emits findings tagged Blocker / Major / Minor / Suggestion per `
|
|
197
|
+
Each agent emits findings tagged Blocker / Major / Minor / Suggestion per `shared/_Severity-and-Ownership.md` AND a single `Score: NN/100` line. Capture both into the per-agent report.
|
|
198
198
|
|
|
199
199
|
When you build the `reports[]` array for `apply_consolidation_rules`, include the score:
|
|
200
200
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Shared read/write for the task CLI helpers in this directory.
|
|
2
|
+
// Mirrors src/tasks/store.ts on-disk format. Keeps the CLIs from depending
|
|
3
|
+
// on the compiled dist/ output so they run in any node 18+ environment.
|
|
4
|
+
|
|
5
|
+
import { promises as fs } from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_TASKS_PATH = ".squad/tasks.json";
|
|
9
|
+
|
|
10
|
+
export async function readTasksFile(workspace, file) {
|
|
11
|
+
const filePath = path.resolve(workspace, file ?? DEFAULT_TASKS_PATH);
|
|
12
|
+
let raw;
|
|
13
|
+
try {
|
|
14
|
+
raw = await fs.readFile(filePath, "utf8");
|
|
15
|
+
} catch (err) {
|
|
16
|
+
if (err.code === "ENOENT") {
|
|
17
|
+
return { filePath, data: { version: 1, tasks: [] } };
|
|
18
|
+
}
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
let parsed;
|
|
22
|
+
try {
|
|
23
|
+
parsed = JSON.parse(raw);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
throw new Error(`${filePath}: invalid JSON: ${err.message}`);
|
|
26
|
+
}
|
|
27
|
+
if (
|
|
28
|
+
typeof parsed !== "object" ||
|
|
29
|
+
parsed === null ||
|
|
30
|
+
!Array.isArray(parsed.tasks)
|
|
31
|
+
) {
|
|
32
|
+
throw new Error(`${filePath}: missing tasks array`);
|
|
33
|
+
}
|
|
34
|
+
return { filePath, data: parsed };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function writeTasksFile(filePath, data) {
|
|
38
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
39
|
+
const ordered = {
|
|
40
|
+
version: data.version ?? 1,
|
|
41
|
+
tasks: [...data.tasks]
|
|
42
|
+
.sort((a, b) => a.id - b.id)
|
|
43
|
+
.map((t) => ({
|
|
44
|
+
...t,
|
|
45
|
+
subtasks: Array.isArray(t.subtasks)
|
|
46
|
+
? [...t.subtasks].sort((a, b) => a.id - b.id)
|
|
47
|
+
: [],
|
|
48
|
+
})),
|
|
49
|
+
};
|
|
50
|
+
const tmp = `${filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
51
|
+
await fs.writeFile(tmp, JSON.stringify(ordered, null, 2) + "\n", "utf8");
|
|
52
|
+
await fs.rename(tmp, filePath);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const VALID_STATUSES = [
|
|
56
|
+
"pending",
|
|
57
|
+
"in-progress",
|
|
58
|
+
"review",
|
|
59
|
+
"done",
|
|
60
|
+
"blocked",
|
|
61
|
+
"cancelled",
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
export const VALID_PRIORITIES = ["low", "medium", "high"];
|
|
65
|
+
|
|
66
|
+
export function fail(prog, code, msg) {
|
|
67
|
+
process.stderr.write(`${prog}: ${msg}\n`);
|
|
68
|
+
process.exit(code);
|
|
69
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// List tasks from `.squad/tasks.json`.
|
|
3
|
+
//
|
|
4
|
+
// Usage:
|
|
5
|
+
// tools/list-tasks.mjs [--status pending,done] [--agent senior-dba]
|
|
6
|
+
// [--workspace <path>] [--file <relpath>] [--json]
|
|
7
|
+
//
|
|
8
|
+
// Without --json, prints a compact table to stdout. With --json, prints
|
|
9
|
+
// the filtered tasks as one JSON document.
|
|
10
|
+
//
|
|
11
|
+
// Exit codes:
|
|
12
|
+
// 0 success
|
|
13
|
+
// 2 invalid input
|
|
14
|
+
|
|
15
|
+
import { readTasksFile, VALID_STATUSES, fail } from "./_tasks-io.mjs";
|
|
16
|
+
|
|
17
|
+
const args = process.argv.slice(2);
|
|
18
|
+
const PROG = "list-tasks";
|
|
19
|
+
|
|
20
|
+
function parseArgs(argv) {
|
|
21
|
+
const out = {
|
|
22
|
+
status: null,
|
|
23
|
+
agent: null,
|
|
24
|
+
workspace: process.cwd(),
|
|
25
|
+
file: null,
|
|
26
|
+
json: false,
|
|
27
|
+
};
|
|
28
|
+
for (let i = 0; i < argv.length; i++) {
|
|
29
|
+
const a = argv[i];
|
|
30
|
+
switch (a) {
|
|
31
|
+
case "--status": {
|
|
32
|
+
const v = argv[++i];
|
|
33
|
+
if (!v) fail(PROG, 2, "--status requires a value");
|
|
34
|
+
out.status = v.split(",").map((s) => s.trim());
|
|
35
|
+
for (const s of out.status) {
|
|
36
|
+
if (!VALID_STATUSES.includes(s)) {
|
|
37
|
+
fail(PROG, 2, `unknown status: ${s}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case "--agent":
|
|
43
|
+
out.agent = argv[++i];
|
|
44
|
+
break;
|
|
45
|
+
case "--workspace":
|
|
46
|
+
out.workspace = argv[++i];
|
|
47
|
+
break;
|
|
48
|
+
case "--file":
|
|
49
|
+
out.file = argv[++i];
|
|
50
|
+
break;
|
|
51
|
+
case "--json":
|
|
52
|
+
out.json = true;
|
|
53
|
+
break;
|
|
54
|
+
case "--help":
|
|
55
|
+
case "-h":
|
|
56
|
+
process.stdout.write(
|
|
57
|
+
"usage: list-tasks.mjs [--status p,d] [--agent NAME] [--workspace PATH] [--file PATH] [--json]\n",
|
|
58
|
+
);
|
|
59
|
+
process.exit(0);
|
|
60
|
+
default:
|
|
61
|
+
fail(PROG, 2, `unknown flag: ${a}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function filter(tasks, opts) {
|
|
68
|
+
let out = tasks;
|
|
69
|
+
if (opts.status) {
|
|
70
|
+
const s = new Set(opts.status);
|
|
71
|
+
out = out.filter((t) => s.has(t.status));
|
|
72
|
+
}
|
|
73
|
+
if (opts.agent) {
|
|
74
|
+
out = out.filter(
|
|
75
|
+
(t) =>
|
|
76
|
+
!t.agent_hints ||
|
|
77
|
+
t.agent_hints.length === 0 ||
|
|
78
|
+
t.agent_hints.includes(opts.agent),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function renderTable(tasks) {
|
|
85
|
+
if (tasks.length === 0) {
|
|
86
|
+
return "(no tasks match filters)\n";
|
|
87
|
+
}
|
|
88
|
+
const lines = [];
|
|
89
|
+
lines.push("ID\tSTATUS\t\tPRI\tTITLE");
|
|
90
|
+
for (const t of tasks) {
|
|
91
|
+
const status = t.status.padEnd(12);
|
|
92
|
+
const pri = (t.priority ?? "medium").padEnd(6);
|
|
93
|
+
lines.push(`${t.id}\t${status}\t${pri}\t${t.title}`);
|
|
94
|
+
}
|
|
95
|
+
return lines.join("\n") + "\n";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function main() {
|
|
99
|
+
const opts = parseArgs(args);
|
|
100
|
+
const { data } = await readTasksFile(opts.workspace, opts.file);
|
|
101
|
+
const filtered = filter(data.tasks, opts);
|
|
102
|
+
|
|
103
|
+
if (opts.json) {
|
|
104
|
+
process.stdout.write(JSON.stringify(filtered, null, 2) + "\n");
|
|
105
|
+
} else {
|
|
106
|
+
process.stdout.write(renderTable(filtered));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
main().catch((err) => fail(PROG, 2, err.message ?? String(err)));
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Pick the next ready task: candidate status (default pending), all
|
|
3
|
+
// dependencies done, optional agent filter. Tiebreaker priority then id.
|
|
4
|
+
//
|
|
5
|
+
// Usage:
|
|
6
|
+
// tools/next-task.mjs [--agent senior-dba] [--workspace <path>]
|
|
7
|
+
// [--file <relpath>] [--json]
|
|
8
|
+
//
|
|
9
|
+
// Prints a one-line summary by default, or the full task as JSON with --json.
|
|
10
|
+
// If no ready task, prints reason ("no_candidates" / "all_blocked") and the
|
|
11
|
+
// blocked list.
|
|
12
|
+
//
|
|
13
|
+
// Exit codes:
|
|
14
|
+
// 0 ready task surfaced (or json mode, regardless of ready)
|
|
15
|
+
// 1 no ready task (text mode only — for shell pipelines)
|
|
16
|
+
// 2 invalid input
|
|
17
|
+
|
|
18
|
+
import { readTasksFile, fail } from "./_tasks-io.mjs";
|
|
19
|
+
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
const PROG = "next-task";
|
|
22
|
+
const PRIORITY_RANK = { high: 0, medium: 1, low: 2 };
|
|
23
|
+
|
|
24
|
+
function parseArgs(argv) {
|
|
25
|
+
const out = {
|
|
26
|
+
agent: null,
|
|
27
|
+
workspace: process.cwd(),
|
|
28
|
+
file: null,
|
|
29
|
+
json: false,
|
|
30
|
+
};
|
|
31
|
+
for (let i = 0; i < argv.length; i++) {
|
|
32
|
+
const a = argv[i];
|
|
33
|
+
switch (a) {
|
|
34
|
+
case "--agent":
|
|
35
|
+
out.agent = argv[++i];
|
|
36
|
+
break;
|
|
37
|
+
case "--workspace":
|
|
38
|
+
out.workspace = argv[++i];
|
|
39
|
+
break;
|
|
40
|
+
case "--file":
|
|
41
|
+
out.file = argv[++i];
|
|
42
|
+
break;
|
|
43
|
+
case "--json":
|
|
44
|
+
out.json = true;
|
|
45
|
+
break;
|
|
46
|
+
case "--help":
|
|
47
|
+
case "-h":
|
|
48
|
+
process.stdout.write(
|
|
49
|
+
"usage: next-task.mjs [--agent NAME] [--workspace PATH] [--file PATH] [--json]\n",
|
|
50
|
+
);
|
|
51
|
+
process.exit(0);
|
|
52
|
+
default:
|
|
53
|
+
fail(PROG, 2, `unknown flag: ${a}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function pickNext(tasks, opts) {
|
|
60
|
+
const doneIds = new Set(
|
|
61
|
+
tasks.filter((t) => t.status === "done").map((t) => t.id),
|
|
62
|
+
);
|
|
63
|
+
let candidates = tasks.filter((t) => t.status === "pending");
|
|
64
|
+
if (opts.agent) {
|
|
65
|
+
candidates = candidates.filter(
|
|
66
|
+
(t) =>
|
|
67
|
+
!t.agent_hints ||
|
|
68
|
+
t.agent_hints.length === 0 ||
|
|
69
|
+
t.agent_hints.includes(opts.agent),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (candidates.length === 0) {
|
|
73
|
+
return { task: null, reason: "no_candidates", blocked: [] };
|
|
74
|
+
}
|
|
75
|
+
const ready = [];
|
|
76
|
+
const blocked = [];
|
|
77
|
+
for (const t of candidates) {
|
|
78
|
+
const missing = (t.dependencies ?? []).filter((d) => !doneIds.has(d));
|
|
79
|
+
if (missing.length === 0) {
|
|
80
|
+
ready.push(t);
|
|
81
|
+
} else {
|
|
82
|
+
blocked.push({ id: t.id, title: t.title, missing_deps: missing });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (ready.length === 0) {
|
|
86
|
+
return { task: null, reason: "all_blocked", blocked };
|
|
87
|
+
}
|
|
88
|
+
ready.sort((a, b) => {
|
|
89
|
+
const p =
|
|
90
|
+
PRIORITY_RANK[a.priority ?? "medium"] -
|
|
91
|
+
PRIORITY_RANK[b.priority ?? "medium"];
|
|
92
|
+
if (p !== 0) return p;
|
|
93
|
+
return a.id - b.id;
|
|
94
|
+
});
|
|
95
|
+
return { task: ready[0], reason: "ok", blocked };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function main() {
|
|
99
|
+
const opts = parseArgs(args);
|
|
100
|
+
const { data } = await readTasksFile(opts.workspace, opts.file);
|
|
101
|
+
const result = pickNext(data.tasks, opts);
|
|
102
|
+
|
|
103
|
+
if (opts.json) {
|
|
104
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (result.task) {
|
|
109
|
+
const t = result.task;
|
|
110
|
+
process.stdout.write(`#${t.id} [${t.priority ?? "medium"}] ${t.title}\n`);
|
|
111
|
+
if (t.scope) process.stdout.write(` scope: ${t.scope}\n`);
|
|
112
|
+
if (t.agent_hints && t.agent_hints.length > 0) {
|
|
113
|
+
process.stdout.write(` agents: ${t.agent_hints.join(", ")}\n`);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (result.reason === "no_candidates") {
|
|
119
|
+
process.stderr.write("no pending tasks\n");
|
|
120
|
+
} else {
|
|
121
|
+
process.stderr.write("all candidates blocked:\n");
|
|
122
|
+
for (const b of result.blocked) {
|
|
123
|
+
process.stderr.write(
|
|
124
|
+
` #${b.id} ${b.title} (missing deps: ${b.missing_deps.join(", ")})\n`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
main().catch((err) => fail(PROG, 2, err.message ?? String(err)));
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Append a team decision (accept | reject) to `.squad/learnings.jsonl`.
|
|
3
|
+
//
|
|
4
|
+
// Usage:
|
|
5
|
+
// tools/record-learning.mjs --reject \
|
|
6
|
+
// --agent senior-dev-security \
|
|
7
|
+
// --finding "missing CSRF on POST /api/refund" \
|
|
8
|
+
// --reason "CSRF terminated at API gateway, see infra/edge.tf" \
|
|
9
|
+
// --pr 42
|
|
10
|
+
//
|
|
11
|
+
// tools/record-learning.mjs --accept \
|
|
12
|
+
// --agent senior-architect \
|
|
13
|
+
// --finding "cross-module coupling Auth -> Billing" \
|
|
14
|
+
// --reason "refactored to event bus" \
|
|
15
|
+
// --branch refactor/auth
|
|
16
|
+
//
|
|
17
|
+
// Flags:
|
|
18
|
+
// --accept | --reject (required, mutually exclusive)
|
|
19
|
+
// --agent <name> (required)
|
|
20
|
+
// --finding "<short title>" (required)
|
|
21
|
+
// --reason "<rationale>" (optional but recommended)
|
|
22
|
+
// --severity Blocker|Major|Minor|Suggestion (optional)
|
|
23
|
+
// --pr <number> (optional)
|
|
24
|
+
// --branch <name> (optional)
|
|
25
|
+
// --scope "<glob>" (optional, e.g. "src/auth/**")
|
|
26
|
+
// --workspace <path> (default: cwd)
|
|
27
|
+
// --file <relpath> (override the JSONL location for this run)
|
|
28
|
+
//
|
|
29
|
+
// Exit codes:
|
|
30
|
+
// 0 success
|
|
31
|
+
// 2 invalid input
|
|
32
|
+
|
|
33
|
+
import { promises as fs } from "node:fs";
|
|
34
|
+
import path from "node:path";
|
|
35
|
+
|
|
36
|
+
const args = process.argv.slice(2);
|
|
37
|
+
|
|
38
|
+
function fail(code, msg) {
|
|
39
|
+
process.stderr.write(`record-learning: ${msg}\n`);
|
|
40
|
+
process.exit(code);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseArgs(argv) {
|
|
44
|
+
const out = {
|
|
45
|
+
decision: null, // 'accept' | 'reject'
|
|
46
|
+
agent: null,
|
|
47
|
+
finding: null,
|
|
48
|
+
reason: null,
|
|
49
|
+
severity: null,
|
|
50
|
+
pr: null,
|
|
51
|
+
branch: null,
|
|
52
|
+
scope: null,
|
|
53
|
+
workspace: process.cwd(),
|
|
54
|
+
file: null,
|
|
55
|
+
};
|
|
56
|
+
for (let i = 0; i < argv.length; i++) {
|
|
57
|
+
const a = argv[i];
|
|
58
|
+
switch (a) {
|
|
59
|
+
case "--accept":
|
|
60
|
+
if (out.decision)
|
|
61
|
+
fail(2, "--accept and --reject are mutually exclusive");
|
|
62
|
+
out.decision = "accept";
|
|
63
|
+
break;
|
|
64
|
+
case "--reject":
|
|
65
|
+
if (out.decision)
|
|
66
|
+
fail(2, "--accept and --reject are mutually exclusive");
|
|
67
|
+
out.decision = "reject";
|
|
68
|
+
break;
|
|
69
|
+
case "--agent":
|
|
70
|
+
out.agent = argv[++i];
|
|
71
|
+
break;
|
|
72
|
+
case "--finding":
|
|
73
|
+
out.finding = argv[++i];
|
|
74
|
+
break;
|
|
75
|
+
case "--reason":
|
|
76
|
+
out.reason = argv[++i];
|
|
77
|
+
break;
|
|
78
|
+
case "--severity":
|
|
79
|
+
out.severity = argv[++i];
|
|
80
|
+
break;
|
|
81
|
+
case "--pr":
|
|
82
|
+
out.pr = Number(argv[++i]);
|
|
83
|
+
if (!Number.isInteger(out.pr) || out.pr <= 0) {
|
|
84
|
+
fail(2, "--pr must be a positive integer");
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case "--branch":
|
|
88
|
+
out.branch = argv[++i];
|
|
89
|
+
break;
|
|
90
|
+
case "--scope":
|
|
91
|
+
out.scope = argv[++i];
|
|
92
|
+
break;
|
|
93
|
+
case "--workspace":
|
|
94
|
+
out.workspace = argv[++i];
|
|
95
|
+
break;
|
|
96
|
+
case "--file":
|
|
97
|
+
out.file = argv[++i];
|
|
98
|
+
break;
|
|
99
|
+
case "--help":
|
|
100
|
+
case "-h":
|
|
101
|
+
process.stdout.write(
|
|
102
|
+
"usage: record-learning.mjs --accept|--reject --agent <name> --finding <title> [options]\n",
|
|
103
|
+
);
|
|
104
|
+
process.exit(0);
|
|
105
|
+
default:
|
|
106
|
+
fail(2, `unknown flag: ${a}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!out.decision) fail(2, "one of --accept or --reject is required");
|
|
110
|
+
if (!out.agent) fail(2, "--agent <name> is required");
|
|
111
|
+
if (!out.finding) fail(2, "--finding <title> is required");
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function main() {
|
|
116
|
+
const opts = parseArgs(args);
|
|
117
|
+
const ts = new Date().toISOString();
|
|
118
|
+
const entry = {
|
|
119
|
+
ts,
|
|
120
|
+
agent: opts.agent,
|
|
121
|
+
finding: opts.finding,
|
|
122
|
+
decision: opts.decision,
|
|
123
|
+
};
|
|
124
|
+
if (opts.severity) entry.severity = opts.severity;
|
|
125
|
+
if (opts.reason) entry.reason = opts.reason;
|
|
126
|
+
if (opts.pr) entry.pr = opts.pr;
|
|
127
|
+
if (opts.branch) entry.branch = opts.branch;
|
|
128
|
+
if (opts.scope) entry.scope = opts.scope;
|
|
129
|
+
|
|
130
|
+
const target = path.resolve(
|
|
131
|
+
opts.workspace,
|
|
132
|
+
opts.file ?? ".squad/learnings.jsonl",
|
|
133
|
+
);
|
|
134
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
135
|
+
await fs.appendFile(target, JSON.stringify(entry) + "\n", "utf8");
|
|
136
|
+
|
|
137
|
+
process.stdout.write(
|
|
138
|
+
`recorded: ${opts.decision} on ${opts.agent} — "${opts.finding}"\n`,
|
|
139
|
+
);
|
|
140
|
+
process.stdout.write(`file: ${target}\n`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
main().catch((err) => {
|
|
144
|
+
fail(2, `unexpected error: ${err && err.stack ? err.stack : err}`);
|
|
145
|
+
});
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Bulk-add tasks to `.squad/tasks.json`. Reads a JSON array of task inputs
|
|
3
|
+
// from stdin (or a file via --input) and appends them.
|
|
4
|
+
//
|
|
5
|
+
// Usage:
|
|
6
|
+
// echo '[{"title":"Add CSRF","scope":"src/api/**"}]' | tools/record-tasks.mjs
|
|
7
|
+
// tools/record-tasks.mjs --input parsed-prd.json
|
|
8
|
+
//
|
|
9
|
+
// Each task input may include: title (required), description, dependencies,
|
|
10
|
+
// priority, details, test_strategy, scope, agent_hints. id is optional —
|
|
11
|
+
// auto-allocated as max(existing) + 1 in input order.
|
|
12
|
+
//
|
|
13
|
+
// Flags:
|
|
14
|
+
// --input <path> Read JSON from this file instead of stdin
|
|
15
|
+
// --workspace <path> Default: cwd
|
|
16
|
+
// --file <relpath> Override the JSON store location
|
|
17
|
+
// --dry-run Validate + print resulting file, do not write
|
|
18
|
+
//
|
|
19
|
+
// Exit codes:
|
|
20
|
+
// 0 success
|
|
21
|
+
// 2 invalid input
|
|
22
|
+
//
|
|
23
|
+
// This CLI is intentionally minimal — no schema validation beyond shape.
|
|
24
|
+
// Production use should go through the MCP `record_tasks` tool which
|
|
25
|
+
// validates the full zod schema.
|
|
26
|
+
|
|
27
|
+
import { promises as fs } from "node:fs";
|
|
28
|
+
import {
|
|
29
|
+
readTasksFile,
|
|
30
|
+
writeTasksFile,
|
|
31
|
+
VALID_PRIORITIES,
|
|
32
|
+
fail,
|
|
33
|
+
} from "./_tasks-io.mjs";
|
|
34
|
+
|
|
35
|
+
const args = process.argv.slice(2);
|
|
36
|
+
const PROG = "record-tasks";
|
|
37
|
+
|
|
38
|
+
function parseArgs(argv) {
|
|
39
|
+
const out = {
|
|
40
|
+
input: null,
|
|
41
|
+
workspace: process.cwd(),
|
|
42
|
+
file: null,
|
|
43
|
+
dryRun: false,
|
|
44
|
+
};
|
|
45
|
+
for (let i = 0; i < argv.length; i++) {
|
|
46
|
+
const a = argv[i];
|
|
47
|
+
switch (a) {
|
|
48
|
+
case "--input":
|
|
49
|
+
out.input = argv[++i];
|
|
50
|
+
break;
|
|
51
|
+
case "--workspace":
|
|
52
|
+
out.workspace = argv[++i];
|
|
53
|
+
break;
|
|
54
|
+
case "--file":
|
|
55
|
+
out.file = argv[++i];
|
|
56
|
+
break;
|
|
57
|
+
case "--dry-run":
|
|
58
|
+
out.dryRun = true;
|
|
59
|
+
break;
|
|
60
|
+
case "--help":
|
|
61
|
+
case "-h":
|
|
62
|
+
process.stdout.write(
|
|
63
|
+
"usage: record-tasks.mjs [--input PATH | <stdin>] [--workspace PATH] [--file PATH] [--dry-run]\n",
|
|
64
|
+
);
|
|
65
|
+
process.exit(0);
|
|
66
|
+
default:
|
|
67
|
+
fail(PROG, 2, `unknown flag: ${a}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function readStdin() {
|
|
74
|
+
const chunks = [];
|
|
75
|
+
for await (const c of process.stdin) chunks.push(c);
|
|
76
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function validateInputs(inputs) {
|
|
80
|
+
if (!Array.isArray(inputs) || inputs.length === 0) {
|
|
81
|
+
fail(PROG, 2, "input must be a non-empty array of task objects");
|
|
82
|
+
}
|
|
83
|
+
for (const [i, t] of inputs.entries()) {
|
|
84
|
+
if (!t || typeof t !== "object") {
|
|
85
|
+
fail(PROG, 2, `input[${i}]: not an object`);
|
|
86
|
+
}
|
|
87
|
+
if (typeof t.title !== "string" || t.title.length === 0) {
|
|
88
|
+
fail(PROG, 2, `input[${i}]: title is required and must be a string`);
|
|
89
|
+
}
|
|
90
|
+
if (t.priority !== undefined && !VALID_PRIORITIES.includes(t.priority)) {
|
|
91
|
+
fail(PROG, 2, `input[${i}]: priority must be low|medium|high`);
|
|
92
|
+
}
|
|
93
|
+
if (t.dependencies !== undefined && !Array.isArray(t.dependencies)) {
|
|
94
|
+
fail(PROG, 2, `input[${i}]: dependencies must be an array`);
|
|
95
|
+
}
|
|
96
|
+
if (t.id !== undefined && (!Number.isInteger(t.id) || t.id <= 0)) {
|
|
97
|
+
fail(PROG, 2, `input[${i}]: id must be a positive integer`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function main() {
|
|
103
|
+
const opts = parseArgs(args);
|
|
104
|
+
const raw = opts.input
|
|
105
|
+
? await fs.readFile(opts.input, "utf8")
|
|
106
|
+
: await readStdin();
|
|
107
|
+
|
|
108
|
+
let inputs;
|
|
109
|
+
try {
|
|
110
|
+
inputs = JSON.parse(raw);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
fail(PROG, 2, `invalid JSON on input: ${err.message}`);
|
|
113
|
+
}
|
|
114
|
+
validateInputs(inputs);
|
|
115
|
+
|
|
116
|
+
const { filePath, data } = await readTasksFile(opts.workspace, opts.file);
|
|
117
|
+
const existingIds = new Set(data.tasks.map((t) => t.id));
|
|
118
|
+
let cursor = data.tasks.reduce((m, t) => Math.max(m, t.id), 0);
|
|
119
|
+
const ts = new Date().toISOString();
|
|
120
|
+
const newTasks = [];
|
|
121
|
+
const seen = new Set(existingIds);
|
|
122
|
+
|
|
123
|
+
for (const inp of inputs) {
|
|
124
|
+
let id = inp.id;
|
|
125
|
+
if (id === undefined) {
|
|
126
|
+
cursor += 1;
|
|
127
|
+
id = cursor;
|
|
128
|
+
} else {
|
|
129
|
+
if (seen.has(id)) {
|
|
130
|
+
fail(PROG, 2, `duplicate task id ${id}`);
|
|
131
|
+
}
|
|
132
|
+
cursor = Math.max(cursor, id);
|
|
133
|
+
}
|
|
134
|
+
seen.add(id);
|
|
135
|
+
newTasks.push({
|
|
136
|
+
id,
|
|
137
|
+
title: inp.title,
|
|
138
|
+
...(inp.description !== undefined && { description: inp.description }),
|
|
139
|
+
status: "pending",
|
|
140
|
+
dependencies: inp.dependencies ?? [],
|
|
141
|
+
priority: inp.priority ?? "medium",
|
|
142
|
+
...(inp.details !== undefined && { details: inp.details }),
|
|
143
|
+
...(inp.test_strategy !== undefined && {
|
|
144
|
+
test_strategy: inp.test_strategy,
|
|
145
|
+
}),
|
|
146
|
+
...(inp.scope !== undefined && { scope: inp.scope }),
|
|
147
|
+
...(inp.agent_hints !== undefined && { agent_hints: inp.agent_hints }),
|
|
148
|
+
subtasks: [],
|
|
149
|
+
created_at: ts,
|
|
150
|
+
updated_at: ts,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Validate deps after id allocation (forward refs allowed in batch).
|
|
155
|
+
for (const t of newTasks) {
|
|
156
|
+
for (const dep of t.dependencies) {
|
|
157
|
+
if (!seen.has(dep)) {
|
|
158
|
+
fail(PROG, 2, `task ${t.id} depends on unknown id ${dep}`);
|
|
159
|
+
}
|
|
160
|
+
if (dep === t.id) {
|
|
161
|
+
fail(PROG, 2, `task ${t.id} cannot depend on itself`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const next = {
|
|
167
|
+
version: data.version ?? 1,
|
|
168
|
+
tasks: [...data.tasks, ...newTasks],
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
if (opts.dryRun) {
|
|
172
|
+
process.stdout.write(JSON.stringify(next, null, 2) + "\n");
|
|
173
|
+
process.stderr.write(
|
|
174
|
+
`would record: ${newTasks.length} task(s), ids ${newTasks.map((t) => t.id).join(", ")}\n`,
|
|
175
|
+
);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
await writeTasksFile(filePath, next);
|
|
180
|
+
process.stdout.write(
|
|
181
|
+
`recorded: ${newTasks.length} task(s), ids ${newTasks.map((t) => t.id).join(", ")}\n`,
|
|
182
|
+
);
|
|
183
|
+
process.stdout.write(`file: ${filePath}\n`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
main().catch((err) => fail(PROG, 2, err.message ?? String(err)));
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Flip a task (or subtask) status.
|
|
3
|
+
//
|
|
4
|
+
// Usage:
|
|
5
|
+
// tools/update-task-status.mjs --task 5 --status in-progress
|
|
6
|
+
// tools/update-task-status.mjs --task 5 --subtask 2 --status done
|
|
7
|
+
//
|
|
8
|
+
// Flags:
|
|
9
|
+
// --task <id> (required)
|
|
10
|
+
// --status pending|in-progress|review|done|blocked|cancelled (required)
|
|
11
|
+
// --subtask <id> (optional)
|
|
12
|
+
// --workspace <path> (default: cwd)
|
|
13
|
+
// --file <relpath> (override path)
|
|
14
|
+
//
|
|
15
|
+
// Exit codes:
|
|
16
|
+
// 0 success
|
|
17
|
+
// 2 invalid input or task/subtask not found
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
readTasksFile,
|
|
21
|
+
writeTasksFile,
|
|
22
|
+
VALID_STATUSES,
|
|
23
|
+
fail,
|
|
24
|
+
} from "./_tasks-io.mjs";
|
|
25
|
+
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
const PROG = "update-task-status";
|
|
28
|
+
|
|
29
|
+
function parseArgs(argv) {
|
|
30
|
+
const out = {
|
|
31
|
+
task: null,
|
|
32
|
+
subtask: null,
|
|
33
|
+
status: null,
|
|
34
|
+
workspace: process.cwd(),
|
|
35
|
+
file: null,
|
|
36
|
+
};
|
|
37
|
+
for (let i = 0; i < argv.length; i++) {
|
|
38
|
+
const a = argv[i];
|
|
39
|
+
switch (a) {
|
|
40
|
+
case "--task":
|
|
41
|
+
out.task = Number(argv[++i]);
|
|
42
|
+
if (!Number.isInteger(out.task) || out.task <= 0) {
|
|
43
|
+
fail(PROG, 2, "--task must be a positive integer");
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
case "--subtask":
|
|
47
|
+
out.subtask = Number(argv[++i]);
|
|
48
|
+
if (!Number.isInteger(out.subtask) || out.subtask <= 0) {
|
|
49
|
+
fail(PROG, 2, "--subtask must be a positive integer");
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case "--status":
|
|
53
|
+
out.status = argv[++i];
|
|
54
|
+
if (!VALID_STATUSES.includes(out.status)) {
|
|
55
|
+
fail(PROG, 2, `unknown status: ${out.status}`);
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
case "--workspace":
|
|
59
|
+
out.workspace = argv[++i];
|
|
60
|
+
break;
|
|
61
|
+
case "--file":
|
|
62
|
+
out.file = argv[++i];
|
|
63
|
+
break;
|
|
64
|
+
case "--help":
|
|
65
|
+
case "-h":
|
|
66
|
+
process.stdout.write(
|
|
67
|
+
"usage: update-task-status.mjs --task ID --status STATUS [--subtask ID] [--workspace PATH] [--file PATH]\n",
|
|
68
|
+
);
|
|
69
|
+
process.exit(0);
|
|
70
|
+
default:
|
|
71
|
+
fail(PROG, 2, `unknown flag: ${a}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (out.task === null) fail(PROG, 2, "--task is required");
|
|
75
|
+
if (out.status === null) fail(PROG, 2, "--status is required");
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function main() {
|
|
80
|
+
const opts = parseArgs(args);
|
|
81
|
+
const { filePath, data } = await readTasksFile(opts.workspace, opts.file);
|
|
82
|
+
|
|
83
|
+
const idx = data.tasks.findIndex((t) => t.id === opts.task);
|
|
84
|
+
if (idx < 0) fail(PROG, 2, `task ${opts.task} not found`);
|
|
85
|
+
|
|
86
|
+
const ts = new Date().toISOString();
|
|
87
|
+
const original = data.tasks[idx];
|
|
88
|
+
|
|
89
|
+
if (opts.subtask !== null) {
|
|
90
|
+
const sIdx = (original.subtasks ?? []).findIndex(
|
|
91
|
+
(s) => s.id === opts.subtask,
|
|
92
|
+
);
|
|
93
|
+
if (sIdx < 0) {
|
|
94
|
+
fail(PROG, 2, `subtask ${opts.subtask} not found on task ${opts.task}`);
|
|
95
|
+
}
|
|
96
|
+
const newSubtasks = [...original.subtasks];
|
|
97
|
+
newSubtasks[sIdx] = { ...newSubtasks[sIdx], status: opts.status };
|
|
98
|
+
data.tasks[idx] = {
|
|
99
|
+
...original,
|
|
100
|
+
subtasks: newSubtasks,
|
|
101
|
+
updated_at: ts,
|
|
102
|
+
};
|
|
103
|
+
} else {
|
|
104
|
+
data.tasks[idx] = { ...original, status: opts.status, updated_at: ts };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
await writeTasksFile(filePath, data);
|
|
108
|
+
process.stdout.write(
|
|
109
|
+
`updated: task ${opts.task}${opts.subtask !== null ? `.${opts.subtask}` : ""} -> ${opts.status}\n`,
|
|
110
|
+
);
|
|
111
|
+
process.stdout.write(`file: ${filePath}\n`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
main().catch((err) => fail(PROG, 2, err.message ?? String(err)));
|
|
File without changes
|
|
File without changes
|
|
File without changes
|