@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
|
@@ -6,8 +6,13 @@ import { resolveSafePath, createSafePathContext } from "../util/path-safety.js";
|
|
|
6
6
|
import { AGENT_NAMES_TUPLE } from "../config/ownership-matrix.js";
|
|
7
7
|
const schema = z.object({
|
|
8
8
|
workspace_root: z.string().min(1).max(4096),
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Cap rendered/returned entries. Default 50. `0` is a valid sentinel
|
|
11
|
+
* meaning "summary only, no entries" (used by `/squad:stats` to fetch
|
|
12
|
+
* counts without paging the file). Range widened from `positive()` to
|
|
13
|
+
* `nonnegative()` in v0.11.0 to accommodate that.
|
|
14
|
+
*/
|
|
15
|
+
limit: z.number().int().nonnegative().max(200).optional().default(50),
|
|
11
16
|
/** When set, restrict to learnings for this agent. */
|
|
12
17
|
agent: z.enum(AGENT_NAMES_TUPLE).optional(),
|
|
13
18
|
/** When set, restrict to accepts or rejects. Default both. */
|
|
@@ -23,6 +28,21 @@ const schema = z.object({
|
|
|
23
28
|
* array. Skip the render when the caller will format their own.
|
|
24
29
|
*/
|
|
25
30
|
include_rendered: z.boolean().optional().default(true),
|
|
31
|
+
/**
|
|
32
|
+
* v0.11.0+ : when true, include entries with `archived: true` in the
|
|
33
|
+
* result. Default false — archived entries are kept on disk for forensics
|
|
34
|
+
* but suppressed from the active read path. Set true for debug / audit /
|
|
35
|
+
* `/squad:stats` summary panels that need the total count.
|
|
36
|
+
*/
|
|
37
|
+
include_archived: z.boolean().optional().default(false),
|
|
38
|
+
/**
|
|
39
|
+
* v0.11.0+ : when true, include a `summary` object on the response with
|
|
40
|
+
* `{total, active, archived, promoted}` counts (computed over the full
|
|
41
|
+
* file, ignoring agent / decision / scope filters but respecting
|
|
42
|
+
* include_archived semantics). Used by `/squad:stats` to surface the
|
|
43
|
+
* journal health line.
|
|
44
|
+
*/
|
|
45
|
+
include_summary: z.boolean().optional().default(false),
|
|
26
46
|
});
|
|
27
47
|
/**
|
|
28
48
|
* Read recent learnings from `.squad/learnings.jsonl` (path overridable via
|
|
@@ -37,26 +57,98 @@ export async function readLearningsTool(input) {
|
|
|
37
57
|
// Honor the master switch — if learnings disabled, return empty without
|
|
38
58
|
// touching the filesystem (the user explicitly turned it off).
|
|
39
59
|
if (!config.learnings.enabled) {
|
|
40
|
-
|
|
60
|
+
const baseOut = {
|
|
61
|
+
entries: [],
|
|
62
|
+
total_in_store: 0,
|
|
63
|
+
rendered: "",
|
|
64
|
+
source: null,
|
|
65
|
+
};
|
|
66
|
+
return input.include_summary
|
|
67
|
+
? { ...baseOut, summary: { total: 0, active: 0, archived: 0, promoted: 0 } }
|
|
68
|
+
: baseOut;
|
|
41
69
|
}
|
|
42
70
|
const configuredPath = config.learnings.path;
|
|
43
71
|
const allEntries = await readLearnings(safeRoot, { configuredPath });
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
72
|
+
// v0.11.0: compute summary over the FULL file before any filter is applied.
|
|
73
|
+
// Counts respect file-level state, not query-level filters.
|
|
74
|
+
const summary = input.include_summary
|
|
75
|
+
? {
|
|
76
|
+
total: allEntries.length,
|
|
77
|
+
active: allEntries.filter((e) => !e.archived).length,
|
|
78
|
+
archived: allEntries.filter((e) => e.archived === true).length,
|
|
79
|
+
promoted: allEntries.filter((e) => e.promoted === true).length,
|
|
80
|
+
}
|
|
81
|
+
: undefined;
|
|
82
|
+
// v0.11.0: default read suppresses archived entries. include_archived: true
|
|
83
|
+
// opts back in (debug / audit / stats panel surfacing).
|
|
84
|
+
const visible = input.include_archived
|
|
85
|
+
? allEntries
|
|
86
|
+
: allEntries.filter((e) => e.archived !== true);
|
|
87
|
+
// v0.11.0 (cycle-2 Blocker B1 fix): promoted entries surface FIRST in
|
|
88
|
+
// BOTH the entries[] array (API view for direct callers) AND in the
|
|
89
|
+
// rendered markdown block (LLM prompt view).
|
|
90
|
+
//
|
|
91
|
+
// The previous implementation built `[...promoted, ...rest]` and passed
|
|
92
|
+
// it through `tailRecent.slice(-limit)`, which is a TAIL slice — so
|
|
93
|
+
// promoted entries (sitting at the HEAD) were silently dropped the
|
|
94
|
+
// moment `entries.length > limit`. Worse, `formatLearningsForPrompt`
|
|
95
|
+
// reverses the array before rendering, so even in small fixtures the
|
|
96
|
+
// promoted entries landed at the BOTTOM of the rendered output.
|
|
97
|
+
//
|
|
98
|
+
// New flow:
|
|
99
|
+
// 1. Partition visible entries into promoted vs. rest.
|
|
100
|
+
// 2. Cap promoted at MAX_PROMOTED_IN_PROMPT to bound prompt size as
|
|
101
|
+
// the journal accumulates promoted entries over a project lifetime
|
|
102
|
+
// (architect cycle-2 Major M2). Pick the most-recent N by ts.
|
|
103
|
+
// 3. Apply the user's agent / decision filter ONLY to `rest` — promoted
|
|
104
|
+
// entries are team policy and bypass per-agent narrowing by design.
|
|
105
|
+
// 4. Order BOTH lists newest-first.
|
|
106
|
+
// 5. Build the API-visible `entries` array as
|
|
107
|
+
// `[...promotedNewestFirst, ...restNewestFirst]` so direct API
|
|
108
|
+
// consumers see promoted at the top.
|
|
109
|
+
// 6. For the render input, REVERSE `entries` once so the formatter's
|
|
110
|
+
// internal `.reverse()` flips it back to the same shape — promoted
|
|
111
|
+
// stays at the top of the rendered output. This keeps the formatter
|
|
112
|
+
// contract (input is chronological-oldest-first) intact for the
|
|
113
|
+
// existing test suite.
|
|
114
|
+
const MAX_PROMOTED_IN_PROMPT = 10;
|
|
115
|
+
const promoted = visible.filter((e) => e.promoted === true);
|
|
116
|
+
const rest = visible.filter((e) => e.promoted !== true);
|
|
117
|
+
// promoted: sort ascending by ts so slice(-N) returns newest N (in oldest-
|
|
118
|
+
// first order), then reverse to get newest-first.
|
|
119
|
+
const promotedSorted = [...promoted].sort((a, b) => a.ts.localeCompare(b.ts));
|
|
120
|
+
const promotedCappedNewestFirst = [...promotedSorted.slice(-MAX_PROMOTED_IN_PROMPT)].reverse();
|
|
121
|
+
// rest: tailRecent returns tail-N in storage order (oldest-first within
|
|
122
|
+
// the tail). Reverse for newest-first display.
|
|
123
|
+
const restBudget = Math.max(0, input.limit - promotedCappedNewestFirst.length);
|
|
124
|
+
const restTail = restBudget > 0
|
|
125
|
+
? tailRecent(rest, restBudget, {
|
|
126
|
+
...(input.agent !== undefined ? { agent: input.agent } : {}),
|
|
127
|
+
...(input.decision !== undefined ? { decision: input.decision } : {}),
|
|
128
|
+
})
|
|
129
|
+
: [];
|
|
130
|
+
const restTailNewestFirst = [...restTail].reverse();
|
|
131
|
+
// API-visible entries: promoted first, newest-within-each-group first.
|
|
132
|
+
const filtered = input.limit === 0 ? [] : [...promotedCappedNewestFirst, ...restTailNewestFirst];
|
|
133
|
+
// Format-input shape: chronological oldest-first. Since `filtered` is
|
|
134
|
+
// already in newest-first display order, reverse it before handing to
|
|
135
|
+
// the formatter (the formatter's internal `.reverse()` flips it back).
|
|
136
|
+
// This is the load-bearing detail that keeps the existing
|
|
137
|
+
// `learning-format.test.ts` contract intact while also putting promoted
|
|
138
|
+
// entries at the top of the rendered output (cycle-2 Blocker B1 fix).
|
|
139
|
+
const rendered = input.include_rendered && input.limit > 0
|
|
140
|
+
? formatLearningsForPrompt([...filtered].reverse(), {
|
|
50
141
|
...(input.changed_files ? { changedFiles: input.changed_files } : {}),
|
|
51
142
|
limit: input.limit,
|
|
52
143
|
})
|
|
53
144
|
: "";
|
|
54
|
-
|
|
145
|
+
const baseOut = {
|
|
55
146
|
entries: filtered,
|
|
56
147
|
total_in_store: allEntries.length,
|
|
57
148
|
rendered,
|
|
58
149
|
source: allEntries.length > 0 ? `${safeRoot}/${configuredPath ?? ".squad/learnings.jsonl"}` : null,
|
|
59
150
|
};
|
|
151
|
+
return summary ? { ...baseOut, summary } : baseOut;
|
|
60
152
|
}
|
|
61
153
|
export const readLearningsToolDef = {
|
|
62
154
|
name: "read_learnings",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-learnings.js","sourceRoot":"","sources":["../../src/tools/read-learnings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAsB,MAAM,sBAAsB,CAAC;AACrF,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IAC3C
|
|
1
|
+
{"version":3,"file":"read-learnings.js","sourceRoot":"","sources":["../../src/tools/read-learnings.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-learning.js","sourceRoot":"","sources":["../../src/tools/record-learning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"record-learning.js","sourceRoot":"","sources":["../../src/tools/record-learning.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/record-run.js
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
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 { appendRun } from "../runs/store.js";
|
|
4
|
+
import { appendRun, INVOCATION_VALUES } from "../runs/store.js";
|
|
5
5
|
/**
|
|
6
|
-
* SINGLE WRITER CONTRACT (plan v4, cycle 2 architect A-4; extended in v0.10.0
|
|
6
|
+
* SINGLE WRITER CONTRACT (plan v4, cycle 2 architect A-4; extended in v0.10.0,
|
|
7
|
+
* v0.10.1).
|
|
7
8
|
*
|
|
8
9
|
* Legitimate callers of this tool are skills that own a two-phase lifecycle:
|
|
9
10
|
*
|
|
10
11
|
* - `skills/squad/SKILL.md` (v0.9.0+) — Phase 1 `in_flight` + Phase 10
|
|
11
|
-
* terminal pair for `/squad:implement` and `/squad:review` runs
|
|
12
|
+
* terminal pair for `/squad:implement` and `/squad:review` runs
|
|
13
|
+
* (invocations: `implement`, `review`, `task`).
|
|
12
14
|
* - `skills/debug/SKILL.md` (v0.10.0+) — Phase A `in_flight` + Phase C
|
|
13
|
-
* terminal pair for `/squad:debug` runs
|
|
15
|
+
* terminal pair for `/squad:debug` runs (invocation: `debug`).
|
|
16
|
+
* - `skills/question/SKILL.md` (v0.10.1+) — Phase 1.5 `in_flight` + Phase
|
|
17
|
+
* 3.5 terminal pair for `/squad:question` runs (invocation: `question`).
|
|
18
|
+
* - `skills/brainstorm/SKILL.md` (v0.10.1+) — Step 1.5 `in_flight` + Step
|
|
19
|
+
* 5.5 terminal pair for `/brainstorm` runs (invocation: `brainstorm`).
|
|
14
20
|
*
|
|
15
|
-
* Any other caller is a bug. The
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* aggregator relies on for stranded-run detection.
|
|
21
|
+
* Any other caller is a bug. The two-phase write pair is the transactional
|
|
22
|
+
* unit; emitting terminal rows from any other path (notably
|
|
23
|
+
* `apply_consolidation_rules`) breaks the `(in_flight, completed)` pair-by-id
|
|
24
|
+
* invariant that the aggregator relies on for stranded-run detection.
|
|
20
25
|
*
|
|
21
26
|
* Two phases of the skill's lifecycle:
|
|
22
27
|
*
|
|
@@ -40,7 +45,7 @@ import { appendRun } from "../runs/store.js";
|
|
|
40
45
|
// instance; instead we redefine the inputs here as the tool boundary. The
|
|
41
46
|
// store re-validates inside `appendRun`, so any drift between the two
|
|
42
47
|
// schemas trips at the store layer rather than silently passing.
|
|
43
|
-
const InvocationEnum = z.enum(
|
|
48
|
+
const InvocationEnum = z.enum(INVOCATION_VALUES);
|
|
44
49
|
const ModeEnum = z.enum(["quick", "normal", "deep"]);
|
|
45
50
|
const ModeSourceEnum = z.enum(["user", "auto"]);
|
|
46
51
|
const StatusEnum = z.enum(["in_flight", "completed", "aborted"]);
|
|
@@ -107,11 +112,12 @@ async function handler(input) {
|
|
|
107
112
|
}
|
|
108
113
|
export const recordRunToolDef = {
|
|
109
114
|
name: "record_run",
|
|
110
|
-
description: "Append one RunRecord to .squad/runs.jsonl. Single-writer contract: only the
|
|
111
|
-
"(Phase 1
|
|
112
|
-
"Phase
|
|
113
|
-
"and enforces MAX_RECORD_BYTES (4000) via RECORD_TOO_LARGE on overflow.
|
|
114
|
-
"for matching in_flight↔terminal rows by id. File mode is 0o600
|
|
115
|
+
description: "Append one RunRecord to .squad/runs.jsonl. Single-writer contract: only the lifecycle-owning " +
|
|
116
|
+
"skills should call this — squad (Phase 1 + Phase 10), debug (Phase A + Phase C), question " +
|
|
117
|
+
"(Phase 1.5 + Phase 3.5), brainstorm (Step 1.5 + Step 5.5). Validates against the RunRecord " +
|
|
118
|
+
"schema_version:1 and enforces MAX_RECORD_BYTES (4000) via RECORD_TOO_LARGE on overflow. " +
|
|
119
|
+
"Caller is responsible for matching in_flight↔terminal rows by id. File mode is 0o600 " +
|
|
120
|
+
"(user-only) on first create. mode_warning.message is stripped of control chars at write time.",
|
|
115
121
|
schema,
|
|
116
122
|
handler,
|
|
117
123
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-run.js","sourceRoot":"","sources":["../../src/tools/record-run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,SAAS,EAAkB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"record-run.js","sourceRoot":"","sources":["../../src/tools/record-run.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/registry.js
CHANGED
|
@@ -8,6 +8,7 @@ import { scoreRubricTool } from "./score-rubric.js";
|
|
|
8
8
|
import { readSquadConfigTool } from "./read-squad-config.js";
|
|
9
9
|
import { readLearningsToolDef } from "./read-learnings.js";
|
|
10
10
|
import { recordLearningToolDef } from "./record-learning.js";
|
|
11
|
+
import { pruneLearningsToolDef } from "./prune-learnings.js";
|
|
11
12
|
import { listTasksToolDef } from "./list-tasks.js";
|
|
12
13
|
import { nextTaskToolDef } from "./next-task.js";
|
|
13
14
|
import { recordTasksToolDef } from "./record-tasks.js";
|
|
@@ -23,6 +24,7 @@ import { composeAdvisoryBundleTool } from "./compose-advisory-bundle.js";
|
|
|
23
24
|
import { recordRunToolDef } from "./record-run.js";
|
|
24
25
|
import { listRunsToolDef } from "./list-runs.js";
|
|
25
26
|
import { isSquadError } from "../errors.js";
|
|
27
|
+
import { pathSafe, pathSafeDetails } from "../util/path-safety.js";
|
|
26
28
|
import { logger, newRequestId } from "../observability/logger.js";
|
|
27
29
|
const tools = new Map();
|
|
28
30
|
export function register(def) {
|
|
@@ -40,6 +42,7 @@ export function registerTools() {
|
|
|
40
42
|
register(readSquadConfigTool);
|
|
41
43
|
register(readLearningsToolDef);
|
|
42
44
|
register(recordLearningToolDef);
|
|
45
|
+
register(pruneLearningsToolDef);
|
|
43
46
|
register(listTasksToolDef);
|
|
44
47
|
register(nextTaskToolDef);
|
|
45
48
|
register(recordTasksToolDef);
|
|
@@ -149,8 +152,17 @@ export async function dispatchTool(name, args) {
|
|
|
149
152
|
duration_ms,
|
|
150
153
|
error_code: err.code,
|
|
151
154
|
});
|
|
155
|
+
// Sanitize absolute filesystem paths before the payload crosses the MCP
|
|
156
|
+
// dispatch boundary to the (potentially untrusted) client. The in-
|
|
157
|
+
// process SquadError still carries full paths for local debug; only
|
|
158
|
+
// this serialised copy is truncated. See path-safety.ts:pathSafe for
|
|
159
|
+
// the truncation shape (last 3 segments with `…/` prefix).
|
|
152
160
|
return asToolErrorResponse({
|
|
153
|
-
error: {
|
|
161
|
+
error: {
|
|
162
|
+
code: err.code,
|
|
163
|
+
message: pathSafe(err.message),
|
|
164
|
+
details: pathSafeDetails(err.details),
|
|
165
|
+
},
|
|
154
166
|
});
|
|
155
167
|
}
|
|
156
168
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomically rewrite a JSONL file with a new set of rows. Survives crashes
|
|
3
|
+
* mid-write and races with concurrent appenders that hold the same file
|
|
4
|
+
* lock. Concurrent READERS (which do not take the lock today by design)
|
|
5
|
+
* also survive — they either see the pre-rewrite file in full or the
|
|
6
|
+
* post-rewrite file in full, never a half-written state. The protocol
|
|
7
|
+
* uses POSIX rename semantics (atomic-within-filesystem).
|
|
8
|
+
*
|
|
9
|
+
* Used by:
|
|
10
|
+
* - `prune_learnings` (v0.11.0+) to mark entries archived/promoted in a
|
|
11
|
+
* full rewrite of `.squad/learnings.jsonl`.
|
|
12
|
+
*
|
|
13
|
+
* Protocol (executes inside the lock):
|
|
14
|
+
* 1. Read current file contents into memory (caller does this BEFORE
|
|
15
|
+
* calling; we receive the new rows to write).
|
|
16
|
+
* 2. Write new content to `<file>.tmp` with mode 0o600 (private).
|
|
17
|
+
* 3. Rename current `<file>` → `<file>.prev` (atomic). This is the
|
|
18
|
+
* rollback point — if the next step fails, the user can manually
|
|
19
|
+
* `mv <file>.prev <file>` to recover.
|
|
20
|
+
* 4. Rename `<file>.tmp` → `<file>` (atomic).
|
|
21
|
+
* 5. Lock released by the caller's withFileLock wrapper.
|
|
22
|
+
*
|
|
23
|
+
* On failure between steps 3 and 4 (rare — both renames are usually a
|
|
24
|
+
* single syscall on the same FS), the file goes missing for a moment but
|
|
25
|
+
* `.prev` is intact. Step 4 retries inside the lock could be added; for
|
|
26
|
+
* now, surface the error and let the caller decide.
|
|
27
|
+
*
|
|
28
|
+
* The function takes a `lock: false` escape hatch for tests that want to
|
|
29
|
+
* exercise the rename sequence without taking the cross-process lock (we
|
|
30
|
+
* never use it in production).
|
|
31
|
+
*/
|
|
32
|
+
export interface AtomicRewriteOptions {
|
|
33
|
+
/** When false, skip the file-lock acquisition. Test-only. Default true. */
|
|
34
|
+
lock?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function atomicRewriteJsonl(filePath: string, rows: ReadonlyArray<object>, options?: AtomicRewriteOptions): Promise<void>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { withFileLock } from "./file-lock.js";
|
|
4
|
+
import { SquadError } from "../errors.js";
|
|
5
|
+
export async function atomicRewriteJsonl(filePath, rows, options = {}) {
|
|
6
|
+
const useLock = options.lock !== false;
|
|
7
|
+
const body = rows.map((r) => JSON.stringify(r)).join("\n") + (rows.length > 0 ? "\n" : "");
|
|
8
|
+
const tmpPath = `${filePath}.tmp`;
|
|
9
|
+
const prevPath = `${filePath}.prev`;
|
|
10
|
+
const performRewrite = async () => {
|
|
11
|
+
// Ensure the directory exists. mkdir is idempotent.
|
|
12
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 });
|
|
13
|
+
// 1. Write the new content to <file>.tmp with private mode. fh.writeFile
|
|
14
|
+
// truncates if the file existed (we never reuse a stale tmp).
|
|
15
|
+
const fh = await fs.open(tmpPath, "w", 0o600);
|
|
16
|
+
try {
|
|
17
|
+
await fh.writeFile(body, "utf8");
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
await fh.close();
|
|
21
|
+
}
|
|
22
|
+
// 2. Move the current file to <file>.prev as a rollback snapshot. If the
|
|
23
|
+
// source doesn't exist (first-ever write), the rename is skipped.
|
|
24
|
+
let prevMoved = false;
|
|
25
|
+
try {
|
|
26
|
+
await fs.rename(filePath, prevPath);
|
|
27
|
+
prevMoved = true;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
if (err.code !== "ENOENT")
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
// 3. Move the new tmp into place. Atomic on POSIX same-FS rename.
|
|
34
|
+
// v0.11.0 cycle-2 Blocker B2 fix: on failure here, attempt to rollback
|
|
35
|
+
// .prev → <file> so the caller never sees a missing journal. If the
|
|
36
|
+
// rollback also fails, surface a SquadError with the manual recovery
|
|
37
|
+
// command embedded so the user can `mv .prev <file>` themselves.
|
|
38
|
+
try {
|
|
39
|
+
await fs.rename(tmpPath, filePath);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
const step3Err = err;
|
|
43
|
+
if (!prevMoved) {
|
|
44
|
+
// First-ever write — no .prev to roll back. Clean up tmp and rethrow.
|
|
45
|
+
try {
|
|
46
|
+
await fs.unlink(tmpPath);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* swallow — tmp cleanup is best-effort */
|
|
50
|
+
}
|
|
51
|
+
throw step3Err;
|
|
52
|
+
}
|
|
53
|
+
// We moved source → .prev and now the second rename failed. Try to
|
|
54
|
+
// put .prev back so the journal isn't missing.
|
|
55
|
+
try {
|
|
56
|
+
await fs.rename(prevPath, filePath);
|
|
57
|
+
// Rollback succeeded. Cleanup tmp.
|
|
58
|
+
try {
|
|
59
|
+
await fs.unlink(tmpPath);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
/* swallow */
|
|
63
|
+
}
|
|
64
|
+
throw new SquadError("ATOMIC_REWRITE_FAILED", `failed to swap new content into place (${step3Err.message}). Rollback applied: original journal restored from .prev. No data loss.`, {
|
|
65
|
+
step: "rename_tmp_to_file",
|
|
66
|
+
path: filePath,
|
|
67
|
+
errno: step3Err.code,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (rollbackErr) {
|
|
71
|
+
// Rollback failed too — surface manual recovery instructions.
|
|
72
|
+
if (rollbackErr.code === "ATOMIC_REWRITE_FAILED") {
|
|
73
|
+
// The error from the success-rollback branch above; bubble unchanged.
|
|
74
|
+
throw rollbackErr;
|
|
75
|
+
}
|
|
76
|
+
throw new SquadError("ATOMIC_REWRITE_FAILED", `failed to swap new content into place AND failed to rollback .prev → original. ` +
|
|
77
|
+
`To recover manually: mv ${prevPath} ${filePath}`, {
|
|
78
|
+
step: "rename_tmp_to_file_with_rollback_failure",
|
|
79
|
+
path: filePath,
|
|
80
|
+
prev: prevPath,
|
|
81
|
+
tmp: tmpPath,
|
|
82
|
+
primary_errno: step3Err.code,
|
|
83
|
+
rollback_errno: rollbackErr.code,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
if (useLock) {
|
|
89
|
+
await withFileLock(filePath, performRewrite);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
await performRewrite();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=atomic-rewrite-jsonl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic-rewrite-jsonl.js","sourceRoot":"","sources":["../../src/util/atomic-rewrite-jsonl.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,40 @@
|
|
|
1
1
|
export declare const MAX_BYTES = 16384;
|
|
2
|
+
/**
|
|
3
|
+
* Truncate absolute filesystem paths inside a string to their last 3 segments,
|
|
4
|
+
* with a `…/` prefix indicating truncation. Used by the MCP dispatch boundary
|
|
5
|
+
* (`src/tools/registry.ts`) to sanitise `SquadError.message` and
|
|
6
|
+
* `SquadError.details` before they leave the server to a (potentially
|
|
7
|
+
* untrusted) MCP client.
|
|
8
|
+
*
|
|
9
|
+
* Why: error messages routinely embed `workspaceRoot` or absolute file paths
|
|
10
|
+
* (e.g. `failed to read runs file /home/<user>/work/some-repo/.squad/runs.jsonl`).
|
|
11
|
+
* The full path leaks the local user's home directory and folder layout —
|
|
12
|
+
* useful debug context, but a sidechannel for username discovery if an MCP
|
|
13
|
+
* client logs or relays error payloads.
|
|
14
|
+
*
|
|
15
|
+
* The transform is purely cosmetic — the `SquadError` itself, in-process,
|
|
16
|
+
* still carries the full path for local debugging. Only the serialised
|
|
17
|
+
* payload that crosses the dispatch boundary is sanitised.
|
|
18
|
+
*
|
|
19
|
+
* Recognised path shapes (handled non-greedily so multiple paths in one
|
|
20
|
+
* string each truncate independently):
|
|
21
|
+
*
|
|
22
|
+
* - POSIX absolute: `/foo/bar/baz/qux/file.ts` → `…/baz/qux/file.ts`
|
|
23
|
+
* - Windows drive: `C:\foo\bar\baz\qux\file.ts` → `…/baz/qux/file.ts`
|
|
24
|
+
*
|
|
25
|
+
* Paths with fewer than 4 non-empty segments do not match the pattern (the
|
|
26
|
+
* regex requires at least two interior separators) and are returned as-is.
|
|
27
|
+
* Already-truncated paths (begin with `…/`) are idempotent under this
|
|
28
|
+
* function (lookbehind prevents re-matching).
|
|
29
|
+
*/
|
|
30
|
+
export declare function pathSafe(s: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Recursively apply `pathSafe` to every string leaf in an error-details
|
|
33
|
+
* payload. Top-level wrapper for `SquadError.details` sanitisation at the
|
|
34
|
+
* dispatch boundary. Returns a deep-cloned object — the in-process error
|
|
35
|
+
* is not mutated.
|
|
36
|
+
*/
|
|
37
|
+
export declare function pathSafeDetails(details: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
|
|
2
38
|
export interface SafePathContext {
|
|
3
39
|
rootRealCache: Map<string, string>;
|
|
4
40
|
}
|
package/dist/util/path-safety.js
CHANGED
|
@@ -3,6 +3,82 @@ import path from "node:path";
|
|
|
3
3
|
import { SquadError } from "../errors.js";
|
|
4
4
|
import { rejectIfMalformed, realpathOrSelf } from "./path-internal.js";
|
|
5
5
|
export const MAX_BYTES = 16_384;
|
|
6
|
+
/**
|
|
7
|
+
* Truncate absolute filesystem paths inside a string to their last 3 segments,
|
|
8
|
+
* with a `…/` prefix indicating truncation. Used by the MCP dispatch boundary
|
|
9
|
+
* (`src/tools/registry.ts`) to sanitise `SquadError.message` and
|
|
10
|
+
* `SquadError.details` before they leave the server to a (potentially
|
|
11
|
+
* untrusted) MCP client.
|
|
12
|
+
*
|
|
13
|
+
* Why: error messages routinely embed `workspaceRoot` or absolute file paths
|
|
14
|
+
* (e.g. `failed to read runs file /home/<user>/work/some-repo/.squad/runs.jsonl`).
|
|
15
|
+
* The full path leaks the local user's home directory and folder layout —
|
|
16
|
+
* useful debug context, but a sidechannel for username discovery if an MCP
|
|
17
|
+
* client logs or relays error payloads.
|
|
18
|
+
*
|
|
19
|
+
* The transform is purely cosmetic — the `SquadError` itself, in-process,
|
|
20
|
+
* still carries the full path for local debugging. Only the serialised
|
|
21
|
+
* payload that crosses the dispatch boundary is sanitised.
|
|
22
|
+
*
|
|
23
|
+
* Recognised path shapes (handled non-greedily so multiple paths in one
|
|
24
|
+
* string each truncate independently):
|
|
25
|
+
*
|
|
26
|
+
* - POSIX absolute: `/foo/bar/baz/qux/file.ts` → `…/baz/qux/file.ts`
|
|
27
|
+
* - Windows drive: `C:\foo\bar\baz\qux\file.ts` → `…/baz/qux/file.ts`
|
|
28
|
+
*
|
|
29
|
+
* Paths with fewer than 4 non-empty segments do not match the pattern (the
|
|
30
|
+
* regex requires at least two interior separators) and are returned as-is.
|
|
31
|
+
* Already-truncated paths (begin with `…/`) are idempotent under this
|
|
32
|
+
* function (lookbehind prevents re-matching).
|
|
33
|
+
*/
|
|
34
|
+
export function pathSafe(s) {
|
|
35
|
+
if (typeof s !== "string" || s.length === 0)
|
|
36
|
+
return s;
|
|
37
|
+
// POSIX absolute path: starts with /, captures everything until a whitespace,
|
|
38
|
+
// quote, or message-formatting boundary. The `(?<!…)` lookbehind prevents
|
|
39
|
+
// re-matching after an already-truncated `…/` prefix (idempotency).
|
|
40
|
+
const posix = /(?<!…)\/(?:[A-Za-z0-9._-][^\s'"`<>:,)\]]*\/)+[A-Za-z0-9._-][^\s'"`<>:,)\]]*/g;
|
|
41
|
+
// Windows drive path: drive letter + colon + backslash, captured similarly.
|
|
42
|
+
// Note: the Windows segment char-class adds a space (`[A-Za-z0-9._ -]` vs
|
|
43
|
+
// POSIX's `[A-Za-z0-9._-]`) because Windows directory names commonly contain
|
|
44
|
+
// spaces (`C:\Program Files\...`). POSIX paths conventionally do not, so
|
|
45
|
+
// the asymmetry is intentional, not a copy-paste oversight.
|
|
46
|
+
const win = /[A-Za-z]:\\(?:[A-Za-z0-9._ -][^\s'"`<>:,)\]]*\\)+[A-Za-z0-9._ -][^\s'"`<>:,)\]]*/g;
|
|
47
|
+
const truncate = (match, sep) => {
|
|
48
|
+
// Drop empty leading segment from absolute paths (leading `/` gives `""`).
|
|
49
|
+
const segments = match.split(sep).filter((p) => p.length > 0);
|
|
50
|
+
if (segments.length <= 3)
|
|
51
|
+
return match;
|
|
52
|
+
return "…/" + segments.slice(-3).join("/");
|
|
53
|
+
};
|
|
54
|
+
return s.replace(posix, (m) => truncate(m, "/")).replace(win, (m) => truncate(m, "\\"));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Recursively apply `pathSafe` to every string leaf in an error-details
|
|
58
|
+
* payload. Top-level wrapper for `SquadError.details` sanitisation at the
|
|
59
|
+
* dispatch boundary. Returns a deep-cloned object — the in-process error
|
|
60
|
+
* is not mutated.
|
|
61
|
+
*/
|
|
62
|
+
export function pathSafeDetails(details) {
|
|
63
|
+
if (details === undefined)
|
|
64
|
+
return undefined;
|
|
65
|
+
const out = {};
|
|
66
|
+
for (const [k, v] of Object.entries(details)) {
|
|
67
|
+
if (typeof v === "string") {
|
|
68
|
+
out[k] = pathSafe(v);
|
|
69
|
+
}
|
|
70
|
+
else if (Array.isArray(v)) {
|
|
71
|
+
out[k] = v.map((item) => (typeof item === "string" ? pathSafe(item) : item));
|
|
72
|
+
}
|
|
73
|
+
else if (v !== null && typeof v === "object") {
|
|
74
|
+
out[k] = pathSafeDetails(v);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
out[k] = v;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
6
82
|
export function createSafePathContext() {
|
|
7
83
|
return { rootRealCache: new Map() };
|
|
8
84
|
}
|