gossipcat 0.6.7 → 0.6.9
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/dist-mcp/mcp-server.js +205 -26
- package/package.json +3 -2
package/dist-mcp/mcp-server.js
CHANGED
|
@@ -6967,11 +6967,14 @@ var init_mcp_context = __esm({
|
|
|
6967
6967
|
// packages/orchestrator/src/log.ts
|
|
6968
6968
|
function ts() {
|
|
6969
6969
|
const d = /* @__PURE__ */ new Date();
|
|
6970
|
+
const yyyy = d.getUTCFullYear();
|
|
6971
|
+
const mo = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
6972
|
+
const dd = String(d.getUTCDate()).padStart(2, "0");
|
|
6970
6973
|
const hh = String(d.getUTCHours()).padStart(2, "0");
|
|
6971
6974
|
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
|
6972
6975
|
const ss = String(d.getUTCSeconds()).padStart(2, "0");
|
|
6973
6976
|
const ms = String(d.getUTCMilliseconds()).padStart(3, "0");
|
|
6974
|
-
return `${hh}:${mm}:${ss}.${ms}`;
|
|
6977
|
+
return `${yyyy}-${mo}-${dd} ${hh}:${mm}:${ss}.${ms}Z`;
|
|
6975
6978
|
}
|
|
6976
6979
|
function emojiFor(tag) {
|
|
6977
6980
|
if (TAG_EMOJI[tag]) return TAG_EMOJI[tag];
|
|
@@ -14617,13 +14620,17 @@ ${context}` : ""}
|
|
|
14617
14620
|
});
|
|
14618
14621
|
|
|
14619
14622
|
// packages/tools/src/file-tools.ts
|
|
14620
|
-
var import_promises, import_path6, import_fs7, FileTools;
|
|
14623
|
+
var import_promises, import_path6, import_fs7, import_re2, MAX_GREP_FILE_BYTES, MAX_GREP_MATCHES, MAX_GREP_FILES, FileTools;
|
|
14621
14624
|
var init_file_tools = __esm({
|
|
14622
14625
|
"packages/tools/src/file-tools.ts"() {
|
|
14623
14626
|
"use strict";
|
|
14624
14627
|
import_promises = require("fs/promises");
|
|
14625
14628
|
import_path6 = require("path");
|
|
14626
14629
|
import_fs7 = require("fs");
|
|
14630
|
+
import_re2 = __toESM(require("re2"));
|
|
14631
|
+
MAX_GREP_FILE_BYTES = 2 * 1024 * 1024;
|
|
14632
|
+
MAX_GREP_MATCHES = 2e3;
|
|
14633
|
+
MAX_GREP_FILES = 5e3;
|
|
14627
14634
|
FileTools = class {
|
|
14628
14635
|
constructor(sandbox) {
|
|
14629
14636
|
this.sandbox = sandbox;
|
|
@@ -14709,13 +14716,17 @@ var init_file_tools = __esm({
|
|
|
14709
14716
|
const searchRoot = args.path ? this.sandbox.validatePath(args.path, allowed) : agentRoot || this.sandbox.projectRoot;
|
|
14710
14717
|
let regex;
|
|
14711
14718
|
try {
|
|
14712
|
-
regex = new
|
|
14719
|
+
regex = new import_re2.default(args.pattern);
|
|
14713
14720
|
} catch (error51) {
|
|
14714
14721
|
return `Invalid regex pattern: ${error51 instanceof Error ? error51.message : "Unknown error"}`;
|
|
14715
14722
|
}
|
|
14716
|
-
const
|
|
14717
|
-
await this.grepDir(searchRoot, regex,
|
|
14718
|
-
|
|
14723
|
+
const state = { matches: [], filesScanned: 0, truncated: false };
|
|
14724
|
+
await this.grepDir(searchRoot, regex, state, 0, 10);
|
|
14725
|
+
let output = state.matches.join("\n") || "No matches found";
|
|
14726
|
+
if (state.truncated) {
|
|
14727
|
+
output += "\n... (truncated \u2014 result or scan limit reached; narrow your pattern/path)";
|
|
14728
|
+
}
|
|
14729
|
+
return output;
|
|
14719
14730
|
}
|
|
14720
14731
|
async fileTree(args, agentRoot) {
|
|
14721
14732
|
const allowed = agentRoot ? [agentRoot] : [];
|
|
@@ -14735,7 +14746,7 @@ var init_file_tools = __esm({
|
|
|
14735
14746
|
return;
|
|
14736
14747
|
}
|
|
14737
14748
|
const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
14738
|
-
const regex = new
|
|
14749
|
+
const regex = new import_re2.default(regexStr);
|
|
14739
14750
|
for (const entry of entries) {
|
|
14740
14751
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
14741
14752
|
const fullPath = (0, import_path6.join)(dir, entry);
|
|
@@ -14755,8 +14766,9 @@ var init_file_tools = __esm({
|
|
|
14755
14766
|
}
|
|
14756
14767
|
}
|
|
14757
14768
|
}
|
|
14758
|
-
async grepDir(dir, regex,
|
|
14769
|
+
async grepDir(dir, regex, state, depth = 0, maxDepth = 10) {
|
|
14759
14770
|
if (depth >= maxDepth) return;
|
|
14771
|
+
if (state.truncated) return;
|
|
14760
14772
|
let entries;
|
|
14761
14773
|
try {
|
|
14762
14774
|
entries = await (0, import_promises.readdir)(dir);
|
|
@@ -14764,6 +14776,7 @@ var init_file_tools = __esm({
|
|
|
14764
14776
|
return;
|
|
14765
14777
|
}
|
|
14766
14778
|
for (const entry of entries) {
|
|
14779
|
+
if (state.truncated) return;
|
|
14767
14780
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
14768
14781
|
const fullPath = (0, import_path6.join)(dir, entry);
|
|
14769
14782
|
let info;
|
|
@@ -14773,17 +14786,29 @@ var init_file_tools = __esm({
|
|
|
14773
14786
|
continue;
|
|
14774
14787
|
}
|
|
14775
14788
|
if (info.isDirectory()) {
|
|
14776
|
-
await this.grepDir(fullPath, regex,
|
|
14789
|
+
await this.grepDir(fullPath, regex, state, depth + 1, maxDepth);
|
|
14777
14790
|
} else {
|
|
14791
|
+
if (info.size > MAX_GREP_FILE_BYTES) {
|
|
14792
|
+
continue;
|
|
14793
|
+
}
|
|
14794
|
+
state.filesScanned++;
|
|
14795
|
+
if (state.filesScanned > MAX_GREP_FILES) {
|
|
14796
|
+
state.truncated = true;
|
|
14797
|
+
return;
|
|
14798
|
+
}
|
|
14778
14799
|
try {
|
|
14779
14800
|
const content = await (0, import_promises.readFile)(fullPath, "utf-8");
|
|
14780
14801
|
const lines = content.split("\n");
|
|
14781
14802
|
const relPath = (0, import_path6.relative)(this.sandbox.projectRoot, fullPath);
|
|
14782
|
-
lines.
|
|
14783
|
-
if (
|
|
14784
|
-
|
|
14803
|
+
for (let idx = 0; idx < lines.length; idx++) {
|
|
14804
|
+
if (state.matches.length >= MAX_GREP_MATCHES) {
|
|
14805
|
+
state.truncated = true;
|
|
14806
|
+
break;
|
|
14785
14807
|
}
|
|
14786
|
-
|
|
14808
|
+
if (regex.test(lines[idx])) {
|
|
14809
|
+
state.matches.push(`${relPath}:${idx + 1}: ${lines[idx]}`);
|
|
14810
|
+
}
|
|
14811
|
+
}
|
|
14787
14812
|
} catch {
|
|
14788
14813
|
}
|
|
14789
14814
|
}
|
|
@@ -20216,6 +20241,9 @@ __export(src_exports2, {
|
|
|
20216
20241
|
GIT_TOOLS: () => GIT_TOOLS,
|
|
20217
20242
|
GitTools: () => GitTools,
|
|
20218
20243
|
IDENTITY_TOOLS: () => IDENTITY_TOOLS,
|
|
20244
|
+
MAX_GREP_FILES: () => MAX_GREP_FILES,
|
|
20245
|
+
MAX_GREP_FILE_BYTES: () => MAX_GREP_FILE_BYTES,
|
|
20246
|
+
MAX_GREP_MATCHES: () => MAX_GREP_MATCHES,
|
|
20219
20247
|
MAX_MEMORY_QUERY_LOG_BYTES: () => MAX_MEMORY_QUERY_LOG_BYTES,
|
|
20220
20248
|
MEMORY_QUERY_LOG: () => MEMORY_QUERY_LOG,
|
|
20221
20249
|
MEMORY_TOOLS: () => MEMORY_TOOLS,
|
|
@@ -24732,7 +24760,7 @@ This section will be used for cross-review with peer agents.
|
|
|
24732
24760
|
|
|
24733
24761
|
${OUTPUT_DELIVERY_PROTOCOL}` });
|
|
24734
24762
|
} else {
|
|
24735
|
-
const hasAnyMeaningfulPart = !!(parts.identity || parts.instructions || parts.memory || parts.memoryDir || parts.lens || parts.skills || parts.context || parts.sessionContext || parts.chainContext || parts.specReviewContext || parts.projectStructure || parts.task || parts.consensusFindings && parts.consensusFindings.length > 0);
|
|
24763
|
+
const hasAnyMeaningfulPart = !!(parts.identity || parts.instructions || parts.memory || parts.memoryDir || parts.lens || parts.skills || parts.context || parts.sessionContext || parts.chainContext || parts.specReviewContext || parts.projectStructure || parts.task || parts.consensusFindings && parts.consensusFindings.length > 0 || parts.agentCorrections && parts.agentCorrections.length > 0);
|
|
24736
24764
|
if (hasAnyMeaningfulPart) {
|
|
24737
24765
|
suffix.push({ priority: 0, text: `
|
|
24738
24766
|
|
|
@@ -24758,13 +24786,18 @@ ${parts.lens}
|
|
|
24758
24786
|
${parts.specReviewContext}
|
|
24759
24787
|
--- END SPEC REVIEW ---` });
|
|
24760
24788
|
}
|
|
24761
|
-
if (parts.memory || parts.consensusFindings && parts.consensusFindings.length > 0) {
|
|
24789
|
+
if (parts.memory || parts.consensusFindings && parts.consensusFindings.length > 0 || parts.agentCorrections && parts.agentCorrections.length > 0) {
|
|
24762
24790
|
const memParts = [];
|
|
24763
24791
|
if (parts.memory) memParts.push(parts.memory);
|
|
24764
24792
|
if (parts.consensusFindings && parts.consensusFindings.length > 0) {
|
|
24765
24793
|
const findingsBlock = "### Recent Consensus Findings\n" + parts.consensusFindings.map((f, i) => `${i + 1}. ${f}`).join("\n");
|
|
24766
24794
|
memParts.push(findingsBlock);
|
|
24767
24795
|
}
|
|
24796
|
+
if (parts.agentCorrections && parts.agentCorrections.length > 0) {
|
|
24797
|
+
memParts.push(
|
|
24798
|
+
"### Your Prior Corrections\n" + parts.agentCorrections.map((f, i) => `${i + 1}. ${f}`).join("\n")
|
|
24799
|
+
);
|
|
24800
|
+
}
|
|
24768
24801
|
suffix.push({ priority: 3, text: `
|
|
24769
24802
|
|
|
24770
24803
|
--- MEMORY ---
|
|
@@ -24883,7 +24916,7 @@ var init_prompt_assembler = __esm({
|
|
|
24883
24916
|
});
|
|
24884
24917
|
|
|
24885
24918
|
// packages/orchestrator/src/agent-memory.ts
|
|
24886
|
-
var import_fs20, import_path21, FINDINGS_MAX_RESULTS, FINDINGS_MAX_CHARS, FINDINGS_STALE_DAYS, FINDINGS_MIN_SCORE, AgentMemoryReader;
|
|
24919
|
+
var import_fs20, import_path21, FINDINGS_MAX_RESULTS, FINDINGS_MAX_CHARS, FINDINGS_STALE_DAYS, FINDINGS_MIN_SCORE, CORRECTIONS_MAX_RESULTS, AgentMemoryReader;
|
|
24887
24920
|
var init_agent_memory = __esm({
|
|
24888
24921
|
"packages/orchestrator/src/agent-memory.ts"() {
|
|
24889
24922
|
"use strict";
|
|
@@ -24893,6 +24926,7 @@ var init_agent_memory = __esm({
|
|
|
24893
24926
|
FINDINGS_MAX_CHARS = 150;
|
|
24894
24927
|
FINDINGS_STALE_DAYS = 30;
|
|
24895
24928
|
FINDINGS_MIN_SCORE = 1;
|
|
24929
|
+
CORRECTIONS_MAX_RESULTS = 2;
|
|
24896
24930
|
AgentMemoryReader = class {
|
|
24897
24931
|
constructor(projectRoot) {
|
|
24898
24932
|
this.projectRoot = projectRoot;
|
|
@@ -24993,6 +25027,46 @@ ${content}
|
|
|
24993
25027
|
}
|
|
24994
25028
|
return scored.sort((a, b) => b.score - a.score).slice(0, FINDINGS_MAX_RESULTS).map((s) => s.text);
|
|
24995
25029
|
}
|
|
25030
|
+
/**
|
|
25031
|
+
* Pre-fetch this agent's own prior lesson cards relevant to the task (issue #642 B-delta).
|
|
25032
|
+
* Selects by `lesson-*.md` filename (not frontmatter `type`, which parsers don't read),
|
|
25033
|
+
* ranks by body keyword overlap, drops cards older than FINDINGS_STALE_DAYS, and strips
|
|
25034
|
+
* prompt-injection delimiters before returning. Returns top CORRECTIONS_MAX_RESULTS snippets.
|
|
25035
|
+
*/
|
|
25036
|
+
prefetchAgentCorrectionsText(agentId, taskText) {
|
|
25037
|
+
if (!agentId || /[/\\.\0]/.test(agentId)) return [];
|
|
25038
|
+
const knowledgeDir = (0, import_path21.join)(this.projectRoot, ".gossip", "agents", agentId, "memory", "knowledge");
|
|
25039
|
+
if (!(0, import_fs20.existsSync)(knowledgeDir)) return [];
|
|
25040
|
+
let files;
|
|
25041
|
+
try {
|
|
25042
|
+
files = (0, import_fs20.readdirSync)(knowledgeDir).filter((f) => f.startsWith("lesson-") && f.endsWith(".md"));
|
|
25043
|
+
} catch {
|
|
25044
|
+
return [];
|
|
25045
|
+
}
|
|
25046
|
+
if (files.length === 0) return [];
|
|
25047
|
+
const keywords = this.extractKeywords(taskText);
|
|
25048
|
+
if (keywords.length === 0) return [];
|
|
25049
|
+
const cutoffMs = Date.now() - FINDINGS_STALE_DAYS * 864e5;
|
|
25050
|
+
const scored = [];
|
|
25051
|
+
for (const file2 of files) {
|
|
25052
|
+
const filePath = (0, import_path21.join)(knowledgeDir, file2);
|
|
25053
|
+
let content;
|
|
25054
|
+
try {
|
|
25055
|
+
const mtime = (0, import_fs20.statSync)(filePath).mtimeMs;
|
|
25056
|
+
if (mtime < cutoffMs) continue;
|
|
25057
|
+
content = (0, import_fs20.readFileSync)(filePath, "utf-8");
|
|
25058
|
+
} catch {
|
|
25059
|
+
continue;
|
|
25060
|
+
}
|
|
25061
|
+
const body = content.replace(/^---\n[\s\S]*?\n---\n*/, "").replace(/<\/?(?:agent-memory|system|instructions)>/gi, "").replace(/\s+/g, " ").trim();
|
|
25062
|
+
if (!body) continue;
|
|
25063
|
+
const score = this.scoreKeywords(keywords, body);
|
|
25064
|
+
if (score >= FINDINGS_MIN_SCORE) {
|
|
25065
|
+
scored.push({ text: body.slice(0, FINDINGS_MAX_CHARS).trim(), score });
|
|
25066
|
+
}
|
|
25067
|
+
}
|
|
25068
|
+
return scored.sort((a, b) => b.score - a.score).slice(0, CORRECTIONS_MAX_RESULTS).map((s) => s.text);
|
|
25069
|
+
}
|
|
24996
25070
|
/** Simple word-boundary keyword overlap scoring (no LLM). */
|
|
24997
25071
|
extractKeywords(taskText) {
|
|
24998
25072
|
const words = taskText.toLowerCase().split(/[\s,/.;:!?()\[\]{}*_~`"'<>|]+/);
|
|
@@ -25477,7 +25551,21 @@ function validateAgentId(agentId) {
|
|
|
25477
25551
|
function sanitizeTaskId(taskId) {
|
|
25478
25552
|
return taskId.replace(/[/\\:*?"<>|\0]/g, "_");
|
|
25479
25553
|
}
|
|
25480
|
-
|
|
25554
|
+
function writeLessonCardsForSignals(projectRoot, signals) {
|
|
25555
|
+
if (!Array.isArray(signals) || signals.length === 0) return;
|
|
25556
|
+
const writer = new MemoryWriter(projectRoot);
|
|
25557
|
+
for (const s of signals) {
|
|
25558
|
+
if (!s || !s.finding_id || !TERMINAL_LESSON_SIGNALS.has(s.signal)) continue;
|
|
25559
|
+
writer.writeLessonCard(s.agent_id, {
|
|
25560
|
+
signal: s.signal,
|
|
25561
|
+
findingId: s.finding_id,
|
|
25562
|
+
finding: s.finding ?? "",
|
|
25563
|
+
lesson: s.lesson,
|
|
25564
|
+
taskTokens: s.finding
|
|
25565
|
+
});
|
|
25566
|
+
}
|
|
25567
|
+
}
|
|
25568
|
+
var import_fs23, import_path24, import_crypto11, TERMINAL_LESSON_SIGNALS, LESSON_CARDS_MAX_PER_AGENT, LESSON_RESERVED_AGENT_IDS, MemoryWriter;
|
|
25481
25569
|
var init_memory_writer = __esm({
|
|
25482
25570
|
"packages/orchestrator/src/memory-writer.ts"() {
|
|
25483
25571
|
"use strict";
|
|
@@ -25488,6 +25576,13 @@ var init_memory_writer = __esm({
|
|
|
25488
25576
|
init_project_structure();
|
|
25489
25577
|
init_log();
|
|
25490
25578
|
init_completion_signals();
|
|
25579
|
+
TERMINAL_LESSON_SIGNALS = /* @__PURE__ */ new Set([
|
|
25580
|
+
"hallucination_caught",
|
|
25581
|
+
"impl_test_fail",
|
|
25582
|
+
"impl_peer_rejected"
|
|
25583
|
+
]);
|
|
25584
|
+
LESSON_CARDS_MAX_PER_AGENT = 200;
|
|
25585
|
+
LESSON_RESERVED_AGENT_IDS = /* @__PURE__ */ new Set(["_project", "_system", "_utility"]);
|
|
25491
25586
|
MemoryWriter = class {
|
|
25492
25587
|
constructor(projectRoot) {
|
|
25493
25588
|
this.projectRoot = projectRoot;
|
|
@@ -26060,7 +26155,7 @@ ${truncateAtWord(summaryBody, NEXT_SESSION_MAX_CHARS)}
|
|
|
26060
26155
|
/** Shared warmth-aware pruning — evicts lowest-warmth files, respects pinned */
|
|
26061
26156
|
pruneKnowledgeDir(knowledgeDir, maxFiles) {
|
|
26062
26157
|
try {
|
|
26063
|
-
const existing = (0, import_fs23.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md") && !f.endsWith("-session.md")).sort();
|
|
26158
|
+
const existing = (0, import_fs23.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md") && !f.endsWith("-session.md") && !f.startsWith("lesson-")).sort();
|
|
26064
26159
|
if (existing.length >= maxFiles) {
|
|
26065
26160
|
const scored = existing.map((f) => {
|
|
26066
26161
|
const content = (0, import_fs23.readFileSync)((0, import_path24.join)(knowledgeDir, f), "utf-8");
|
|
@@ -26364,6 +26459,76 @@ ${result}`;
|
|
|
26364
26459
|
this.pruneKnowledgeDir(knowledgeDir, 25);
|
|
26365
26460
|
(0, import_fs23.writeFileSync)((0, import_path24.join)(knowledgeDir, filename), content);
|
|
26366
26461
|
}
|
|
26462
|
+
/**
|
|
26463
|
+
* Write a recallable "lesson card" for a terminal correction signal (issue #642 A).
|
|
26464
|
+
* Best-effort: any failure is swallowed — this MUST NOT fail signal recording.
|
|
26465
|
+
* Idempotent: keyed by finding_id via sanitizeTaskId, no timestamp in the filename.
|
|
26466
|
+
*/
|
|
26467
|
+
writeLessonCard(agentId, card) {
|
|
26468
|
+
try {
|
|
26469
|
+
if (LESSON_RESERVED_AGENT_IDS.has(agentId)) return;
|
|
26470
|
+
validateAgentId(agentId);
|
|
26471
|
+
const slug = sanitizeTaskId(card.findingId).slice(0, 96);
|
|
26472
|
+
if (!slug) return;
|
|
26473
|
+
const memDir = this.ensureDirs(agentId);
|
|
26474
|
+
const knowledgeDir = (0, import_path24.join)(memDir, "knowledge");
|
|
26475
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
26476
|
+
const generated = (/* @__PURE__ */ new Date()).toISOString();
|
|
26477
|
+
const shortId = slug.slice(0, 24);
|
|
26478
|
+
const finding = truncateAtWord(sanitizeYamlValue(card.finding ?? ""), 400);
|
|
26479
|
+
const lessonBody = card.lesson ? truncateAtWord(sanitizeYamlValue(card.lesson), 400) : "(no root-cause supplied)";
|
|
26480
|
+
const desc = sanitizeYamlValue(card.lesson || card.finding || "lesson").slice(0, 80);
|
|
26481
|
+
const taskTokens = (card.taskTokens ?? card.finding ?? "").replace(/[\n\r]/g, " ").slice(0, 300);
|
|
26482
|
+
const content = [
|
|
26483
|
+
"---",
|
|
26484
|
+
`name: lesson-${sanitizeYamlValue(card.signal)}-${shortId}`,
|
|
26485
|
+
`description: ${desc}`,
|
|
26486
|
+
"type: lesson",
|
|
26487
|
+
`agent: ${sanitizeYamlValue(agentId)}`,
|
|
26488
|
+
`signal: ${sanitizeYamlValue(card.signal)}`,
|
|
26489
|
+
`finding_id: ${sanitizeYamlValue(card.findingId)}`,
|
|
26490
|
+
"importance: 0.7",
|
|
26491
|
+
`lastAccessed: ${today}`,
|
|
26492
|
+
"accessCount: 0",
|
|
26493
|
+
`generated: ${generated}`,
|
|
26494
|
+
"---",
|
|
26495
|
+
"",
|
|
26496
|
+
`**Why it failed:** ${lessonBody}`,
|
|
26497
|
+
"",
|
|
26498
|
+
`**What happened:** ${finding}`,
|
|
26499
|
+
"",
|
|
26500
|
+
`**Task context:** ${taskTokens}`
|
|
26501
|
+
].join("\n");
|
|
26502
|
+
const cardPath = (0, import_path24.join)(knowledgeDir, `lesson-${slug}.md`);
|
|
26503
|
+
if (!(0, import_fs23.existsSync)(cardPath)) this.pruneLessonCards(knowledgeDir, LESSON_CARDS_MAX_PER_AGENT);
|
|
26504
|
+
(0, import_fs23.writeFileSync)(cardPath, content);
|
|
26505
|
+
} catch {
|
|
26506
|
+
}
|
|
26507
|
+
}
|
|
26508
|
+
/** Count-based prune of lesson-*.md only (leaves consensus/session knowledge untouched). */
|
|
26509
|
+
pruneLessonCards(knowledgeDir, maxFiles) {
|
|
26510
|
+
try {
|
|
26511
|
+
const cards = (0, import_fs23.readdirSync)(knowledgeDir).filter((f) => f.startsWith("lesson-") && f.endsWith(".md"));
|
|
26512
|
+
if (cards.length < maxFiles) return;
|
|
26513
|
+
const withMtime = cards.map((f) => {
|
|
26514
|
+
let mtime = 0;
|
|
26515
|
+
try {
|
|
26516
|
+
mtime = (0, import_fs23.statSync)((0, import_path24.join)(knowledgeDir, f)).mtimeMs;
|
|
26517
|
+
} catch {
|
|
26518
|
+
}
|
|
26519
|
+
return { f, mtime };
|
|
26520
|
+
});
|
|
26521
|
+
withMtime.sort((a, b) => a.mtime - b.mtime);
|
|
26522
|
+
const toEvict = withMtime.slice(0, cards.length - (maxFiles - 1));
|
|
26523
|
+
for (const item of toEvict) {
|
|
26524
|
+
try {
|
|
26525
|
+
(0, import_fs23.unlinkSync)((0, import_path24.join)(knowledgeDir, item.f));
|
|
26526
|
+
} catch {
|
|
26527
|
+
}
|
|
26528
|
+
}
|
|
26529
|
+
} catch {
|
|
26530
|
+
}
|
|
26531
|
+
}
|
|
26367
26532
|
/**
|
|
26368
26533
|
* Update task memory importance based on consensus signals.
|
|
26369
26534
|
* High-quality findings get boosted, hallucinations get reduced.
|
|
@@ -32270,6 +32435,10 @@ var init_dispatch_pipeline = __esm({
|
|
|
32270
32435
|
if (consensusFindings.length > 0) {
|
|
32271
32436
|
gossipLog(`\u{1F4CB} pre-fetched ${consensusFindings.length} consensus findings for ${agentId}`);
|
|
32272
32437
|
}
|
|
32438
|
+
const agentCorrections = this.memReader.prefetchAgentCorrectionsText(agentId, task);
|
|
32439
|
+
if (agentCorrections.length > 0) {
|
|
32440
|
+
gossipLog(`\u{1F9E0} pre-fetched ${agentCorrections.length} prior corrections for ${agentId}`);
|
|
32441
|
+
}
|
|
32273
32442
|
const effectiveSkills = resolveEffectiveSkills(agentId, agentSkills, this.skillIndex ?? void 0);
|
|
32274
32443
|
const skillWarnings = this.catalog ? this.catalog.checkCoverage(effectiveSkills, task) : [];
|
|
32275
32444
|
const sessionGossip = this.sessionContext.getSessionGossip();
|
|
@@ -32320,7 +32489,8 @@ var init_dispatch_pipeline = __esm({
|
|
|
32320
32489
|
consensusSummary: options?.consensus,
|
|
32321
32490
|
specReviewContext,
|
|
32322
32491
|
projectStructure: this.getProjectStructure(),
|
|
32323
|
-
consensusFindings: consensusFindings.length > 0 ? consensusFindings : void 0
|
|
32492
|
+
consensusFindings: consensusFindings.length > 0 ? consensusFindings : void 0,
|
|
32493
|
+
agentCorrections: agentCorrections.length > 0 ? agentCorrections : void 0
|
|
32324
32494
|
});
|
|
32325
32495
|
this.taskGraph.recordCreated(taskId, agentId, task, agentSkills);
|
|
32326
32496
|
const entry = {
|
|
@@ -40570,6 +40740,7 @@ __export(src_exports3, {
|
|
|
40570
40740
|
JACCARD_THRESHOLD: () => JACCARD_THRESHOLD,
|
|
40571
40741
|
KEY_REQUIRING_PROVIDERS: () => KEY_REQUIRING_PROVIDERS,
|
|
40572
40742
|
LEDGER_INDEX_FILENAME: () => LEDGER_INDEX_FILENAME,
|
|
40743
|
+
LESSON_CARDS_MAX_PER_AGENT: () => LESSON_CARDS_MAX_PER_AGENT,
|
|
40573
40744
|
LensGenerator: () => LensGenerator,
|
|
40574
40745
|
MAX_ASSEMBLED_PROMPT_CHARS: () => MAX_ASSEMBLED_PROMPT_CHARS,
|
|
40575
40746
|
MAX_CLAIMS_PER_BLOCK: () => MAX_CLAIMS_PER_BLOCK,
|
|
@@ -40613,6 +40784,7 @@ __export(src_exports3, {
|
|
|
40613
40784
|
SkillEngine: () => SkillEngine,
|
|
40614
40785
|
SkillGapTracker: () => SkillGapTracker,
|
|
40615
40786
|
SkillIndex: () => SkillIndex,
|
|
40787
|
+
TERMINAL_LESSON_SIGNALS: () => TERMINAL_LESSON_SIGNALS,
|
|
40616
40788
|
TIMEOUT_DAYS: () => TIMEOUT_DAYS,
|
|
40617
40789
|
TIMEOUT_MS: () => TIMEOUT_MS,
|
|
40618
40790
|
TOOL_SCHEMAS: () => TOOL_SCHEMAS2,
|
|
@@ -40780,6 +40952,7 @@ __export(src_exports3, {
|
|
|
40780
40952
|
verifyClaims: () => verifyClaims,
|
|
40781
40953
|
withResolverLock: () => withResolverLock,
|
|
40782
40954
|
writeLedgerIndex: () => writeLedgerIndex,
|
|
40955
|
+
writeLessonCardsForSignals: () => writeLessonCardsForSignals,
|
|
40783
40956
|
writeOrchestratorRoleMarker: () => writeOrchestratorRoleMarker
|
|
40784
40957
|
});
|
|
40785
40958
|
var init_src4 = __esm({
|
|
@@ -46503,11 +46676,11 @@ var init_routes = __esm({
|
|
|
46503
46676
|
}
|
|
46504
46677
|
if (!existsSync74(reportsDir)) return { reports: [], totalReports: 0, page, pageSize, retractedConsensusIds, roundRetractions };
|
|
46505
46678
|
try {
|
|
46506
|
-
const { statSync:
|
|
46679
|
+
const { statSync: statSync37 } = require("fs");
|
|
46507
46680
|
const allFiles = readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).sort((a, b) => {
|
|
46508
46681
|
try {
|
|
46509
|
-
const aTime =
|
|
46510
|
-
const bTime =
|
|
46682
|
+
const aTime = statSync37((0, import_path80.join)(reportsDir, a)).mtimeMs;
|
|
46683
|
+
const bTime = statSync37((0, import_path80.join)(reportsDir, b)).mtimeMs;
|
|
46511
46684
|
return bTime - aTime;
|
|
46512
46685
|
} catch {
|
|
46513
46686
|
return 0;
|
|
@@ -49375,7 +49548,7 @@ function appendRelayWarning(projectRoot, entry) {
|
|
|
49375
49548
|
}
|
|
49376
49549
|
function checkWorktreeEngaged(startedAt, projectRoot = process.cwd()) {
|
|
49377
49550
|
try {
|
|
49378
|
-
const { readdirSync: readdirSync22, statSync:
|
|
49551
|
+
const { readdirSync: readdirSync22, statSync: statSync37 } = require("fs");
|
|
49379
49552
|
const { join: join93 } = require("path");
|
|
49380
49553
|
const wtDir = join93(projectRoot, ".claude", "worktrees");
|
|
49381
49554
|
let entries;
|
|
@@ -49388,7 +49561,7 @@ function checkWorktreeEngaged(startedAt, projectRoot = process.cwd()) {
|
|
|
49388
49561
|
for (const entry of entries) {
|
|
49389
49562
|
if (!entry.startsWith("agent-")) continue;
|
|
49390
49563
|
try {
|
|
49391
|
-
const st =
|
|
49564
|
+
const st = statSync37(join93(wtDir, entry));
|
|
49392
49565
|
if (st.isDirectory() && st.mtimeMs >= startedAt - 2e3) return true;
|
|
49393
49566
|
} catch {
|
|
49394
49567
|
}
|
|
@@ -81731,7 +81904,7 @@ Ledger: ${ledgerPath2}`
|
|
|
81731
81904
|
} catch {
|
|
81732
81905
|
}
|
|
81733
81906
|
try {
|
|
81734
|
-
const { readdirSync: readdirSync22, statSync:
|
|
81907
|
+
const { readdirSync: readdirSync22, statSync: statSync37, readFileSync: readFileSync70 } = await import("fs");
|
|
81735
81908
|
const { readJsonlWithRotated: readJsonlRotated1506 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
|
|
81736
81909
|
const reportsDir = (0, import_path97.join)(process.cwd(), ".gossip", "consensus-reports");
|
|
81737
81910
|
const perfPath = (0, import_path97.join)(process.cwd(), ".gossip", "agent-performance.jsonl");
|
|
@@ -81742,7 +81915,7 @@ Ledger: ${ledgerPath2}`
|
|
|
81742
81915
|
for (const fname of readdirSync22(reportsDir)) {
|
|
81743
81916
|
if (!fname.endsWith(".json")) continue;
|
|
81744
81917
|
const fpath = (0, import_path97.join)(reportsDir, fname);
|
|
81745
|
-
const st =
|
|
81918
|
+
const st = statSync37(fpath);
|
|
81746
81919
|
if (now - st.mtimeMs > WINDOW_MS3) continue;
|
|
81747
81920
|
try {
|
|
81748
81921
|
const report = JSON.parse(readFileSync70(fpath, "utf8"));
|
|
@@ -82567,6 +82740,7 @@ ${output}` }]
|
|
|
82567
82740
|
agent_id: external_exports.string().describe("Agent being evaluated"),
|
|
82568
82741
|
counterpart_id: external_exports.string().optional().describe("The other agent involved (e.g., who won the disagreement)"),
|
|
82569
82742
|
finding: external_exports.string().describe("Brief description of the finding"),
|
|
82743
|
+
lesson: external_exports.string().optional().describe("Root-cause narrative for a terminal correction signal \u2014 1-2 sentences on why it failed and the check that would have caught it. Written verbatim into the discovering agent's lesson card (issue #642 A)."),
|
|
82570
82744
|
finding_id: external_exports.string().optional().describe("Consensus finding ID \u2014 links this signal to a specific finding in a consensus report. Enables dashboard to resolve UNVERIFIED findings."),
|
|
82571
82745
|
severity: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("Finding severity for impact scoring. If omitted, defaults to medium."),
|
|
82572
82746
|
category: external_exports.string().optional().describe("Finding category for ATI competency profiles (e.g., concurrency, trust_boundaries, injection_vectors, resource_exhaustion, type_safety, error_handling, data_integrity, input_validation)"),
|
|
@@ -83055,6 +83229,11 @@ Uncategorized finding_ids: ${uncategorized.join(", ")}`;
|
|
|
83055
83229
|
if (dedupedConsensus.length > 0) emitRecordConsensusSignals(process.cwd(), dedupedConsensus);
|
|
83056
83230
|
if (dedupedImpl.length > 0) emitRecordImplSignals(process.cwd(), dedupedImpl);
|
|
83057
83231
|
}
|
|
83232
|
+
try {
|
|
83233
|
+
const { writeLessonCardsForSignals: writeLessonCardsForSignals2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
|
|
83234
|
+
writeLessonCardsForSignals2(process.cwd(), signals ?? []);
|
|
83235
|
+
} catch {
|
|
83236
|
+
}
|
|
83058
83237
|
const hallucinationSignals = deduped.filter(
|
|
83059
83238
|
(s) => s.type === "consensus" && s.signal === "hallucination_caught"
|
|
83060
83239
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gossipcat",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
4
4
|
"description": "Multi-agent orchestration for Claude Code — parallel review, consensus, adaptive dispatch",
|
|
5
5
|
"mcpName": "io.github.ataberk-xyz/gossipcat",
|
|
6
6
|
"repository": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "jest --config jest.config.base.js",
|
|
35
35
|
"clean": "rm -rf packages/*/dist apps/*/dist dist-mcp/ dist-dashboard/",
|
|
36
36
|
"postinstall": "node scripts/postinstall.js",
|
|
37
|
-
"build:mcp": "rm -rf dist-mcp && npx esbuild apps/cli/src/mcp-server-sdk.ts --bundle --platform=node --target=node22 --outfile=dist-mcp/mcp-server.js --external:bufferutil --external:utf-8-validate --tsconfig=tsconfig.json && cp -r packages/orchestrator/src/default-skills dist-mcp/default-skills && cp -r packages/orchestrator/src/default-rules dist-mcp/default-rules && cp -r assets dist-mcp/assets && mkdir -p dist-mcp/data && cp data/archetypes.json dist-mcp/data/archetypes.json && chmod +x dist-mcp/mcp-server.js && chmod +x dist-mcp/assets/hooks/worktree-sandbox.sh && chmod +x dist-mcp/assets/hooks/discipline/*.sh",
|
|
37
|
+
"build:mcp": "rm -rf dist-mcp && npx esbuild apps/cli/src/mcp-server-sdk.ts --bundle --platform=node --target=node22 --outfile=dist-mcp/mcp-server.js --external:bufferutil --external:utf-8-validate --external:re2 --tsconfig=tsconfig.json && cp -r packages/orchestrator/src/default-skills dist-mcp/default-skills && cp -r packages/orchestrator/src/default-rules dist-mcp/default-rules && cp -r assets dist-mcp/assets && mkdir -p dist-mcp/data && cp data/archetypes.json dist-mcp/data/archetypes.json && chmod +x dist-mcp/mcp-server.js && chmod +x dist-mcp/assets/hooks/worktree-sandbox.sh && chmod +x dist-mcp/assets/hooks/discipline/*.sh",
|
|
38
38
|
"build:dashboard": "cd packages/dashboard-v2 && npx vite build --outDir ../../dist-dashboard --emptyOutDir",
|
|
39
39
|
"prepublishOnly": "npm run build:all && npm run build:mcp && npm run build:dashboard",
|
|
40
40
|
"gossipcat": "npx ts-node -r tsconfig-paths/register -P tsconfig.json apps/cli/src/index.ts",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@clack/prompts": "^1.1.0",
|
|
57
57
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
58
|
+
"re2": "^1.25.0",
|
|
58
59
|
"tsconfig-paths": "^4.2.0",
|
|
59
60
|
"ws": "^8.20.1"
|
|
60
61
|
},
|