@gempack/squad-mcp 0.10.0 → 0.11.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 +1 -1
- package/.claude-plugin/plugin.json +2 -2
- package/CHANGELOG.md +89 -0
- package/README.md +34 -8
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/learning/format.js +0 -0
- package/dist/learning/format.js.map +1 -1
- package/dist/learning/normalize.d.ts +28 -0
- package/dist/learning/normalize.js +54 -0
- package/dist/learning/normalize.js.map +1 -0
- package/dist/learning/store.d.ts +33 -3
- package/dist/learning/store.js +39 -3
- package/dist/learning/store.js.map +1 -1
- package/dist/runs/aggregate.js +6 -9
- package/dist/runs/aggregate.js.map +1 -1
- package/dist/runs/store.d.ts +14 -0
- package/dist/runs/store.js +54 -2
- package/dist/runs/store.js.map +1 -1
- package/dist/tools/list-runs.js +2 -2
- package/dist/tools/list-runs.js.map +1 -1
- package/dist/tools/prune-learnings.d.ts +84 -0
- package/dist/tools/prune-learnings.js +256 -0
- package/dist/tools/prune-learnings.js.map +1 -0
- package/dist/tools/read-learnings.d.ts +37 -1
- package/dist/tools/read-learnings.js +102 -10
- package/dist/tools/read-learnings.js.map +1 -1
- package/dist/tools/record-learning.d.ts +0 -0
- package/dist/tools/record-learning.js +0 -0
- package/dist/tools/record-learning.js.map +1 -1
- package/dist/tools/record-run.js +21 -15
- package/dist/tools/record-run.js.map +1 -1
- package/dist/tools/registry.js +13 -1
- package/dist/tools/registry.js.map +1 -1
- package/dist/util/atomic-rewrite-jsonl.d.ts +36 -0
- package/dist/util/atomic-rewrite-jsonl.js +95 -0
- package/dist/util/atomic-rewrite-jsonl.js.map +1 -0
- package/dist/util/path-safety.d.ts +36 -0
- package/dist/util/path-safety.js +76 -0
- package/dist/util/path-safety.js.map +1 -1
- package/package.json +1 -1
- package/skills/brainstorm/SKILL.md +70 -7
- package/skills/question/SKILL.md +73 -1
- package/skills/squad/SKILL.md +66 -74
- package/skills/stats/SKILL.md +1 -0
package/dist/runs/store.js
CHANGED
|
@@ -79,7 +79,43 @@ export function decodeSeverityScore(n) {
|
|
|
79
79
|
}
|
|
80
80
|
/** Public re-export so callers can build records without re-implementing the encoding. */
|
|
81
81
|
export { severityScore };
|
|
82
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Strip C0 (`\x00`-`\x1F` except `\t`), C1 (`\x7F`-`\x9F`), and ESC (`\x1B`)
|
|
84
|
+
* from a string before it lands on disk. This is the WRITER-side mirror of
|
|
85
|
+
* the renderer's `aggregate.stripControlChars` (security #5).
|
|
86
|
+
*
|
|
87
|
+
* Defense in depth: render-time sanitisation protects users running
|
|
88
|
+
* `/squad:stats`; writer-side sanitisation also protects users running
|
|
89
|
+
* `cat .squad/runs.jsonl` or any other tool that bypasses the aggregator.
|
|
90
|
+
* The regex is intentionally duplicated (3 lines, no runtime cost) rather
|
|
91
|
+
* than importing from `aggregate.ts` because that would invert the natural
|
|
92
|
+
* dep direction (store is foundational; aggregate consumes store).
|
|
93
|
+
*/
|
|
94
|
+
function stripWriterControlChars(s) {
|
|
95
|
+
return s.replace(/[\x00-\x08\x0A-\x1F\x7F-\x9F]/g, "");
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Canonical tuple of accepted journal invocations. Single source of truth.
|
|
99
|
+
*
|
|
100
|
+
* Why a tuple, not just a Zod enum: the same set is consumed by FIVE call
|
|
101
|
+
* sites — this store's `InvocationEnum`, the tool boundary at
|
|
102
|
+
* `src/tools/record-run.ts`, the filter schema at `src/tools/list-runs.ts`,
|
|
103
|
+
* the Record literal in the aggregate output type, and the `invocation_counts`
|
|
104
|
+
* initialiser in `src/runs/aggregate.ts`. Exporting one tuple makes "add a
|
|
105
|
+
* new invocation" a single-line change instead of five-sites-must-stay-in-
|
|
106
|
+
* sync. Pattern parallels `AGENT_NAMES_TUPLE` in `src/config/ownership-matrix.ts`.
|
|
107
|
+
*
|
|
108
|
+
* `as const` (readonly tuple) is what Zod's `z.enum` requires.
|
|
109
|
+
*/
|
|
110
|
+
export const INVOCATION_VALUES = [
|
|
111
|
+
"implement",
|
|
112
|
+
"review",
|
|
113
|
+
"task",
|
|
114
|
+
"question",
|
|
115
|
+
"brainstorm",
|
|
116
|
+
"debug",
|
|
117
|
+
];
|
|
118
|
+
const InvocationEnum = z.enum(INVOCATION_VALUES);
|
|
83
119
|
const ModeEnum = z.enum(["quick", "normal", "deep"]);
|
|
84
120
|
const ModeSourceEnum = z.enum(["user", "auto"]);
|
|
85
121
|
const StatusEnum = z.enum(["in_flight", "completed", "aborted"]);
|
|
@@ -313,7 +349,23 @@ export async function appendRun(workspaceRoot, record, options = {}) {
|
|
|
313
349
|
if (!validated.success) {
|
|
314
350
|
throw new SquadError("INVALID_INPUT", `run record schema violation: ${validated.error.message}`, { issues: validated.error.issues.length });
|
|
315
351
|
}
|
|
316
|
-
|
|
352
|
+
// Defense in depth: strip control chars from `mode_warning.message` at the
|
|
353
|
+
// writer too. The aggregator's `stripControlChars` already runs at render
|
|
354
|
+
// (security #5 in v0.9.0), but direct file inspection (`cat`, `less`) sees
|
|
355
|
+
// raw bytes. Sanitising here keeps the recorded data terminal-safe for any
|
|
356
|
+
// future viewer that bypasses the aggregator. We strip only this one field
|
|
357
|
+
// because it's the documented free-form leak surface — other fields are
|
|
358
|
+
// schema-bounded to safer shapes (enums, ISO strings, numbers, sha refs).
|
|
359
|
+
const sanitized = validated.data.mode_warning != null
|
|
360
|
+
? {
|
|
361
|
+
...validated.data,
|
|
362
|
+
mode_warning: {
|
|
363
|
+
...validated.data.mode_warning,
|
|
364
|
+
message: stripWriterControlChars(validated.data.mode_warning.message),
|
|
365
|
+
},
|
|
366
|
+
}
|
|
367
|
+
: validated.data;
|
|
368
|
+
const line = JSON.stringify(sanitized) + "\n";
|
|
317
369
|
const byteLen = Buffer.byteLength(line, "utf8");
|
|
318
370
|
if (byteLen > MAX_RECORD_BYTES) {
|
|
319
371
|
throw new SquadError("RECORD_TOO_LARGE", `run record exceeds MAX_RECORD_BYTES (${byteLen} > ${MAX_RECORD_BYTES}); ` +
|
package/dist/runs/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/runs/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CAAC;AAErD;;;;;;;;GAQG;AACH,SAAS,aAAa,CAAC,MAKtB;IACC,OAAO,MAAM,CAAC,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;AAC5F,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,mBAAmB,CAAC,CAAS;IAM3C,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;QACnC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC;QACjC,UAAU,EAAE,CAAC,GAAG,EAAE;KACnB,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/runs/store.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/list-runs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { SafeString } from "./_shared/schemas.js";
|
|
3
3
|
import { AGENT_NAMES_TUPLE } from "../config/ownership-matrix.js";
|
|
4
|
-
import { readRuns } from "../runs/store.js";
|
|
4
|
+
import { readRuns, INVOCATION_VALUES } from "../runs/store.js";
|
|
5
5
|
import { foldById, applyFilters, aggregateOutcomes, aggregateHealth, trendByDay, getEstTokens, } from "../runs/aggregate.js";
|
|
6
6
|
/**
|
|
7
7
|
* Read tool: load runs from `.squad/runs.jsonl`, fold the two-phase
|
|
@@ -15,7 +15,7 @@ import { foldById, applyFilters, aggregateOutcomes, aggregateHealth, trendByDay,
|
|
|
15
15
|
*
|
|
16
16
|
* No writes here. The single-writer contract belongs to `record_run`.
|
|
17
17
|
*/
|
|
18
|
-
const InvocationEnum = z.enum(
|
|
18
|
+
const InvocationEnum = z.enum(INVOCATION_VALUES);
|
|
19
19
|
const ModeEnum = z.enum(["quick", "normal", "deep"]);
|
|
20
20
|
const VerdictEnum = z.enum(["APPROVED", "CHANGES_REQUIRED", "REJECTED"]);
|
|
21
21
|
const WorkTypeEnum = z.enum([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-runs.js","sourceRoot":"","sources":["../../src/tools/list-runs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAkB,MAAM,+BAA+B,CAAC;AAClF,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"list-runs.js","sourceRoot":"","sources":["../../src/tools/list-runs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ToolDef } from "./registry.js";
|
|
3
|
+
/**
|
|
4
|
+
* Lifecycle maintenance for `.squad/learnings.jsonl` (v0.11.0+).
|
|
5
|
+
*
|
|
6
|
+
* Two passes, both running inside the same atomic-rewrite (lock + rename-
|
|
7
|
+
* rename) under `withFileLock`:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Age cutoff** — when `max_age_days > 0`, entries whose `ts` is older
|
|
10
|
+
* than `now - max_age_days` are marked `archived: true`. Archived
|
|
11
|
+
* entries stay on disk for forensics; they are suppressed from the
|
|
12
|
+
* default `read_learnings` read path (use `include_archived: true` to
|
|
13
|
+
* surface them).
|
|
14
|
+
*
|
|
15
|
+
* 2. **Promotion** — entries are grouped by `normalizeFindingTitle(finding)`.
|
|
16
|
+
* For each group, the number of `decision: "accept"` entries that are
|
|
17
|
+
* NOT already archived is counted. When the count is ≥ `min_recurrence`,
|
|
18
|
+
* the most-recent accepted entry in the group is marked `promoted: true`
|
|
19
|
+
* (the rest stay un-promoted to avoid noisy duplicates in the rendered
|
|
20
|
+
* block). Promoted entries surface FIRST in `read_learnings` output
|
|
21
|
+
* regardless of scope match — they represent crystallised team policy.
|
|
22
|
+
*
|
|
23
|
+
* **Never auto-runs.** The default `max_age_days` is `0` (= disabled) so
|
|
24
|
+
* invoking the tool with no input is a safe no-op. Users who want regular
|
|
25
|
+
* housekeeping run it themselves (or wire a cron / git pre-commit hook).
|
|
26
|
+
*
|
|
27
|
+
* **Auditability**: pruning produces a diff on the on-disk journal. Repos
|
|
28
|
+
* that commit `.squad/learnings.jsonl` should expect a non-trivial diff
|
|
29
|
+
* after a non-no-op run. The `.prev` snapshot from the atomic rewrite is
|
|
30
|
+
* the rollback point.
|
|
31
|
+
*
|
|
32
|
+
* **Race safety**: the entire read-modify-write happens under the file
|
|
33
|
+
* lock used by `appendLearning`. Concurrent appenders block until the
|
|
34
|
+
* prune finishes; concurrent readers (no lock by design) see either the
|
|
35
|
+
* pre-prune or post-prune file in full because rename-into-place is
|
|
36
|
+
* atomic on POSIX same-filesystem renames.
|
|
37
|
+
*/
|
|
38
|
+
declare const schema: z.ZodObject<{
|
|
39
|
+
workspace_root: z.ZodString;
|
|
40
|
+
/**
|
|
41
|
+
* Age cutoff in days. Entries older than `now - max_age_days` are marked
|
|
42
|
+
* archived. Default `0` (= disabled — explicit user opt-in required).
|
|
43
|
+
* The plan v2 default departs from the plan v1 default of 180 to avoid
|
|
44
|
+
* surprising diff churn on repos that commit the journal.
|
|
45
|
+
*/
|
|
46
|
+
max_age_days: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
47
|
+
/**
|
|
48
|
+
* Promotion threshold. A finding-title group with ≥ this many accept
|
|
49
|
+
* decisions (across all agents, after archival) earns a `promoted: true`
|
|
50
|
+
* flag on its most-recent entry. Default 3 (1× = anecdote; 2× = pattern;
|
|
51
|
+
* 3× = team policy). Set 0 to disable promotion entirely. `1` is rejected
|
|
52
|
+
* because it would mark every singleton accept as promoted — defeating the
|
|
53
|
+
* "this is team policy" signal (developer cycle-2 Major M5).
|
|
54
|
+
*/
|
|
55
|
+
min_recurrence: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodNumber>>, number, number | undefined>;
|
|
56
|
+
/**
|
|
57
|
+
* When true, compute counts without writing. Useful for "what would this
|
|
58
|
+
* do?" inspection before running the destructive pass.
|
|
59
|
+
*/
|
|
60
|
+
dry_run: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
61
|
+
}, "strip", z.ZodTypeAny, {
|
|
62
|
+
workspace_root: string;
|
|
63
|
+
max_age_days: number;
|
|
64
|
+
min_recurrence: number;
|
|
65
|
+
dry_run: boolean;
|
|
66
|
+
}, {
|
|
67
|
+
workspace_root: string;
|
|
68
|
+
max_age_days?: number | undefined;
|
|
69
|
+
min_recurrence?: number | undefined;
|
|
70
|
+
dry_run?: boolean | undefined;
|
|
71
|
+
}>;
|
|
72
|
+
type Input = z.infer<typeof schema>;
|
|
73
|
+
export interface PruneLearningsOutput {
|
|
74
|
+
ok: true;
|
|
75
|
+
file: string;
|
|
76
|
+
total: number;
|
|
77
|
+
archived_count: number;
|
|
78
|
+
promoted_count: number;
|
|
79
|
+
unchanged_count: number;
|
|
80
|
+
dry_run: boolean;
|
|
81
|
+
}
|
|
82
|
+
export declare function pruneLearningsTool(input: Input): Promise<PruneLearningsOutput>;
|
|
83
|
+
export declare const pruneLearningsToolDef: ToolDef<typeof schema>;
|
|
84
|
+
export {};
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readLearnings, DEFAULT_LEARNING_PATH } from "../learning/store.js";
|
|
4
|
+
import { normalizeFindingTitle } from "../learning/normalize.js";
|
|
5
|
+
import { atomicRewriteJsonl } from "../util/atomic-rewrite-jsonl.js";
|
|
6
|
+
import { readSquadYaml } from "../config/squad-yaml.js";
|
|
7
|
+
import { resolveSafePath, createSafePathContext } from "../util/path-safety.js";
|
|
8
|
+
import { SquadError } from "../errors.js";
|
|
9
|
+
import { ensureRelativeInsideRoot } from "../util/path-safety.js";
|
|
10
|
+
import { logger } from "../observability/logger.js";
|
|
11
|
+
/**
|
|
12
|
+
* Lifecycle maintenance for `.squad/learnings.jsonl` (v0.11.0+).
|
|
13
|
+
*
|
|
14
|
+
* Two passes, both running inside the same atomic-rewrite (lock + rename-
|
|
15
|
+
* rename) under `withFileLock`:
|
|
16
|
+
*
|
|
17
|
+
* 1. **Age cutoff** — when `max_age_days > 0`, entries whose `ts` is older
|
|
18
|
+
* than `now - max_age_days` are marked `archived: true`. Archived
|
|
19
|
+
* entries stay on disk for forensics; they are suppressed from the
|
|
20
|
+
* default `read_learnings` read path (use `include_archived: true` to
|
|
21
|
+
* surface them).
|
|
22
|
+
*
|
|
23
|
+
* 2. **Promotion** — entries are grouped by `normalizeFindingTitle(finding)`.
|
|
24
|
+
* For each group, the number of `decision: "accept"` entries that are
|
|
25
|
+
* NOT already archived is counted. When the count is ≥ `min_recurrence`,
|
|
26
|
+
* the most-recent accepted entry in the group is marked `promoted: true`
|
|
27
|
+
* (the rest stay un-promoted to avoid noisy duplicates in the rendered
|
|
28
|
+
* block). Promoted entries surface FIRST in `read_learnings` output
|
|
29
|
+
* regardless of scope match — they represent crystallised team policy.
|
|
30
|
+
*
|
|
31
|
+
* **Never auto-runs.** The default `max_age_days` is `0` (= disabled) so
|
|
32
|
+
* invoking the tool with no input is a safe no-op. Users who want regular
|
|
33
|
+
* housekeeping run it themselves (or wire a cron / git pre-commit hook).
|
|
34
|
+
*
|
|
35
|
+
* **Auditability**: pruning produces a diff on the on-disk journal. Repos
|
|
36
|
+
* that commit `.squad/learnings.jsonl` should expect a non-trivial diff
|
|
37
|
+
* after a non-no-op run. The `.prev` snapshot from the atomic rewrite is
|
|
38
|
+
* the rollback point.
|
|
39
|
+
*
|
|
40
|
+
* **Race safety**: the entire read-modify-write happens under the file
|
|
41
|
+
* lock used by `appendLearning`. Concurrent appenders block until the
|
|
42
|
+
* prune finishes; concurrent readers (no lock by design) see either the
|
|
43
|
+
* pre-prune or post-prune file in full because rename-into-place is
|
|
44
|
+
* atomic on POSIX same-filesystem renames.
|
|
45
|
+
*/
|
|
46
|
+
const schema = z.object({
|
|
47
|
+
workspace_root: z.string().min(1).max(4096),
|
|
48
|
+
/**
|
|
49
|
+
* Age cutoff in days. Entries older than `now - max_age_days` are marked
|
|
50
|
+
* archived. Default `0` (= disabled — explicit user opt-in required).
|
|
51
|
+
* The plan v2 default departs from the plan v1 default of 180 to avoid
|
|
52
|
+
* surprising diff churn on repos that commit the journal.
|
|
53
|
+
*/
|
|
54
|
+
max_age_days: z.number().int().nonnegative().max(36500).optional().default(0),
|
|
55
|
+
/**
|
|
56
|
+
* Promotion threshold. A finding-title group with ≥ this many accept
|
|
57
|
+
* decisions (across all agents, after archival) earns a `promoted: true`
|
|
58
|
+
* flag on its most-recent entry. Default 3 (1× = anecdote; 2× = pattern;
|
|
59
|
+
* 3× = team policy). Set 0 to disable promotion entirely. `1` is rejected
|
|
60
|
+
* because it would mark every singleton accept as promoted — defeating the
|
|
61
|
+
* "this is team policy" signal (developer cycle-2 Major M5).
|
|
62
|
+
*/
|
|
63
|
+
min_recurrence: z
|
|
64
|
+
.number()
|
|
65
|
+
.int()
|
|
66
|
+
.nonnegative()
|
|
67
|
+
.max(1000)
|
|
68
|
+
.optional()
|
|
69
|
+
.default(3)
|
|
70
|
+
.refine((n) => n !== 1, "min_recurrence must be 0 (disable promotion) or >= 2 (a singleton accept is not recurrence)"),
|
|
71
|
+
/**
|
|
72
|
+
* When true, compute counts without writing. Useful for "what would this
|
|
73
|
+
* do?" inspection before running the destructive pass.
|
|
74
|
+
*/
|
|
75
|
+
dry_run: z.boolean().optional().default(false),
|
|
76
|
+
});
|
|
77
|
+
function resolveLearningPath(safeRoot, configuredPath) {
|
|
78
|
+
if (configuredPath !== undefined) {
|
|
79
|
+
ensureRelativeInsideRoot(safeRoot, configuredPath, "learnings.path");
|
|
80
|
+
return path.resolve(safeRoot, configuredPath);
|
|
81
|
+
}
|
|
82
|
+
return path.resolve(safeRoot, DEFAULT_LEARNING_PATH);
|
|
83
|
+
}
|
|
84
|
+
export async function pruneLearningsTool(input) {
|
|
85
|
+
// v0.11.0 cycle-2 (developer Major M5): defense-in-depth guard against
|
|
86
|
+
// `min_recurrence: 1`. The schema's `.refine` only fires when the call
|
|
87
|
+
// goes through the dispatch registry; direct programmatic callers (and
|
|
88
|
+
// the test suite) bypass it. A runtime check inside the handler closes
|
|
89
|
+
// that gap so the contract holds regardless of entry point.
|
|
90
|
+
if (input.min_recurrence === 1) {
|
|
91
|
+
throw new SquadError("INVALID_INPUT", "min_recurrence must be 0 (disable promotion) or >= 2 (a singleton accept is not recurrence — `1` would promote every one-off finding)", { received: 1 });
|
|
92
|
+
}
|
|
93
|
+
const ctx = createSafePathContext();
|
|
94
|
+
const safeRoot = await resolveSafePath(input.workspace_root, ".", ctx);
|
|
95
|
+
const config = await readSquadYaml(safeRoot);
|
|
96
|
+
// If learnings is disabled at config level, treat as no-op rather than
|
|
97
|
+
// implicitly enabling it via the prune tool.
|
|
98
|
+
if (!config.learnings.enabled) {
|
|
99
|
+
const filePath = resolveLearningPath(safeRoot, config.learnings.path);
|
|
100
|
+
return {
|
|
101
|
+
ok: true,
|
|
102
|
+
file: filePath,
|
|
103
|
+
total: 0,
|
|
104
|
+
archived_count: 0,
|
|
105
|
+
promoted_count: 0,
|
|
106
|
+
unchanged_count: 0,
|
|
107
|
+
dry_run: input.dry_run,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const configuredPath = config.learnings.path;
|
|
111
|
+
const filePath = resolveLearningPath(safeRoot, configuredPath);
|
|
112
|
+
const entries = await readLearnings(safeRoot, {
|
|
113
|
+
...(configuredPath !== undefined ? { configuredPath } : {}),
|
|
114
|
+
});
|
|
115
|
+
if (entries.length === 0) {
|
|
116
|
+
return {
|
|
117
|
+
ok: true,
|
|
118
|
+
file: filePath,
|
|
119
|
+
total: 0,
|
|
120
|
+
archived_count: 0,
|
|
121
|
+
promoted_count: 0,
|
|
122
|
+
unchanged_count: 0,
|
|
123
|
+
dry_run: input.dry_run,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// Pass 1: age cutoff
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// v0.11.0 cycle-2 (developer Major M4): track changed indices in a Set
|
|
130
|
+
// instead of computing `unchangedCount = total - (archived + promoted)`
|
|
131
|
+
// arithmetically. The arithmetic was structurally fragile — it relied on
|
|
132
|
+
// three invariants holding simultaneously (Pass 2 skips archived; Pass 2
|
|
133
|
+
// skips already-promoted; Pass 1 doesn't read promoted). A future drift
|
|
134
|
+
// in any of those would silently break the count. The Set approach is
|
|
135
|
+
// robust under refactoring: an index in the Set means "this row mutated
|
|
136
|
+
// this pass", regardless of how many fields changed.
|
|
137
|
+
const changedIndices = new Set();
|
|
138
|
+
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
139
|
+
const nowMs = Date.now();
|
|
140
|
+
const cutoffMs = input.max_age_days > 0 ? nowMs - input.max_age_days * ONE_DAY_MS : -Infinity;
|
|
141
|
+
let archivedCount = 0;
|
|
142
|
+
const stage1 = entries.map((e, idx) => {
|
|
143
|
+
if (e.archived === true)
|
|
144
|
+
return e;
|
|
145
|
+
const tsMs = Date.parse(e.ts);
|
|
146
|
+
if (!Number.isFinite(tsMs))
|
|
147
|
+
return e;
|
|
148
|
+
if (tsMs < cutoffMs) {
|
|
149
|
+
archivedCount++;
|
|
150
|
+
changedIndices.add(idx);
|
|
151
|
+
return { ...e, archived: true };
|
|
152
|
+
}
|
|
153
|
+
return e;
|
|
154
|
+
});
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Pass 2: promotion by normalised-title recurrence
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
let promotedCount = 0;
|
|
159
|
+
let stage2 = stage1;
|
|
160
|
+
if (input.min_recurrence > 0) {
|
|
161
|
+
// Group indices by normalised title. We carry indices (not entries) so
|
|
162
|
+
// we can mutate the most-recent member of each qualifying group.
|
|
163
|
+
const groups = new Map();
|
|
164
|
+
stage1.forEach((e, idx) => {
|
|
165
|
+
if (e.archived === true)
|
|
166
|
+
return;
|
|
167
|
+
if (e.decision !== "accept")
|
|
168
|
+
return;
|
|
169
|
+
const key = normalizeFindingTitle(e.finding);
|
|
170
|
+
if (key.length === 0)
|
|
171
|
+
return;
|
|
172
|
+
const acc = groups.get(key) ?? [];
|
|
173
|
+
acc.push(idx);
|
|
174
|
+
groups.set(key, acc);
|
|
175
|
+
});
|
|
176
|
+
const promotedFlags = new Set();
|
|
177
|
+
for (const [, indices] of groups) {
|
|
178
|
+
if (indices.length < input.min_recurrence)
|
|
179
|
+
continue;
|
|
180
|
+
// Most-recent member by ts (fall back to last in append-order if ts
|
|
181
|
+
// doesn't parse). We compare ms; on equality the later index wins.
|
|
182
|
+
let bestIdx = indices[0];
|
|
183
|
+
let bestMs = Date.parse(stage1[bestIdx].ts);
|
|
184
|
+
for (let i = 1; i < indices.length; i++) {
|
|
185
|
+
const idx = indices[i];
|
|
186
|
+
const ms = Date.parse(stage1[idx].ts);
|
|
187
|
+
if (!Number.isFinite(ms))
|
|
188
|
+
continue;
|
|
189
|
+
if (!Number.isFinite(bestMs) || ms >= bestMs) {
|
|
190
|
+
bestIdx = idx;
|
|
191
|
+
bestMs = ms;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Only count a promotion if the chosen entry wasn't already promoted.
|
|
195
|
+
// Idempotent: re-running prune doesn't keep incrementing promoted_count
|
|
196
|
+
// for the same entries.
|
|
197
|
+
if (stage1[bestIdx].promoted !== true) {
|
|
198
|
+
promotedFlags.add(bestIdx);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (promotedFlags.size > 0) {
|
|
202
|
+
stage2 = stage1.map((e, idx) => (promotedFlags.has(idx) ? { ...e, promoted: true } : e));
|
|
203
|
+
promotedCount = promotedFlags.size;
|
|
204
|
+
// Add promoted indices to the changed-indices Set. An entry both
|
|
205
|
+
// archived (Pass 1) and promoted (Pass 2) would only count ONCE in
|
|
206
|
+
// the Set, which is the correct invariant — it's still one row that
|
|
207
|
+
// changed this pass.
|
|
208
|
+
for (const idx of promotedFlags)
|
|
209
|
+
changedIndices.add(idx);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// Write (or skip in dry-run)
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
// unchangedCount is derived from the Set of touched indices (cycle-2 M4
|
|
216
|
+
// robustness fix). archivedCount and promotedCount are kept as separate
|
|
217
|
+
// observability counters in the return shape; they double-count when an
|
|
218
|
+
// entry is both archived AND promoted in the same run, which can happen
|
|
219
|
+
// across multiple prune cycles (today's Pass 2 skips archived entries
|
|
220
|
+
// from THIS pass, but a previously-promoted entry can age out and get
|
|
221
|
+
// archived later — those rows will appear in BOTH counters historically).
|
|
222
|
+
const changed = changedIndices.size;
|
|
223
|
+
const unchangedCount = entries.length - changed;
|
|
224
|
+
if (!input.dry_run && changed > 0) {
|
|
225
|
+
await atomicRewriteJsonl(filePath, stage2);
|
|
226
|
+
logger.info("prune_learnings: rewritten", {
|
|
227
|
+
details: {
|
|
228
|
+
file: filePath,
|
|
229
|
+
total: entries.length,
|
|
230
|
+
archived_count: archivedCount,
|
|
231
|
+
promoted_count: promotedCount,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
ok: true,
|
|
237
|
+
file: filePath,
|
|
238
|
+
total: entries.length,
|
|
239
|
+
archived_count: archivedCount,
|
|
240
|
+
promoted_count: promotedCount,
|
|
241
|
+
unchanged_count: unchangedCount,
|
|
242
|
+
dry_run: input.dry_run,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
export const pruneLearningsToolDef = {
|
|
246
|
+
name: "prune_learnings",
|
|
247
|
+
description: "Lifecycle maintenance for `.squad/learnings.jsonl` (v0.11.0+). Two passes: (1) entries older than " +
|
|
248
|
+
"`max_age_days` are marked `archived: true` and hidden from default `read_learnings`; (2) entries " +
|
|
249
|
+
"with ≥ `min_recurrence` accept decisions on the same normalised finding title get `promoted: true` " +
|
|
250
|
+
"on the most-recent matching entry — promoted entries surface first in advisory prompts regardless " +
|
|
251
|
+
"of scope match. Atomic rewrite under file lock. Never auto-runs (`max_age_days` defaults to 0). " +
|
|
252
|
+
"Use `dry_run: true` to inspect counts without mutating.",
|
|
253
|
+
schema,
|
|
254
|
+
handler: pruneLearningsTool,
|
|
255
|
+
};
|
|
256
|
+
//# sourceMappingURL=prune-learnings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune-learnings.js","sourceRoot":"","sources":["../../src/tools/prune-learnings.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,12 @@ import type { ToolDef } from "./registry.js";
|
|
|
3
3
|
import { type LearningEntry } from "../learning/store.js";
|
|
4
4
|
declare const schema: z.ZodObject<{
|
|
5
5
|
workspace_root: z.ZodString;
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Cap rendered/returned entries. Default 50. `0` is a valid sentinel
|
|
8
|
+
* meaning "summary only, no entries" (used by `/squad:stats` to fetch
|
|
9
|
+
* counts without paging the file). Range widened from `positive()` to
|
|
10
|
+
* `nonnegative()` in v0.11.0 to accommodate that.
|
|
11
|
+
*/
|
|
7
12
|
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
8
13
|
/** When set, restrict to learnings for this agent. */
|
|
9
14
|
agent: z.ZodOptional<z.ZodEnum<[import("../config/ownership-matrix.js").AgentName, ...import("../config/ownership-matrix.js").AgentName[]]>>;
|
|
@@ -20,10 +25,27 @@ declare const schema: z.ZodObject<{
|
|
|
20
25
|
* array. Skip the render when the caller will format their own.
|
|
21
26
|
*/
|
|
22
27
|
include_rendered: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
28
|
+
/**
|
|
29
|
+
* v0.11.0+ : when true, include entries with `archived: true` in the
|
|
30
|
+
* result. Default false — archived entries are kept on disk for forensics
|
|
31
|
+
* but suppressed from the active read path. Set true for debug / audit /
|
|
32
|
+
* `/squad:stats` summary panels that need the total count.
|
|
33
|
+
*/
|
|
34
|
+
include_archived: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
35
|
+
/**
|
|
36
|
+
* v0.11.0+ : when true, include a `summary` object on the response with
|
|
37
|
+
* `{total, active, archived, promoted}` counts (computed over the full
|
|
38
|
+
* file, ignoring agent / decision / scope filters but respecting
|
|
39
|
+
* include_archived semantics). Used by `/squad:stats` to surface the
|
|
40
|
+
* journal health line.
|
|
41
|
+
*/
|
|
42
|
+
include_summary: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
23
43
|
}, "strip", z.ZodTypeAny, {
|
|
24
44
|
workspace_root: string;
|
|
25
45
|
limit: number;
|
|
26
46
|
include_rendered: boolean;
|
|
47
|
+
include_archived: boolean;
|
|
48
|
+
include_summary: boolean;
|
|
27
49
|
agent?: import("../config/ownership-matrix.js").AgentName | undefined;
|
|
28
50
|
decision?: "accept" | "reject" | undefined;
|
|
29
51
|
changed_files?: string[] | undefined;
|
|
@@ -34,13 +56,27 @@ declare const schema: z.ZodObject<{
|
|
|
34
56
|
limit?: number | undefined;
|
|
35
57
|
changed_files?: string[] | undefined;
|
|
36
58
|
include_rendered?: boolean | undefined;
|
|
59
|
+
include_archived?: boolean | undefined;
|
|
60
|
+
include_summary?: boolean | undefined;
|
|
37
61
|
}>;
|
|
38
62
|
type Input = z.infer<typeof schema>;
|
|
63
|
+
export interface LearningsSummary {
|
|
64
|
+
/** Total rows in the journal, including archived. */
|
|
65
|
+
total: number;
|
|
66
|
+
/** Rows visible to the default read path (archived=false). */
|
|
67
|
+
active: number;
|
|
68
|
+
/** Rows with `archived: true`. */
|
|
69
|
+
archived: number;
|
|
70
|
+
/** Rows with `promoted: true`. */
|
|
71
|
+
promoted: number;
|
|
72
|
+
}
|
|
39
73
|
export interface ReadLearningsOutput {
|
|
40
74
|
entries: LearningEntry[];
|
|
41
75
|
total_in_store: number;
|
|
42
76
|
rendered: string;
|
|
43
77
|
source: string | null;
|
|
78
|
+
/** Present only when input.include_summary === true. */
|
|
79
|
+
summary?: LearningsSummary;
|
|
44
80
|
}
|
|
45
81
|
/**
|
|
46
82
|
* Read recent learnings from `.squad/learnings.jsonl` (path overridable via
|