@gempack/squad-mcp 0.5.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/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +3 -2
- package/CHANGELOG.md +271 -17
- package/INSTALL.md +156 -24
- package/README.md +278 -27
- 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 → senior-dev-reviewer.md} +33 -1
- 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/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 +8 -1
- package/dist/resources/agent-loader.js +83 -48
- 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/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/package.json +11 -1
- package/skills/squad/SKILL.md +454 -0
- package/tools/_tasks-io.mjs +69 -0
- package/tools/list-tasks.mjs +110 -0
- package/tools/next-task.mjs +131 -0
- package/tools/post-review.mjs +212 -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}/Skill-Squad-Dev.md +0 -0
- /package/{agents → shared}/Skill-Squad-Review.md +0 -0
- /package/{agents → shared}/_Severity-and-Ownership.md +0 -0
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Server } from
|
|
3
|
-
import { StdioServerTransport } from
|
|
4
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from
|
|
5
|
-
import { registerTools, dispatchTool, listTools } from
|
|
6
|
-
import { listResources, readResource } from
|
|
7
|
-
import { listPrompts, getPrompt } from
|
|
8
|
-
import { logger, setupProcessHandlers } from
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { registerTools, dispatchTool, listTools } from "./tools/registry.js";
|
|
6
|
+
import { listResources, readResource } from "./resources/registry.js";
|
|
7
|
+
import { listPrompts, getPrompt } from "./prompts/registry.js";
|
|
8
|
+
import { logger, setupProcessHandlers } from "./observability/logger.js";
|
|
9
9
|
setupProcessHandlers();
|
|
10
|
-
const SERVER_VERSION =
|
|
10
|
+
const SERVER_VERSION = "0.6.1";
|
|
11
11
|
const server = new Server({
|
|
12
|
-
name:
|
|
12
|
+
name: "squad-mcp",
|
|
13
13
|
version: SERVER_VERSION,
|
|
14
14
|
}, {
|
|
15
15
|
capabilities: {
|
|
@@ -19,15 +19,21 @@ const server = new Server({
|
|
|
19
19
|
},
|
|
20
20
|
});
|
|
21
21
|
registerTools();
|
|
22
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
22
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
23
|
+
tools: listTools(),
|
|
24
|
+
}));
|
|
23
25
|
server.setRequestHandler(CallToolRequestSchema, async (req) => dispatchTool(req.params.name, req.params.arguments ?? {}));
|
|
24
|
-
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
26
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
27
|
+
resources: await listResources(),
|
|
28
|
+
}));
|
|
25
29
|
server.setRequestHandler(ReadResourceRequestSchema, async (req) => readResource(req.params.uri));
|
|
26
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
30
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
31
|
+
prompts: listPrompts(),
|
|
32
|
+
}));
|
|
27
33
|
server.setRequestHandler(GetPromptRequestSchema, async (req) => getPrompt(req.params.name, req.params.arguments ?? {}));
|
|
28
34
|
const transport = new StdioServerTransport();
|
|
29
35
|
await server.connect(transport);
|
|
30
|
-
logger.info(
|
|
36
|
+
logger.info("server started", {
|
|
31
37
|
details: { version: SERVER_VERSION, tools: listTools().length },
|
|
32
38
|
});
|
|
33
39
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEzE,oBAAoB,EAAE,CAAC;AAEvB,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;CACxB,EACD;IACE,YAAY,EAAE;QACZ,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;KACZ;CACF,CACF,CAAC;AAEF,aAAa,EAAE,CAAC;AAEhB,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEzE,oBAAoB,EAAE,CAAC;AAEvB,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;CACxB,EACD;IACE,YAAY,EAAE;QACZ,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;KACZ;CACF,CACF,CAAC;AAEF,aAAa,EAAE,CAAC;AAEhB,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IAC5D,KAAK,EAAE,SAAS,EAAE;CACnB,CAAC,CAAC,CAAC;AACJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAC5D,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAC1D,CAAC;AAEF,MAAM,CAAC,iBAAiB,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IAChE,SAAS,EAAE,MAAM,aAAa,EAAE;CACjC,CAAC,CAAC,CAAC;AACJ,MAAM,CAAC,iBAAiB,CAAC,yBAAyB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAChE,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAC7B,CAAC;AAEF,MAAM,CAAC,iBAAiB,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IAC9D,OAAO,EAAE,WAAW,EAAE;CACvB,CAAC,CAAC,CAAC;AACJ,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAC7D,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CACvD,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEhC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE;IAC5B,OAAO,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE;CAChE,CAAC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { LearningEntry } from "./store.js";
|
|
2
|
+
export interface FormatLearningsOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Filter to learnings whose `scope` glob matches at least one of these
|
|
5
|
+
* paths. Used to narrow per-PR injection to learnings relevant to the
|
|
6
|
+
* files actually changed. When empty / undefined, all entries pass.
|
|
7
|
+
*/
|
|
8
|
+
changedFiles?: string[];
|
|
9
|
+
/**
|
|
10
|
+
* Cap the rendered list. Default 50. Tail-most-recent. Hard cap of 200
|
|
11
|
+
* to prevent prompt bloat.
|
|
12
|
+
*/
|
|
13
|
+
limit?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Heading level for the section. Default `## Past team decisions`. Adjust
|
|
16
|
+
* when injecting into a prompt that already nests under a higher heading.
|
|
17
|
+
*/
|
|
18
|
+
heading?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Render a slice of learning entries as a markdown block ready to inject into
|
|
22
|
+
* an agent or consolidator prompt. Pure function. The block is intentionally
|
|
23
|
+
* compact — each entry is one numbered line so the LLM can scan quickly and
|
|
24
|
+
* reference back ("see decision #4 — already declined this CSRF flag").
|
|
25
|
+
*
|
|
26
|
+
* Returns `''` when no entries qualify after filtering. Callers should check
|
|
27
|
+
* the empty case before injecting (avoid empty headers in prompts).
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatLearningsForPrompt(entries: LearningEntry[], options?: FormatLearningsOptions): string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { matchesGlob } from "../config/squad-yaml.js";
|
|
2
|
+
const HARD_LIMIT = 200;
|
|
3
|
+
const DEFAULT_LIMIT = 50;
|
|
4
|
+
const DEFAULT_HEADING = "## Past team decisions";
|
|
5
|
+
/**
|
|
6
|
+
* Render a slice of learning entries as a markdown block ready to inject into
|
|
7
|
+
* an agent or consolidator prompt. Pure function. The block is intentionally
|
|
8
|
+
* compact — each entry is one numbered line so the LLM can scan quickly and
|
|
9
|
+
* reference back ("see decision #4 — already declined this CSRF flag").
|
|
10
|
+
*
|
|
11
|
+
* Returns `''` when no entries qualify after filtering. Callers should check
|
|
12
|
+
* the empty case before injecting (avoid empty headers in prompts).
|
|
13
|
+
*/
|
|
14
|
+
export function formatLearningsForPrompt(entries, options = {}) {
|
|
15
|
+
const limit = Math.min(options.limit ?? DEFAULT_LIMIT, HARD_LIMIT);
|
|
16
|
+
const heading = options.heading ?? DEFAULT_HEADING;
|
|
17
|
+
// Filter by scope glob match against changedFiles. An entry without a scope
|
|
18
|
+
// is repo-wide and always passes. An entry WITH a scope passes if any
|
|
19
|
+
// changed file matches the scope glob.
|
|
20
|
+
let relevant = entries;
|
|
21
|
+
if (options.changedFiles && options.changedFiles.length > 0) {
|
|
22
|
+
relevant = entries.filter((e) => {
|
|
23
|
+
if (!e.scope)
|
|
24
|
+
return true;
|
|
25
|
+
return options.changedFiles.some((p) => matchesGlob(e.scope, p));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// Tail-N most recent. Append order = chronological, so slice from end.
|
|
29
|
+
const tail = relevant.slice(-limit);
|
|
30
|
+
if (tail.length === 0)
|
|
31
|
+
return "";
|
|
32
|
+
// Render most-recent-first to bias the LLM's attention.
|
|
33
|
+
const ordered = [...tail].reverse();
|
|
34
|
+
const lines = [];
|
|
35
|
+
lines.push(heading);
|
|
36
|
+
lines.push("");
|
|
37
|
+
lines.push(`Recent decisions on similar findings (${ordered.length} of ${entries.length} total, most recent first). When evaluating a new finding that matches a past **rejected** decision (similar agent + similar finding text + matching scope), suppress or downgrade severity. When a finding contradicts a past **accepted** decision, flag the contradiction explicitly.`);
|
|
38
|
+
lines.push("");
|
|
39
|
+
ordered.forEach((e, i) => {
|
|
40
|
+
const ref = e.pr
|
|
41
|
+
? `PR #${e.pr}`
|
|
42
|
+
: e.branch
|
|
43
|
+
? `branch ${e.branch}`
|
|
44
|
+
: e.ts.slice(0, 10);
|
|
45
|
+
const verdict = e.decision === "reject" ? "REJECTED" : "ACCEPTED";
|
|
46
|
+
const sev = e.severity ? ` [${e.severity}]` : "";
|
|
47
|
+
const scope = e.scope ? ` (scope: \`${e.scope}\`)` : "";
|
|
48
|
+
lines.push(`${i + 1}. **${verdict}** at ${ref}${scope} — ${e.agent}${sev}: "${e.finding}"`);
|
|
49
|
+
if (e.reason) {
|
|
50
|
+
lines.push(` Reason: ${e.reason}`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return lines.join("\n") + "\n";
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/learning/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type AgentName } from "../config/ownership-matrix.js";
|
|
3
|
+
/**
|
|
4
|
+
* One row in `.squad/learnings.jsonl`. Append-only — entries are never
|
|
5
|
+
* rewritten, just superseded by later ones with the same (agent, finding,
|
|
6
|
+
* scope) tuple. Keep the schema small; rich query semantics are out of
|
|
7
|
+
* scope for V1 (the consolidator does free-text recall, not vector search).
|
|
8
|
+
*/
|
|
9
|
+
declare const learningEntrySchema: z.ZodObject<{
|
|
10
|
+
/** ISO 8601 timestamp. Required for ordering. */
|
|
11
|
+
ts: z.ZodString;
|
|
12
|
+
/** PR number when recorded from `/squad-review #N`; optional otherwise. */
|
|
13
|
+
pr: z.ZodOptional<z.ZodNumber>;
|
|
14
|
+
/** Branch name when recorded from a local review (no PR ref). */
|
|
15
|
+
branch: z.ZodOptional<z.ZodString>;
|
|
16
|
+
/** Which agent's finding this decision concerns. */
|
|
17
|
+
agent: z.ZodEnum<[AgentName, ...AgentName[]]>;
|
|
18
|
+
/** Severity at the time of the decision (Blocker / Major / Minor / Suggestion). */
|
|
19
|
+
severity: z.ZodOptional<z.ZodEnum<["Blocker", "Major", "Minor", "Suggestion"]>>;
|
|
20
|
+
/** Short title of the finding — same shape as Finding.title in consolidate. */
|
|
21
|
+
finding: z.ZodString;
|
|
22
|
+
/** Whether the team accepted or rejected this finding. */
|
|
23
|
+
decision: z.ZodEnum<["accept", "reject"]>;
|
|
24
|
+
/** Free-form rationale. Surfaces in the consolidator prompt. */
|
|
25
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
26
|
+
/**
|
|
27
|
+
* Glob-ish path scope this decision applies to (e.g. "src/auth/**"). When
|
|
28
|
+
* absent, the decision applies repo-wide. Used by the formatter to filter
|
|
29
|
+
* learnings down to those relevant to the current diff.
|
|
30
|
+
*/
|
|
31
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
agent: AgentName;
|
|
34
|
+
ts: string;
|
|
35
|
+
finding: string;
|
|
36
|
+
decision: "accept" | "reject";
|
|
37
|
+
reason?: string | undefined;
|
|
38
|
+
severity?: "Blocker" | "Major" | "Minor" | "Suggestion" | undefined;
|
|
39
|
+
pr?: number | undefined;
|
|
40
|
+
branch?: string | undefined;
|
|
41
|
+
scope?: string | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
agent: AgentName;
|
|
44
|
+
ts: string;
|
|
45
|
+
finding: string;
|
|
46
|
+
decision: "accept" | "reject";
|
|
47
|
+
reason?: string | undefined;
|
|
48
|
+
severity?: "Blocker" | "Major" | "Minor" | "Suggestion" | undefined;
|
|
49
|
+
pr?: number | undefined;
|
|
50
|
+
branch?: string | undefined;
|
|
51
|
+
scope?: string | undefined;
|
|
52
|
+
}>;
|
|
53
|
+
export type LearningEntry = z.infer<typeof learningEntrySchema>;
|
|
54
|
+
/**
|
|
55
|
+
* Default location for the JSONL file, relative to workspace_root. Repo-versioned
|
|
56
|
+
* by convention; the team commits `.squad/learnings.jsonl` along with the code so
|
|
57
|
+
* decisions are auditable in PR diffs.
|
|
58
|
+
*/
|
|
59
|
+
export declare const DEFAULT_LEARNING_PATH = ".squad/learnings.jsonl";
|
|
60
|
+
/** Test-only: clear the per-process cache. Production code MUST NOT call this. */
|
|
61
|
+
export declare function __resetLearningStoreCacheForTests(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Read all learnings from the JSONL file. Returns [] if the file does not exist
|
|
64
|
+
* (a fresh repo with no decisions recorded is the common case). Throws on
|
|
65
|
+
* parse failure of any individual line — callers may want to soft-fail, but
|
|
66
|
+
* silent corruption is worse than loud rejection.
|
|
67
|
+
*/
|
|
68
|
+
export declare function readLearnings(workspaceRoot: string, options?: {
|
|
69
|
+
configuredPath?: string;
|
|
70
|
+
}): Promise<LearningEntry[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Append a new learning entry to the JSONL file. Creates the directory and
|
|
73
|
+
* file if needed. Atomic at the append level (single fs.appendFile call —
|
|
74
|
+
* Node serialises this on POSIX); concurrent appenders may interleave entries
|
|
75
|
+
* but never corrupt them line-wise.
|
|
76
|
+
*
|
|
77
|
+
* Stamps the timestamp here if the caller did not supply one — gives a single
|
|
78
|
+
* source of clock truth and prevents stale ts in CLI invocations.
|
|
79
|
+
*/
|
|
80
|
+
export declare function appendLearning(workspaceRoot: string, entry: Omit<LearningEntry, "ts"> & {
|
|
81
|
+
ts?: string;
|
|
82
|
+
}, options?: {
|
|
83
|
+
configuredPath?: string;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
filePath: string;
|
|
86
|
+
entry: LearningEntry;
|
|
87
|
+
}>;
|
|
88
|
+
/**
|
|
89
|
+
* Filter helper: pick the most recent N entries, optionally narrowed by
|
|
90
|
+
* agent. Used by the formatter to inject a small, relevant slice into the
|
|
91
|
+
* agent / consolidator prompt.
|
|
92
|
+
*
|
|
93
|
+
* Sort: input is in append order (oldest first). We slice the tail. The
|
|
94
|
+
* filter happens BEFORE the slice — `recentForAgent('senior-dba', 50)`
|
|
95
|
+
* returns the last 50 DBA decisions, not the last 50 decisions overall
|
|
96
|
+
* filtered to DBA (which would often return zero on diverse repos).
|
|
97
|
+
*/
|
|
98
|
+
export declare function tailRecent(entries: LearningEntry[], limit: number, options?: {
|
|
99
|
+
agent?: AgentName;
|
|
100
|
+
decision?: "accept" | "reject";
|
|
101
|
+
}): LearningEntry[];
|
|
102
|
+
export {};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { AGENT_NAMES_TUPLE, } from "../config/ownership-matrix.js";
|
|
5
|
+
import { SquadError } from "../errors.js";
|
|
6
|
+
import { logger } from "../observability/logger.js";
|
|
7
|
+
/**
|
|
8
|
+
* One row in `.squad/learnings.jsonl`. Append-only — entries are never
|
|
9
|
+
* rewritten, just superseded by later ones with the same (agent, finding,
|
|
10
|
+
* scope) tuple. Keep the schema small; rich query semantics are out of
|
|
11
|
+
* scope for V1 (the consolidator does free-text recall, not vector search).
|
|
12
|
+
*/
|
|
13
|
+
const learningEntrySchema = z.object({
|
|
14
|
+
/** ISO 8601 timestamp. Required for ordering. */
|
|
15
|
+
ts: z.string().min(1).max(40),
|
|
16
|
+
/** PR number when recorded from `/squad-review #N`; optional otherwise. */
|
|
17
|
+
pr: z.number().int().positive().optional(),
|
|
18
|
+
/** Branch name when recorded from a local review (no PR ref). */
|
|
19
|
+
branch: z.string().min(1).max(255).optional(),
|
|
20
|
+
/** Which agent's finding this decision concerns. */
|
|
21
|
+
agent: z.enum(AGENT_NAMES_TUPLE),
|
|
22
|
+
/** Severity at the time of the decision (Blocker / Major / Minor / Suggestion). */
|
|
23
|
+
severity: z.enum(["Blocker", "Major", "Minor", "Suggestion"]).optional(),
|
|
24
|
+
/** Short title of the finding — same shape as Finding.title in consolidate. */
|
|
25
|
+
finding: z.string().min(1).max(2048),
|
|
26
|
+
/** Whether the team accepted or rejected this finding. */
|
|
27
|
+
decision: z.enum(["accept", "reject"]),
|
|
28
|
+
/** Free-form rationale. Surfaces in the consolidator prompt. */
|
|
29
|
+
reason: z.string().max(4096).optional(),
|
|
30
|
+
/**
|
|
31
|
+
* Glob-ish path scope this decision applies to (e.g. "src/auth/**"). When
|
|
32
|
+
* absent, the decision applies repo-wide. Used by the formatter to filter
|
|
33
|
+
* learnings down to those relevant to the current diff.
|
|
34
|
+
*/
|
|
35
|
+
scope: z.string().min(1).max(512).optional(),
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Default location for the JSONL file, relative to workspace_root. Repo-versioned
|
|
39
|
+
* by convention; the team commits `.squad/learnings.jsonl` along with the code so
|
|
40
|
+
* decisions are auditable in PR diffs.
|
|
41
|
+
*/
|
|
42
|
+
export const DEFAULT_LEARNING_PATH = ".squad/learnings.jsonl";
|
|
43
|
+
const cache = new Map();
|
|
44
|
+
/** Test-only: clear the per-process cache. Production code MUST NOT call this. */
|
|
45
|
+
export function __resetLearningStoreCacheForTests() {
|
|
46
|
+
cache.clear();
|
|
47
|
+
}
|
|
48
|
+
function resolveLearningFile(workspaceRoot, configuredPath) {
|
|
49
|
+
const rel = configuredPath ?? DEFAULT_LEARNING_PATH;
|
|
50
|
+
return path.resolve(workspaceRoot, rel);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Read all learnings from the JSONL file. Returns [] if the file does not exist
|
|
54
|
+
* (a fresh repo with no decisions recorded is the common case). Throws on
|
|
55
|
+
* parse failure of any individual line — callers may want to soft-fail, but
|
|
56
|
+
* silent corruption is worse than loud rejection.
|
|
57
|
+
*/
|
|
58
|
+
export async function readLearnings(workspaceRoot, options = {}) {
|
|
59
|
+
const filePath = resolveLearningFile(workspaceRoot, options.configuredPath);
|
|
60
|
+
const absRoot = path.resolve(workspaceRoot);
|
|
61
|
+
let stat;
|
|
62
|
+
try {
|
|
63
|
+
stat = await fs.stat(filePath);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// No file — first run, no learnings yet.
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
if (!stat.isFile()) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const cached = cache.get(absRoot);
|
|
73
|
+
if (cached &&
|
|
74
|
+
cached.filePath === filePath &&
|
|
75
|
+
cached.mtimeMs === stat.mtimeMs) {
|
|
76
|
+
return cached.entries;
|
|
77
|
+
}
|
|
78
|
+
let raw;
|
|
79
|
+
try {
|
|
80
|
+
raw = await fs.readFile(filePath, "utf8");
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
throw new SquadError("CONFIG_READ_FAILED", `failed to read learnings file ${filePath}: ${err.message}`, { source: filePath });
|
|
84
|
+
}
|
|
85
|
+
const lines = raw.split(/\r?\n/);
|
|
86
|
+
const entries = [];
|
|
87
|
+
let lineNo = 0;
|
|
88
|
+
for (const line of lines) {
|
|
89
|
+
lineNo++;
|
|
90
|
+
const trimmed = line.trim();
|
|
91
|
+
if (trimmed === "")
|
|
92
|
+
continue; // skip blank lines (trailing newline, spacing)
|
|
93
|
+
let parsed;
|
|
94
|
+
try {
|
|
95
|
+
parsed = JSON.parse(trimmed);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
throw new SquadError("INVALID_INPUT", `${filePath}:${lineNo}: invalid JSON: ${err.message}`, { source: filePath, line: lineNo });
|
|
99
|
+
}
|
|
100
|
+
const validated = learningEntrySchema.safeParse(parsed);
|
|
101
|
+
if (!validated.success) {
|
|
102
|
+
throw new SquadError("INVALID_INPUT", `${filePath}:${lineNo}: schema violation: ${validated.error.message}`, {
|
|
103
|
+
source: filePath,
|
|
104
|
+
line: lineNo,
|
|
105
|
+
issues: validated.error.issues.length,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
entries.push(validated.data);
|
|
109
|
+
}
|
|
110
|
+
cache.set(absRoot, { mtimeMs: stat.mtimeMs, filePath, entries });
|
|
111
|
+
return entries;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Append a new learning entry to the JSONL file. Creates the directory and
|
|
115
|
+
* file if needed. Atomic at the append level (single fs.appendFile call —
|
|
116
|
+
* Node serialises this on POSIX); concurrent appenders may interleave entries
|
|
117
|
+
* but never corrupt them line-wise.
|
|
118
|
+
*
|
|
119
|
+
* Stamps the timestamp here if the caller did not supply one — gives a single
|
|
120
|
+
* source of clock truth and prevents stale ts in CLI invocations.
|
|
121
|
+
*/
|
|
122
|
+
export async function appendLearning(workspaceRoot, entry, options = {}) {
|
|
123
|
+
const ts = entry.ts ?? new Date().toISOString();
|
|
124
|
+
const candidate = { ...entry, ts };
|
|
125
|
+
const validated = learningEntrySchema.safeParse(candidate);
|
|
126
|
+
if (!validated.success) {
|
|
127
|
+
throw new SquadError("INVALID_INPUT", `learning entry schema violation: ${validated.error.message}`, { issues: validated.error.issues.length });
|
|
128
|
+
}
|
|
129
|
+
const filePath = resolveLearningFile(workspaceRoot, options.configuredPath);
|
|
130
|
+
const dir = path.dirname(filePath);
|
|
131
|
+
await fs.mkdir(dir, { recursive: true });
|
|
132
|
+
// One JSON object per line, no pretty-print — keeps the file grep-friendly
|
|
133
|
+
// and minimises diff churn when entries get re-ordered (which they don't,
|
|
134
|
+
// but defensive).
|
|
135
|
+
const line = JSON.stringify(validated.data) + "\n";
|
|
136
|
+
await fs.appendFile(filePath, line, "utf8");
|
|
137
|
+
// Invalidate cache so next readLearnings reflects the append.
|
|
138
|
+
const absRoot = path.resolve(workspaceRoot);
|
|
139
|
+
cache.delete(absRoot);
|
|
140
|
+
logger.info("learning appended", {
|
|
141
|
+
details: {
|
|
142
|
+
file: filePath,
|
|
143
|
+
agent: validated.data.agent,
|
|
144
|
+
decision: validated.data.decision,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
return { filePath, entry: validated.data };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Filter helper: pick the most recent N entries, optionally narrowed by
|
|
151
|
+
* agent. Used by the formatter to inject a small, relevant slice into the
|
|
152
|
+
* agent / consolidator prompt.
|
|
153
|
+
*
|
|
154
|
+
* Sort: input is in append order (oldest first). We slice the tail. The
|
|
155
|
+
* filter happens BEFORE the slice — `recentForAgent('senior-dba', 50)`
|
|
156
|
+
* returns the last 50 DBA decisions, not the last 50 decisions overall
|
|
157
|
+
* filtered to DBA (which would often return zero on diverse repos).
|
|
158
|
+
*/
|
|
159
|
+
export function tailRecent(entries, limit, options = {}) {
|
|
160
|
+
let filtered = entries;
|
|
161
|
+
if (options.agent) {
|
|
162
|
+
filtered = filtered.filter((e) => e.agent === options.agent);
|
|
163
|
+
}
|
|
164
|
+
if (options.decision) {
|
|
165
|
+
filtered = filtered.filter((e) => e.decision === options.decision);
|
|
166
|
+
}
|
|
167
|
+
return filtered.slice(-limit);
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/learning/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentName } from
|
|
1
|
+
import { type AgentName } from "../config/ownership-matrix.js";
|
|
2
2
|
export declare const SHARED_FILES: string[];
|
|
3
3
|
/**
|
|
4
4
|
* Returns the configured override directory and whether it was set explicitly
|
|
@@ -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.
|