opencode-swarm 7.79.5 → 7.79.7
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/cli/index.js +118 -19
- package/dist/hooks/knowledge-validator.d.ts +16 -0
- package/dist/index.js +126 -33
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "opencode-swarm",
|
|
55
|
-
version: "7.79.
|
|
55
|
+
version: "7.79.7",
|
|
56
56
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
57
57
|
main: "dist/index.js",
|
|
58
58
|
types: "dist/index.d.ts",
|
|
@@ -39424,6 +39424,51 @@ import * as path18 from "path";
|
|
|
39424
39424
|
function normalizeText(text) {
|
|
39425
39425
|
return text.normalize("NFKC").toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
39426
39426
|
}
|
|
39427
|
+
function extractContextWords(text, word, contextWindow = 3) {
|
|
39428
|
+
const words = text.split(" ");
|
|
39429
|
+
const context = new Set;
|
|
39430
|
+
if (!word.includes(" ")) {
|
|
39431
|
+
let from = 0;
|
|
39432
|
+
let idx = words.indexOf(word, from);
|
|
39433
|
+
while (idx !== -1) {
|
|
39434
|
+
const start = Math.max(0, idx - contextWindow);
|
|
39435
|
+
const end = Math.min(words.length, idx + contextWindow + 1);
|
|
39436
|
+
for (let i2 = start;i2 < end; i2++) {
|
|
39437
|
+
if (i2 !== idx && words[i2] && words[i2].length > 0) {
|
|
39438
|
+
context.add(words[i2]);
|
|
39439
|
+
}
|
|
39440
|
+
}
|
|
39441
|
+
from = idx + 1;
|
|
39442
|
+
idx = words.indexOf(word, from);
|
|
39443
|
+
}
|
|
39444
|
+
return context;
|
|
39445
|
+
}
|
|
39446
|
+
const termLen = word.split(" ").length;
|
|
39447
|
+
let i = 0;
|
|
39448
|
+
while (i <= words.length - termLen) {
|
|
39449
|
+
const slice = words.slice(i, i + termLen).join(" ");
|
|
39450
|
+
if (slice === word) {
|
|
39451
|
+
const start = Math.max(0, i - contextWindow);
|
|
39452
|
+
const end = Math.min(words.length, i + termLen + contextWindow);
|
|
39453
|
+
for (let j = start;j < end; j++) {
|
|
39454
|
+
if (j < i || j >= i + termLen) {
|
|
39455
|
+
if (words[j] && words[j].length > 0) {
|
|
39456
|
+
context.add(words[j]);
|
|
39457
|
+
}
|
|
39458
|
+
}
|
|
39459
|
+
}
|
|
39460
|
+
i += termLen;
|
|
39461
|
+
} else {
|
|
39462
|
+
i += 1;
|
|
39463
|
+
}
|
|
39464
|
+
}
|
|
39465
|
+
return context;
|
|
39466
|
+
}
|
|
39467
|
+
function hasSignificantOverlap(set1, set22) {
|
|
39468
|
+
if (set1.size === 0 || set22.size === 0)
|
|
39469
|
+
return false;
|
|
39470
|
+
return [...set1].some((word) => set22.has(word));
|
|
39471
|
+
}
|
|
39427
39472
|
function detectContradiction(candidate, existingLessons) {
|
|
39428
39473
|
const candidateTags = inferTags(candidate);
|
|
39429
39474
|
if (candidateTags.length === 0)
|
|
@@ -39436,10 +39481,20 @@ function detectContradiction(candidate, existingLessons) {
|
|
|
39436
39481
|
continue;
|
|
39437
39482
|
const existingNorm = normalizeText(existing);
|
|
39438
39483
|
for (const [wordA, wordB] of NEGATION_PAIRS) {
|
|
39439
|
-
|
|
39440
|
-
|
|
39441
|
-
|
|
39442
|
-
|
|
39484
|
+
if (candidateNorm.includes(wordA) && existingNorm.includes(wordB)) {
|
|
39485
|
+
const contextA = extractContextWords(candidateNorm, wordA);
|
|
39486
|
+
const contextB = extractContextWords(existingNorm, wordB);
|
|
39487
|
+
if (hasSignificantOverlap(contextA, contextB)) {
|
|
39488
|
+
return true;
|
|
39489
|
+
}
|
|
39490
|
+
}
|
|
39491
|
+
if (candidateNorm.includes(wordB) && existingNorm.includes(wordA)) {
|
|
39492
|
+
const contextB = extractContextWords(candidateNorm, wordB);
|
|
39493
|
+
const contextA = extractContextWords(existingNorm, wordA);
|
|
39494
|
+
if (hasSignificantOverlap(contextA, contextB)) {
|
|
39495
|
+
return true;
|
|
39496
|
+
}
|
|
39497
|
+
}
|
|
39443
39498
|
}
|
|
39444
39499
|
}
|
|
39445
39500
|
return false;
|
|
@@ -40435,10 +40490,12 @@ function isSkillMaturityEligible(entry, opts, outcomes = entry.retrieval_outcome
|
|
|
40435
40490
|
if (outcomeSignal < 0)
|
|
40436
40491
|
return false;
|
|
40437
40492
|
const strongOutcomes = hasStrongSkillOutcomeRecord(outcomes);
|
|
40493
|
+
if (outcomeSignal > 0 && strongOutcomes)
|
|
40494
|
+
return true;
|
|
40438
40495
|
if (entry.confidence < opts.minConfidence && !strongOutcomes)
|
|
40439
40496
|
return false;
|
|
40440
|
-
const
|
|
40441
|
-
return
|
|
40497
|
+
const distinctPhases = new Set((entry.confirmed_by ?? []).map((c) => c.phase_number).filter((p) => typeof p === "number")).size;
|
|
40498
|
+
return distinctPhases >= opts.minConfirmations || strongOutcomes;
|
|
40442
40499
|
}
|
|
40443
40500
|
function jaccardSimilarity(setA, setB) {
|
|
40444
40501
|
const normA = setA.map((s) => s.toLowerCase());
|
|
@@ -41771,12 +41828,52 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
41771
41828
|
if (!_internals17.existsSync(resolved)) {
|
|
41772
41829
|
return { pruned: 0, remaining: 0 };
|
|
41773
41830
|
}
|
|
41774
|
-
const
|
|
41775
|
-
|
|
41831
|
+
const raw = _internals17.readFileSync(resolved, "utf-8");
|
|
41832
|
+
const lines = raw.split(`
|
|
41833
|
+
`);
|
|
41834
|
+
const entries = [];
|
|
41835
|
+
const preservedMarkers = [];
|
|
41836
|
+
for (const line of lines) {
|
|
41837
|
+
const trimmed = line.trim();
|
|
41838
|
+
if (!trimmed)
|
|
41839
|
+
continue;
|
|
41840
|
+
try {
|
|
41841
|
+
const parsed = JSON.parse(trimmed);
|
|
41842
|
+
const marker = parseFeedbackMarker(parsed);
|
|
41843
|
+
if (marker) {
|
|
41844
|
+
preservedMarkers.push(trimmed);
|
|
41845
|
+
continue;
|
|
41846
|
+
}
|
|
41847
|
+
const entry = parseSkillUsageEntry(parsed);
|
|
41848
|
+
if (entry) {
|
|
41849
|
+
entries.push(entry);
|
|
41850
|
+
}
|
|
41851
|
+
} catch {}
|
|
41852
|
+
}
|
|
41853
|
+
if (entries.length === 0) {
|
|
41854
|
+
if (preservedMarkers.length > 0) {
|
|
41855
|
+
const dir2 = path23.dirname(resolved);
|
|
41856
|
+
const tmpPath2 = path23.join(dir2, `skill-usage-${Date.now()}.tmp`);
|
|
41857
|
+
const content2 = preservedMarkers.join(`
|
|
41858
|
+
`).concat(preservedMarkers.length > 0 ? `
|
|
41859
|
+
` : "");
|
|
41860
|
+
try {
|
|
41861
|
+
_internals17.writeFileSync(tmpPath2, content2, "utf-8");
|
|
41862
|
+
_internals17.renameSync(tmpPath2, resolved);
|
|
41863
|
+
} catch (writeErr) {
|
|
41864
|
+
const msg = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
41865
|
+
try {
|
|
41866
|
+
if (_internals17.existsSync(tmpPath2)) {
|
|
41867
|
+
_internals17.writeFileSync(tmpPath2, "", "utf-8");
|
|
41868
|
+
}
|
|
41869
|
+
} catch {}
|
|
41870
|
+
return { pruned: 0, remaining: 0, error: msg };
|
|
41871
|
+
}
|
|
41872
|
+
}
|
|
41776
41873
|
return { pruned: 0, remaining: 0 };
|
|
41777
41874
|
}
|
|
41778
41875
|
const groups = new Map;
|
|
41779
|
-
for (const entry of
|
|
41876
|
+
for (const entry of entries) {
|
|
41780
41877
|
const list = groups.get(entry.skillPath);
|
|
41781
41878
|
if (list)
|
|
41782
41879
|
list.push(entry);
|
|
@@ -41785,22 +41882,24 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
41785
41882
|
}
|
|
41786
41883
|
let pruned = 0;
|
|
41787
41884
|
const surviving = [];
|
|
41788
|
-
groups.forEach((
|
|
41789
|
-
if (
|
|
41790
|
-
surviving.push(...
|
|
41885
|
+
groups.forEach((skillEntries) => {
|
|
41886
|
+
if (skillEntries.length <= maxEntriesPerSkill) {
|
|
41887
|
+
surviving.push(...skillEntries);
|
|
41791
41888
|
return;
|
|
41792
41889
|
}
|
|
41793
|
-
|
|
41794
|
-
const kept =
|
|
41795
|
-
pruned +=
|
|
41890
|
+
skillEntries.sort((a, b) => b.timestamp > a.timestamp ? 1 : b.timestamp < a.timestamp ? -1 : 0);
|
|
41891
|
+
const kept = skillEntries.slice(0, maxEntriesPerSkill);
|
|
41892
|
+
pruned += skillEntries.length - kept.length;
|
|
41796
41893
|
surviving.push(...kept);
|
|
41797
41894
|
});
|
|
41798
41895
|
if (pruned === 0) {
|
|
41799
|
-
return { pruned: 0, remaining:
|
|
41896
|
+
return { pruned: 0, remaining: entries.length };
|
|
41800
41897
|
}
|
|
41801
41898
|
const dir = path23.dirname(resolved);
|
|
41802
41899
|
const tmpPath = path23.join(dir, `skill-usage-${Date.now()}.tmp`);
|
|
41803
|
-
const
|
|
41900
|
+
const entryLines = surviving.map((e) => JSON.stringify(e));
|
|
41901
|
+
const allLines = [...entryLines, ...preservedMarkers];
|
|
41902
|
+
const content = allLines.join(`
|
|
41804
41903
|
`).concat(`
|
|
41805
41904
|
`);
|
|
41806
41905
|
try {
|
|
@@ -41813,7 +41912,7 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
41813
41912
|
_internals17.writeFileSync(tmpPath, "", "utf-8");
|
|
41814
41913
|
}
|
|
41815
41914
|
} catch {}
|
|
41816
|
-
return { pruned: 0, remaining:
|
|
41915
|
+
return { pruned: 0, remaining: entries.length, error: msg };
|
|
41817
41916
|
}
|
|
41818
41917
|
return { pruned, remaining: surviving.length };
|
|
41819
41918
|
}
|
|
@@ -12,6 +12,20 @@ export declare const DANGEROUS_COMMAND_PATTERNS: RegExp[];
|
|
|
12
12
|
export declare const SECURITY_DEGRADING_PATTERNS: RegExp[];
|
|
13
13
|
export declare const INVISIBLE_FORMAT_CHARS: RegExp;
|
|
14
14
|
export declare const INJECTION_PATTERNS: RegExp[];
|
|
15
|
+
/**
|
|
16
|
+
* Extract context words around each occurrence of a target word (single tokens within a window).
|
|
17
|
+
* Context window is 3 words before and after, excluding the target word itself.
|
|
18
|
+
* Handles multi-word terms (e.g. "must not", "don't use") by scanning word slices.
|
|
19
|
+
*
|
|
20
|
+
* Note: this is an exact-word-match heuristic. Synonyms (e.g. "use" / "utilize")
|
|
21
|
+
* will not match across lessons. The 3-token window is bounded; more distant
|
|
22
|
+
* negation attachments will not be detected as contradictions.
|
|
23
|
+
*/
|
|
24
|
+
declare function extractContextWords(text: string, word: string, contextWindow?: number): Set<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Check if two sets of words have significant overlap (at least one word in common).
|
|
27
|
+
*/
|
|
28
|
+
declare function hasSignificantOverlap(set1: Set<string>, set2: Set<string>): boolean;
|
|
15
29
|
export declare function validateLesson(candidate: string, existingLessons: string[], meta: {
|
|
16
30
|
category: KnowledgeCategory;
|
|
17
31
|
scope: string;
|
|
@@ -90,4 +104,6 @@ export declare const _internals: {
|
|
|
90
104
|
auditEntryHealth: typeof auditEntryHealth;
|
|
91
105
|
quarantineEntry: typeof quarantineEntry;
|
|
92
106
|
restoreEntry: typeof restoreEntry;
|
|
107
|
+
extractContextWords: typeof extractContextWords;
|
|
108
|
+
hasSignificantOverlap: typeof hasSignificantOverlap;
|
|
93
109
|
};
|
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ var package_default;
|
|
|
69
69
|
var init_package = __esm(() => {
|
|
70
70
|
package_default = {
|
|
71
71
|
name: "opencode-swarm",
|
|
72
|
-
version: "7.79.
|
|
72
|
+
version: "7.79.7",
|
|
73
73
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
74
74
|
main: "dist/index.js",
|
|
75
75
|
types: "dist/index.d.ts",
|
|
@@ -61771,6 +61771,51 @@ import * as path36 from "node:path";
|
|
|
61771
61771
|
function normalizeText(text) {
|
|
61772
61772
|
return text.normalize("NFKC").toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
61773
61773
|
}
|
|
61774
|
+
function extractContextWords(text, word, contextWindow = 3) {
|
|
61775
|
+
const words = text.split(" ");
|
|
61776
|
+
const context = new Set;
|
|
61777
|
+
if (!word.includes(" ")) {
|
|
61778
|
+
let from = 0;
|
|
61779
|
+
let idx = words.indexOf(word, from);
|
|
61780
|
+
while (idx !== -1) {
|
|
61781
|
+
const start2 = Math.max(0, idx - contextWindow);
|
|
61782
|
+
const end = Math.min(words.length, idx + contextWindow + 1);
|
|
61783
|
+
for (let i3 = start2;i3 < end; i3++) {
|
|
61784
|
+
if (i3 !== idx && words[i3] && words[i3].length > 0) {
|
|
61785
|
+
context.add(words[i3]);
|
|
61786
|
+
}
|
|
61787
|
+
}
|
|
61788
|
+
from = idx + 1;
|
|
61789
|
+
idx = words.indexOf(word, from);
|
|
61790
|
+
}
|
|
61791
|
+
return context;
|
|
61792
|
+
}
|
|
61793
|
+
const termLen = word.split(" ").length;
|
|
61794
|
+
let i2 = 0;
|
|
61795
|
+
while (i2 <= words.length - termLen) {
|
|
61796
|
+
const slice = words.slice(i2, i2 + termLen).join(" ");
|
|
61797
|
+
if (slice === word) {
|
|
61798
|
+
const start2 = Math.max(0, i2 - contextWindow);
|
|
61799
|
+
const end = Math.min(words.length, i2 + termLen + contextWindow);
|
|
61800
|
+
for (let j = start2;j < end; j++) {
|
|
61801
|
+
if (j < i2 || j >= i2 + termLen) {
|
|
61802
|
+
if (words[j] && words[j].length > 0) {
|
|
61803
|
+
context.add(words[j]);
|
|
61804
|
+
}
|
|
61805
|
+
}
|
|
61806
|
+
}
|
|
61807
|
+
i2 += termLen;
|
|
61808
|
+
} else {
|
|
61809
|
+
i2 += 1;
|
|
61810
|
+
}
|
|
61811
|
+
}
|
|
61812
|
+
return context;
|
|
61813
|
+
}
|
|
61814
|
+
function hasSignificantOverlap(set1, set22) {
|
|
61815
|
+
if (set1.size === 0 || set22.size === 0)
|
|
61816
|
+
return false;
|
|
61817
|
+
return [...set1].some((word) => set22.has(word));
|
|
61818
|
+
}
|
|
61774
61819
|
function detectContradiction(candidate, existingLessons) {
|
|
61775
61820
|
const candidateTags = inferTags(candidate);
|
|
61776
61821
|
if (candidateTags.length === 0)
|
|
@@ -61783,10 +61828,20 @@ function detectContradiction(candidate, existingLessons) {
|
|
|
61783
61828
|
continue;
|
|
61784
61829
|
const existingNorm = normalizeText(existing);
|
|
61785
61830
|
for (const [wordA, wordB] of NEGATION_PAIRS) {
|
|
61786
|
-
|
|
61787
|
-
|
|
61788
|
-
|
|
61789
|
-
|
|
61831
|
+
if (candidateNorm.includes(wordA) && existingNorm.includes(wordB)) {
|
|
61832
|
+
const contextA = extractContextWords(candidateNorm, wordA);
|
|
61833
|
+
const contextB = extractContextWords(existingNorm, wordB);
|
|
61834
|
+
if (hasSignificantOverlap(contextA, contextB)) {
|
|
61835
|
+
return true;
|
|
61836
|
+
}
|
|
61837
|
+
}
|
|
61838
|
+
if (candidateNorm.includes(wordB) && existingNorm.includes(wordA)) {
|
|
61839
|
+
const contextB = extractContextWords(candidateNorm, wordB);
|
|
61840
|
+
const contextA = extractContextWords(existingNorm, wordA);
|
|
61841
|
+
if (hasSignificantOverlap(contextA, contextB)) {
|
|
61842
|
+
return true;
|
|
61843
|
+
}
|
|
61844
|
+
}
|
|
61790
61845
|
}
|
|
61791
61846
|
}
|
|
61792
61847
|
return false;
|
|
@@ -62806,10 +62861,12 @@ function isSkillMaturityEligible(entry, opts, outcomes = entry.retrieval_outcome
|
|
|
62806
62861
|
if (outcomeSignal < 0)
|
|
62807
62862
|
return false;
|
|
62808
62863
|
const strongOutcomes = hasStrongSkillOutcomeRecord(outcomes);
|
|
62864
|
+
if (outcomeSignal > 0 && strongOutcomes)
|
|
62865
|
+
return true;
|
|
62809
62866
|
if (entry.confidence < opts.minConfidence && !strongOutcomes)
|
|
62810
62867
|
return false;
|
|
62811
|
-
const
|
|
62812
|
-
return
|
|
62868
|
+
const distinctPhases = new Set((entry.confirmed_by ?? []).map((c) => c.phase_number).filter((p) => typeof p === "number")).size;
|
|
62869
|
+
return distinctPhases >= opts.minConfirmations || strongOutcomes;
|
|
62813
62870
|
}
|
|
62814
62871
|
function jaccardSimilarity(setA, setB) {
|
|
62815
62872
|
const normA = setA.map((s) => s.toLowerCase());
|
|
@@ -64410,12 +64467,52 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
64410
64467
|
if (!_internals27.existsSync(resolved)) {
|
|
64411
64468
|
return { pruned: 0, remaining: 0 };
|
|
64412
64469
|
}
|
|
64413
|
-
const
|
|
64414
|
-
|
|
64470
|
+
const raw = _internals27.readFileSync(resolved, "utf-8");
|
|
64471
|
+
const lines = raw.split(`
|
|
64472
|
+
`);
|
|
64473
|
+
const entries = [];
|
|
64474
|
+
const preservedMarkers = [];
|
|
64475
|
+
for (const line of lines) {
|
|
64476
|
+
const trimmed = line.trim();
|
|
64477
|
+
if (!trimmed)
|
|
64478
|
+
continue;
|
|
64479
|
+
try {
|
|
64480
|
+
const parsed = JSON.parse(trimmed);
|
|
64481
|
+
const marker = parseFeedbackMarker(parsed);
|
|
64482
|
+
if (marker) {
|
|
64483
|
+
preservedMarkers.push(trimmed);
|
|
64484
|
+
continue;
|
|
64485
|
+
}
|
|
64486
|
+
const entry = parseSkillUsageEntry(parsed);
|
|
64487
|
+
if (entry) {
|
|
64488
|
+
entries.push(entry);
|
|
64489
|
+
}
|
|
64490
|
+
} catch {}
|
|
64491
|
+
}
|
|
64492
|
+
if (entries.length === 0) {
|
|
64493
|
+
if (preservedMarkers.length > 0) {
|
|
64494
|
+
const dir2 = path41.dirname(resolved);
|
|
64495
|
+
const tmpPath2 = path41.join(dir2, `skill-usage-${Date.now()}.tmp`);
|
|
64496
|
+
const content2 = preservedMarkers.join(`
|
|
64497
|
+
`).concat(preservedMarkers.length > 0 ? `
|
|
64498
|
+
` : "");
|
|
64499
|
+
try {
|
|
64500
|
+
_internals27.writeFileSync(tmpPath2, content2, "utf-8");
|
|
64501
|
+
_internals27.renameSync(tmpPath2, resolved);
|
|
64502
|
+
} catch (writeErr) {
|
|
64503
|
+
const msg = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
64504
|
+
try {
|
|
64505
|
+
if (_internals27.existsSync(tmpPath2)) {
|
|
64506
|
+
_internals27.writeFileSync(tmpPath2, "", "utf-8");
|
|
64507
|
+
}
|
|
64508
|
+
} catch {}
|
|
64509
|
+
return { pruned: 0, remaining: 0, error: msg };
|
|
64510
|
+
}
|
|
64511
|
+
}
|
|
64415
64512
|
return { pruned: 0, remaining: 0 };
|
|
64416
64513
|
}
|
|
64417
64514
|
const groups = new Map;
|
|
64418
|
-
for (const entry of
|
|
64515
|
+
for (const entry of entries) {
|
|
64419
64516
|
const list = groups.get(entry.skillPath);
|
|
64420
64517
|
if (list)
|
|
64421
64518
|
list.push(entry);
|
|
@@ -64424,22 +64521,24 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
64424
64521
|
}
|
|
64425
64522
|
let pruned = 0;
|
|
64426
64523
|
const surviving = [];
|
|
64427
|
-
groups.forEach((
|
|
64428
|
-
if (
|
|
64429
|
-
surviving.push(...
|
|
64524
|
+
groups.forEach((skillEntries) => {
|
|
64525
|
+
if (skillEntries.length <= maxEntriesPerSkill) {
|
|
64526
|
+
surviving.push(...skillEntries);
|
|
64430
64527
|
return;
|
|
64431
64528
|
}
|
|
64432
|
-
|
|
64433
|
-
const kept =
|
|
64434
|
-
pruned +=
|
|
64529
|
+
skillEntries.sort((a, b) => b.timestamp > a.timestamp ? 1 : b.timestamp < a.timestamp ? -1 : 0);
|
|
64530
|
+
const kept = skillEntries.slice(0, maxEntriesPerSkill);
|
|
64531
|
+
pruned += skillEntries.length - kept.length;
|
|
64435
64532
|
surviving.push(...kept);
|
|
64436
64533
|
});
|
|
64437
64534
|
if (pruned === 0) {
|
|
64438
|
-
return { pruned: 0, remaining:
|
|
64535
|
+
return { pruned: 0, remaining: entries.length };
|
|
64439
64536
|
}
|
|
64440
64537
|
const dir = path41.dirname(resolved);
|
|
64441
64538
|
const tmpPath = path41.join(dir, `skill-usage-${Date.now()}.tmp`);
|
|
64442
|
-
const
|
|
64539
|
+
const entryLines = surviving.map((e) => JSON.stringify(e));
|
|
64540
|
+
const allLines = [...entryLines, ...preservedMarkers];
|
|
64541
|
+
const content = allLines.join(`
|
|
64443
64542
|
`).concat(`
|
|
64444
64543
|
`);
|
|
64445
64544
|
try {
|
|
@@ -64452,7 +64551,7 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
64452
64551
|
_internals27.writeFileSync(tmpPath, "", "utf-8");
|
|
64453
64552
|
}
|
|
64454
64553
|
} catch {}
|
|
64455
|
-
return { pruned: 0, remaining:
|
|
64554
|
+
return { pruned: 0, remaining: entries.length, error: msg };
|
|
64456
64555
|
}
|
|
64457
64556
|
return { pruned, remaining: surviving.length };
|
|
64458
64557
|
}
|
|
@@ -65362,7 +65461,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config3, know
|
|
|
65362
65461
|
try {
|
|
65363
65462
|
const skillModule = await Promise.resolve().then(() => (init_skill_generator(), exports_skill_generator));
|
|
65364
65463
|
for (const cand of skillCandidates) {
|
|
65365
|
-
if (cand.confidence < (config3.min_skill_confidence ??
|
|
65464
|
+
if (cand.confidence < (config3.min_skill_confidence ?? DEFAULT_SKILL_MIN_CONFIDENCE)) {
|
|
65366
65465
|
continue;
|
|
65367
65466
|
}
|
|
65368
65467
|
await skillModule.generateSkills({
|
|
@@ -98327,6 +98426,11 @@ Every listed directive ID MUST appear exactly once. If a directive carries a ver
|
|
|
98327
98426
|
FIXES: required changes if rejected
|
|
98328
98427
|
Use INFO only inside ISSUES for non-blocking suggestions. RISK reflects the highest blocking severity, so it never uses INFO.
|
|
98329
98428
|
|
|
98429
|
+
## OUTPUT ORDER FOR SKILL COMPLIANCE (when applicable)
|
|
98430
|
+
When SKILLS_USED_BY_CODER is provided, output TASK: immediately followed by SKILL_COMPLIANCE to ensure proper attribution:
|
|
98431
|
+
TASK: <task-id-or-unknown>
|
|
98432
|
+
SKILL_COMPLIANCE: <verdict> — <details>
|
|
98433
|
+
|
|
98330
98434
|
## RULES
|
|
98331
98435
|
- Be specific with line numbers
|
|
98332
98436
|
- Only flag real issues, not theoretical
|
|
@@ -131064,7 +131168,7 @@ async function withTurboStateLock(directory, sessionID, fn2, timeoutMs = 30000)
|
|
|
131064
131168
|
} catch (acquireErr) {
|
|
131065
131169
|
console.warn(`[lean-turbo] state lock acquisition error for ${sessionID} (${lockPath}), will retry: ${acquireErr instanceof Error ? acquireErr.message : String(acquireErr)}`);
|
|
131066
131170
|
}
|
|
131067
|
-
if (result
|
|
131171
|
+
if (result?.acquired) {
|
|
131068
131172
|
const lock = result.lock;
|
|
131069
131173
|
try {
|
|
131070
131174
|
return await fn2();
|
|
@@ -134666,18 +134770,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
134666
134770
|
safeWarn("[phase_complete] Design-doc drift check error (non-blocking):", docDriftError);
|
|
134667
134771
|
}
|
|
134668
134772
|
try {
|
|
134669
|
-
const
|
|
134670
|
-
let sinceTimestamp;
|
|
134671
|
-
try {
|
|
134672
|
-
const markerData = JSON.parse(fs111.readFileSync(markerPath, "utf-8"));
|
|
134673
|
-
sinceTimestamp = markerData.lastProcessedTimestamp;
|
|
134674
|
-
} catch {}
|
|
134675
|
-
const feedbackResult = await applySkillUsageFeedback(dir, {
|
|
134676
|
-
sinceTimestamp
|
|
134677
|
-
});
|
|
134678
|
-
try {
|
|
134679
|
-
fs111.writeFileSync(markerPath, JSON.stringify({ lastProcessedTimestamp: new Date().toISOString() }), "utf-8");
|
|
134680
|
-
} catch {}
|
|
134773
|
+
const feedbackResult = await applySkillUsageFeedback(dir);
|
|
134681
134774
|
if (feedbackResult.processed > 0) {
|
|
134682
134775
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
134683
134776
|
if (sessionState) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.79.
|
|
3
|
+
"version": "7.79.7",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|