opencode-swarm 6.71.1 → 6.72.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/dist/cli/index.js +11 -3
- package/dist/config/schema.d.ts +6 -0
- package/dist/hooks/knowledge-store.d.ts +10 -1
- package/dist/hooks/knowledge-types.d.ts +9 -1
- package/dist/index.js +140 -6
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -19162,7 +19162,10 @@ var KnowledgeConfigSchema = exports_external.object({
|
|
|
19162
19162
|
min_encounter_score: exports_external.number().min(0).max(1).default(0.1),
|
|
19163
19163
|
initial_encounter_score: exports_external.number().min(0).max(5).default(1),
|
|
19164
19164
|
encounter_increment: exports_external.number().min(0).max(1).default(0.1),
|
|
19165
|
-
max_encounter_score: exports_external.number().min(1).max(20).default(10)
|
|
19165
|
+
max_encounter_score: exports_external.number().min(1).max(20).default(10),
|
|
19166
|
+
default_max_phases: exports_external.number().int().positive().default(10),
|
|
19167
|
+
todo_max_phases: exports_external.number().int().positive().default(3),
|
|
19168
|
+
sweep_enabled: exports_external.boolean().default(true)
|
|
19166
19169
|
});
|
|
19167
19170
|
var CuratorConfigSchema = exports_external.object({
|
|
19168
19171
|
enabled: exports_external.boolean().default(true),
|
|
@@ -33188,7 +33191,8 @@ async function rewriteKnowledge(filePath, entries) {
|
|
|
33188
33191
|
let release = null;
|
|
33189
33192
|
try {
|
|
33190
33193
|
release = await import_proper_lockfile2.default.lock(dir, {
|
|
33191
|
-
retries: { retries:
|
|
33194
|
+
retries: { retries: 5, minTimeout: 100, maxTimeout: 500 },
|
|
33195
|
+
stale: 5000
|
|
33192
33196
|
});
|
|
33193
33197
|
const content = entries.map((e) => JSON.stringify(e)).join(`
|
|
33194
33198
|
`) + (entries.length > 0 ? `
|
|
@@ -33257,6 +33261,8 @@ function computeConfidence(confirmedByCount, autoGenerated) {
|
|
|
33257
33261
|
function inferTags(lesson) {
|
|
33258
33262
|
const lower = lesson.toLowerCase();
|
|
33259
33263
|
const tags = [];
|
|
33264
|
+
if (/(^|\s)(?:todo|remember|don't?(?:\s+)?forget)(?:\s|:|,|$)/i.test(lesson))
|
|
33265
|
+
tags.push("todo");
|
|
33260
33266
|
if (/\b(?:typescript|ts)\b/.test(lower))
|
|
33261
33267
|
tags.push("typescript");
|
|
33262
33268
|
if (/\b(?:javascript|js)\b/.test(lower))
|
|
@@ -33341,6 +33347,7 @@ var VALID_CATEGORIES = new Set([
|
|
|
33341
33347
|
"debugging",
|
|
33342
33348
|
"performance",
|
|
33343
33349
|
"integration",
|
|
33350
|
+
"todo",
|
|
33344
33351
|
"other"
|
|
33345
33352
|
]);
|
|
33346
33353
|
var TECH_REFERENCE_WORDS = new Set([
|
|
@@ -33659,7 +33666,8 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
|
|
|
33659
33666
|
["debugging", "debugging"],
|
|
33660
33667
|
["performance", "performance"],
|
|
33661
33668
|
["integration", "integration"],
|
|
33662
|
-
["other", "other"]
|
|
33669
|
+
["other", "other"],
|
|
33670
|
+
["todo", "todo"]
|
|
33663
33671
|
]);
|
|
33664
33672
|
for (const lesson of lessons) {
|
|
33665
33673
|
const tags = inferTags(lesson);
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -437,6 +437,9 @@ export declare const KnowledgeConfigSchema: z.ZodObject<{
|
|
|
437
437
|
initial_encounter_score: z.ZodDefault<z.ZodNumber>;
|
|
438
438
|
encounter_increment: z.ZodDefault<z.ZodNumber>;
|
|
439
439
|
max_encounter_score: z.ZodDefault<z.ZodNumber>;
|
|
440
|
+
default_max_phases: z.ZodDefault<z.ZodNumber>;
|
|
441
|
+
todo_max_phases: z.ZodDefault<z.ZodNumber>;
|
|
442
|
+
sweep_enabled: z.ZodDefault<z.ZodBoolean>;
|
|
440
443
|
}, z.core.$strip>;
|
|
441
444
|
export type KnowledgeConfig = z.infer<typeof KnowledgeConfigSchema>;
|
|
442
445
|
export declare const CuratorConfigSchema: z.ZodObject<{
|
|
@@ -826,6 +829,9 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
826
829
|
initial_encounter_score: z.ZodDefault<z.ZodNumber>;
|
|
827
830
|
encounter_increment: z.ZodDefault<z.ZodNumber>;
|
|
828
831
|
max_encounter_score: z.ZodDefault<z.ZodNumber>;
|
|
832
|
+
default_max_phases: z.ZodDefault<z.ZodNumber>;
|
|
833
|
+
todo_max_phases: z.ZodDefault<z.ZodNumber>;
|
|
834
|
+
sweep_enabled: z.ZodDefault<z.ZodBoolean>;
|
|
829
835
|
}, z.core.$strip>>;
|
|
830
836
|
curator: z.ZodOptional<z.ZodObject<{
|
|
831
837
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Core storage layer for the opencode-swarm v6.17 two-tier knowledge system. */
|
|
2
|
-
import type { RejectedLesson } from './knowledge-types.js';
|
|
2
|
+
import type { KnowledgeEntryBase, RejectedLesson } from './knowledge-types.js';
|
|
3
3
|
export declare function getPlatformConfigDir(): string;
|
|
4
4
|
export declare function resolveSwarmKnowledgePath(directory: string): string;
|
|
5
5
|
export declare function resolveSwarmRejectedPath(directory: string): string;
|
|
@@ -10,6 +10,15 @@ export declare function readRejectedLessons(directory: string): Promise<Rejected
|
|
|
10
10
|
export declare function appendKnowledge<T>(filePath: string, entry: T): Promise<void>;
|
|
11
11
|
export declare function rewriteKnowledge<T>(filePath: string, entries: T[]): Promise<void>;
|
|
12
12
|
export declare function enforceKnowledgeCap<T>(filePath: string, maxEntries: number): Promise<void>;
|
|
13
|
+
export interface SweepResult {
|
|
14
|
+
scanned: number;
|
|
15
|
+
aged: number;
|
|
16
|
+
archived: number;
|
|
17
|
+
removed: number;
|
|
18
|
+
skipped_promoted: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function sweepAgedEntries<T extends KnowledgeEntryBase>(filePath: string, defaultMaxPhases: number): Promise<SweepResult>;
|
|
21
|
+
export declare function sweepStaleTodos<T extends KnowledgeEntryBase>(filePath: string, todoMaxPhases: number): Promise<SweepResult>;
|
|
13
22
|
export declare function appendRejectedLesson(directory: string, lesson: RejectedLesson): Promise<void>;
|
|
14
23
|
export declare function normalize(text: string): string;
|
|
15
24
|
export declare function wordBigrams(text: string): Set<string>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Type definitions for the opencode-swarm v6.17 two-tier knowledge system. */
|
|
2
|
-
export type KnowledgeCategory = 'process' | 'architecture' | 'tooling' | 'security' | 'testing' | 'debugging' | 'performance' | 'integration' | 'other';
|
|
2
|
+
export type KnowledgeCategory = 'process' | 'architecture' | 'tooling' | 'security' | 'testing' | 'debugging' | 'performance' | 'integration' | 'todo' | 'other';
|
|
3
3
|
export interface PhaseConfirmationRecord {
|
|
4
4
|
phase_number: number;
|
|
5
5
|
confirmed_at: string;
|
|
@@ -32,6 +32,8 @@ export interface KnowledgeEntryBase {
|
|
|
32
32
|
updated_at: string;
|
|
33
33
|
hive_eligible?: boolean;
|
|
34
34
|
auto_generated?: boolean;
|
|
35
|
+
phases_alive?: number;
|
|
36
|
+
max_phases?: number;
|
|
35
37
|
}
|
|
36
38
|
export interface SwarmKnowledgeEntry extends KnowledgeEntryBase {
|
|
37
39
|
tier: 'swarm';
|
|
@@ -103,6 +105,12 @@ export interface KnowledgeConfig {
|
|
|
103
105
|
encounter_increment: number;
|
|
104
106
|
/** Weighted scoring: maximum encounter score cap. Default: 10.0 */
|
|
105
107
|
max_encounter_score: number;
|
|
108
|
+
/** Default N-phase TTL for knowledge entries. Default: 10 */
|
|
109
|
+
default_max_phases: number;
|
|
110
|
+
/** N-phase TTL for 'todo' category entries. Default: 3 */
|
|
111
|
+
todo_max_phases: number;
|
|
112
|
+
/** Enable age-based sweep of knowledge entries. Default: true */
|
|
113
|
+
sweep_enabled: boolean;
|
|
106
114
|
}
|
|
107
115
|
export interface MessageInfo {
|
|
108
116
|
role: string;
|
package/dist/index.js
CHANGED
|
@@ -15101,7 +15101,10 @@ var init_schema = __esm(() => {
|
|
|
15101
15101
|
min_encounter_score: exports_external.number().min(0).max(1).default(0.1),
|
|
15102
15102
|
initial_encounter_score: exports_external.number().min(0).max(5).default(1),
|
|
15103
15103
|
encounter_increment: exports_external.number().min(0).max(1).default(0.1),
|
|
15104
|
-
max_encounter_score: exports_external.number().min(1).max(20).default(10)
|
|
15104
|
+
max_encounter_score: exports_external.number().min(1).max(20).default(10),
|
|
15105
|
+
default_max_phases: exports_external.number().int().positive().default(10),
|
|
15106
|
+
todo_max_phases: exports_external.number().int().positive().default(3),
|
|
15107
|
+
sweep_enabled: exports_external.boolean().default(true)
|
|
15105
15108
|
});
|
|
15106
15109
|
CuratorConfigSchema = exports_external.object({
|
|
15107
15110
|
enabled: exports_external.boolean().default(true),
|
|
@@ -38935,7 +38938,8 @@ async function rewriteKnowledge(filePath, entries) {
|
|
|
38935
38938
|
let release = null;
|
|
38936
38939
|
try {
|
|
38937
38940
|
release = await import_proper_lockfile2.default.lock(dir, {
|
|
38938
|
-
retries: { retries:
|
|
38941
|
+
retries: { retries: 5, minTimeout: 100, maxTimeout: 500 },
|
|
38942
|
+
stale: 5000
|
|
38939
38943
|
});
|
|
38940
38944
|
const content = entries.map((e) => JSON.stringify(e)).join(`
|
|
38941
38945
|
`) + (entries.length > 0 ? `
|
|
@@ -38956,6 +38960,103 @@ async function enforceKnowledgeCap(filePath, maxEntries) {
|
|
|
38956
38960
|
await rewriteKnowledge(filePath, trimmed);
|
|
38957
38961
|
}
|
|
38958
38962
|
}
|
|
38963
|
+
async function sweepAgedEntries(filePath, defaultMaxPhases) {
|
|
38964
|
+
let release = null;
|
|
38965
|
+
try {
|
|
38966
|
+
const dir = path13.dirname(filePath);
|
|
38967
|
+
await mkdir2(dir, { recursive: true });
|
|
38968
|
+
release = await import_proper_lockfile2.default.lock(dir, {
|
|
38969
|
+
retries: { retries: 5, minTimeout: 100, maxTimeout: 500 },
|
|
38970
|
+
stale: 5000
|
|
38971
|
+
});
|
|
38972
|
+
const entries = await readKnowledge(filePath);
|
|
38973
|
+
const result = {
|
|
38974
|
+
scanned: entries.length,
|
|
38975
|
+
aged: 0,
|
|
38976
|
+
archived: 0,
|
|
38977
|
+
removed: 0,
|
|
38978
|
+
skipped_promoted: 0
|
|
38979
|
+
};
|
|
38980
|
+
if (entries.length === 0)
|
|
38981
|
+
return result;
|
|
38982
|
+
const now = new Date().toISOString();
|
|
38983
|
+
let mutated = false;
|
|
38984
|
+
for (const entry of entries) {
|
|
38985
|
+
if (entry.status === "archived")
|
|
38986
|
+
continue;
|
|
38987
|
+
if (entry.status === "promoted") {
|
|
38988
|
+
result.skipped_promoted++;
|
|
38989
|
+
continue;
|
|
38990
|
+
}
|
|
38991
|
+
entry.phases_alive = (entry.phases_alive ?? 0) + 1;
|
|
38992
|
+
result.aged++;
|
|
38993
|
+
mutated = true;
|
|
38994
|
+
const ttl = entry.max_phases ?? defaultMaxPhases;
|
|
38995
|
+
if (entry.phases_alive > ttl) {
|
|
38996
|
+
entry.status = "archived";
|
|
38997
|
+
entry.updated_at = now;
|
|
38998
|
+
result.archived++;
|
|
38999
|
+
}
|
|
39000
|
+
}
|
|
39001
|
+
if (mutated) {
|
|
39002
|
+
const content = entries.map((e) => JSON.stringify(e)).join(`
|
|
39003
|
+
`) + (entries.length > 0 ? `
|
|
39004
|
+
` : "");
|
|
39005
|
+
await writeFile2(filePath, content, "utf-8");
|
|
39006
|
+
}
|
|
39007
|
+
return result;
|
|
39008
|
+
} finally {
|
|
39009
|
+
if (release) {
|
|
39010
|
+
try {
|
|
39011
|
+
await release();
|
|
39012
|
+
} catch {}
|
|
39013
|
+
}
|
|
39014
|
+
}
|
|
39015
|
+
}
|
|
39016
|
+
async function sweepStaleTodos(filePath, todoMaxPhases) {
|
|
39017
|
+
let release = null;
|
|
39018
|
+
try {
|
|
39019
|
+
const dir = path13.dirname(filePath);
|
|
39020
|
+
await mkdir2(dir, { recursive: true });
|
|
39021
|
+
release = await import_proper_lockfile2.default.lock(dir, {
|
|
39022
|
+
retries: { retries: 5, minTimeout: 100, maxTimeout: 500 },
|
|
39023
|
+
stale: 5000
|
|
39024
|
+
});
|
|
39025
|
+
const entries = await readKnowledge(filePath);
|
|
39026
|
+
const result = {
|
|
39027
|
+
scanned: entries.length,
|
|
39028
|
+
aged: 0,
|
|
39029
|
+
archived: 0,
|
|
39030
|
+
removed: 0,
|
|
39031
|
+
skipped_promoted: 0
|
|
39032
|
+
};
|
|
39033
|
+
if (entries.length === 0)
|
|
39034
|
+
return result;
|
|
39035
|
+
const kept = entries.filter((e) => {
|
|
39036
|
+
if (e.category !== "todo" || e.status === "promoted")
|
|
39037
|
+
return true;
|
|
39038
|
+
const age = e.phases_alive ?? 0;
|
|
39039
|
+
if (age > todoMaxPhases) {
|
|
39040
|
+
result.removed++;
|
|
39041
|
+
return false;
|
|
39042
|
+
}
|
|
39043
|
+
return true;
|
|
39044
|
+
});
|
|
39045
|
+
if (result.removed > 0) {
|
|
39046
|
+
const content = kept.map((e) => JSON.stringify(e)).join(`
|
|
39047
|
+
`) + (kept.length > 0 ? `
|
|
39048
|
+
` : "");
|
|
39049
|
+
await writeFile2(filePath, content, "utf-8");
|
|
39050
|
+
}
|
|
39051
|
+
return result;
|
|
39052
|
+
} finally {
|
|
39053
|
+
if (release) {
|
|
39054
|
+
try {
|
|
39055
|
+
await release();
|
|
39056
|
+
} catch {}
|
|
39057
|
+
}
|
|
39058
|
+
}
|
|
39059
|
+
}
|
|
38959
39060
|
async function appendRejectedLesson(directory, lesson) {
|
|
38960
39061
|
const filePath = resolveSwarmRejectedPath(directory);
|
|
38961
39062
|
const existing = await readRejectedLessons(directory);
|
|
@@ -39004,6 +39105,8 @@ function computeConfidence(confirmedByCount, autoGenerated) {
|
|
|
39004
39105
|
function inferTags(lesson) {
|
|
39005
39106
|
const lower = lesson.toLowerCase();
|
|
39006
39107
|
const tags = [];
|
|
39108
|
+
if (/(^|\s)(?:todo|remember|don't?(?:\s+)?forget)(?:\s|:|,|$)/i.test(lesson))
|
|
39109
|
+
tags.push("todo");
|
|
39007
39110
|
if (/\b(?:typescript|ts)\b/.test(lower))
|
|
39008
39111
|
tags.push("typescript");
|
|
39009
39112
|
if (/\b(?:javascript|js)\b/.test(lower))
|
|
@@ -39142,7 +39245,7 @@ async function readMergedKnowledge(directory, config3, context) {
|
|
|
39142
39245
|
});
|
|
39143
39246
|
}
|
|
39144
39247
|
const scopeFilter = config3.scope_filter ?? ["global"];
|
|
39145
|
-
const filtered = merged.filter((entry) => scopeFilter.some((pattern) => (entry.scope ?? "global") === pattern));
|
|
39248
|
+
const filtered = merged.filter((entry) => scopeFilter.some((pattern) => (entry.scope ?? "global") === pattern) && entry.status !== "archived");
|
|
39146
39249
|
const ranked = filtered.map((entry) => {
|
|
39147
39250
|
let categoryScore = 0;
|
|
39148
39251
|
if (context?.currentPhase) {
|
|
@@ -39562,6 +39665,7 @@ var init_knowledge_validator = __esm(() => {
|
|
|
39562
39665
|
"debugging",
|
|
39563
39666
|
"performance",
|
|
39564
39667
|
"integration",
|
|
39668
|
+
"todo",
|
|
39565
39669
|
"other"
|
|
39566
39670
|
]);
|
|
39567
39671
|
TECH_REFERENCE_WORDS = new Set([
|
|
@@ -39759,7 +39863,8 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
|
|
|
39759
39863
|
["debugging", "debugging"],
|
|
39760
39864
|
["performance", "performance"],
|
|
39761
39865
|
["integration", "integration"],
|
|
39762
|
-
["other", "other"]
|
|
39866
|
+
["other", "other"],
|
|
39867
|
+
["todo", "todo"]
|
|
39763
39868
|
]);
|
|
39764
39869
|
for (const lesson of lessons) {
|
|
39765
39870
|
const tags = inferTags(lesson);
|
|
@@ -73586,7 +73691,7 @@ var knowledge_query = createSwarmTool({
|
|
|
73586
73691
|
args: {
|
|
73587
73692
|
tier: tool.schema.string().optional().describe("Knowledge tier to query: 'swarm', 'hive', or 'all' (default: 'all')"),
|
|
73588
73693
|
status: tool.schema.string().optional().describe("Filter by status: 'candidate', 'established', or 'promoted'"),
|
|
73589
|
-
category: tool.schema.string().optional().describe("Filter by category: 'process', 'architecture', 'tooling', 'security', 'testing', 'debugging', 'performance', 'integration', or 'other'"),
|
|
73694
|
+
category: tool.schema.string().optional().describe("Filter by category: 'process', 'architecture', 'tooling', 'security', 'testing', 'debugging', 'performance', 'integration', 'todo', or 'other'"),
|
|
73590
73695
|
min_score: tool.schema.number().optional().describe("Minimum confidence score filter (0.0-1.0)"),
|
|
73591
73696
|
limit: tool.schema.number().optional().describe(`Maximum number of results to return (default: ${DEFAULT_LIMIT}, max: 100)`)
|
|
73592
73697
|
},
|
|
@@ -73749,6 +73854,7 @@ import * as fs60 from "fs";
|
|
|
73749
73854
|
import * as path74 from "path";
|
|
73750
73855
|
init_knowledge_curator();
|
|
73751
73856
|
init_knowledge_reader();
|
|
73857
|
+
init_knowledge_store();
|
|
73752
73858
|
init_review_receipt();
|
|
73753
73859
|
init_utils2();
|
|
73754
73860
|
init_checkpoint3();
|
|
@@ -74058,7 +74164,13 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
74058
74164
|
safeWarn(`[phase_complete] Drift verifier error (non-blocking):`, driftError);
|
|
74059
74165
|
}
|
|
74060
74166
|
}
|
|
74061
|
-
|
|
74167
|
+
let knowledgeConfig;
|
|
74168
|
+
try {
|
|
74169
|
+
knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
|
|
74170
|
+
} catch (parseErr) {
|
|
74171
|
+
warnings.push(`Knowledge config validation failed: ${String(parseErr)}`);
|
|
74172
|
+
knowledgeConfig = KnowledgeConfigSchema.parse({});
|
|
74173
|
+
}
|
|
74062
74174
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
74063
74175
|
try {
|
|
74064
74176
|
const projectName = path74.basename(dir);
|
|
@@ -74280,6 +74392,28 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
74280
74392
|
telemetry.phaseChanged(contributorSessionId, oldPhase ?? 0, phase);
|
|
74281
74393
|
}
|
|
74282
74394
|
}
|
|
74395
|
+
try {
|
|
74396
|
+
if (knowledgeConfig.sweep_enabled) {
|
|
74397
|
+
const swarmPath = resolveSwarmKnowledgePath(dir);
|
|
74398
|
+
await sweepAgedEntries(swarmPath, knowledgeConfig.default_max_phases);
|
|
74399
|
+
await sweepStaleTodos(swarmPath, knowledgeConfig.todo_max_phases);
|
|
74400
|
+
if (knowledgeConfig.hive_enabled) {
|
|
74401
|
+
const hivePath = resolveHiveKnowledgePath();
|
|
74402
|
+
await sweepAgedEntries(hivePath, knowledgeConfig.default_max_phases);
|
|
74403
|
+
await sweepStaleTodos(hivePath, knowledgeConfig.todo_max_phases);
|
|
74404
|
+
}
|
|
74405
|
+
}
|
|
74406
|
+
} catch (err2) {
|
|
74407
|
+
let detail = String(err2);
|
|
74408
|
+
if (detail.includes("ELOCKED")) {
|
|
74409
|
+
detail = "lock timeout (stale lock detected)";
|
|
74410
|
+
} else if (detail.includes("ENOSPC")) {
|
|
74411
|
+
detail = "disk full";
|
|
74412
|
+
} else if (detail.includes("EACCES")) {
|
|
74413
|
+
detail = "permission denied";
|
|
74414
|
+
}
|
|
74415
|
+
warnings.push(`Knowledge sweep failed for phase ${phase}: ${detail}`);
|
|
74416
|
+
}
|
|
74283
74417
|
try {
|
|
74284
74418
|
const plan = await loadPlan(dir);
|
|
74285
74419
|
if (plan === null) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.72.0",
|
|
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",
|