opencode-ultra 0.7.7 → 0.8.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/index.js +251 -2
- package/dist/tools/evolve-filter.d.ts +36 -0
- package/dist/tools/evolve-scan.d.ts +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28603,6 +28603,72 @@ function formatResult(result) {
|
|
|
28603
28603
|
}
|
|
28604
28604
|
|
|
28605
28605
|
// src/tools/evolve-filter.ts
|
|
28606
|
+
var EvolveProposalSchema = exports_external.object({
|
|
28607
|
+
title: exports_external.string().min(1),
|
|
28608
|
+
priority: exports_external.enum(["P0", "P1", "P2"]),
|
|
28609
|
+
effort: exports_external.enum(["Low", "Medium", "High"]),
|
|
28610
|
+
description: exports_external.string().optional(),
|
|
28611
|
+
files: exports_external.array(exports_external.string()).optional(),
|
|
28612
|
+
currentState: exports_external.string().optional(),
|
|
28613
|
+
inspiration: exports_external.string().optional(),
|
|
28614
|
+
current_state: exports_external.string().optional(),
|
|
28615
|
+
why: exports_external.string().optional(),
|
|
28616
|
+
how: exports_external.string().optional()
|
|
28617
|
+
}).transform((v) => {
|
|
28618
|
+
const legacyDesc = [v.why, v.how].filter((s) => typeof s === "string" && s.length > 0);
|
|
28619
|
+
return {
|
|
28620
|
+
title: v.title,
|
|
28621
|
+
priority: v.priority,
|
|
28622
|
+
effort: v.effort,
|
|
28623
|
+
description: v.description ?? (legacyDesc.length > 0 ? legacyDesc.join(`
|
|
28624
|
+
`) : ""),
|
|
28625
|
+
files: v.files,
|
|
28626
|
+
currentState: v.currentState ?? v.current_state,
|
|
28627
|
+
inspiration: v.inspiration
|
|
28628
|
+
};
|
|
28629
|
+
});
|
|
28630
|
+
function validateProposalJsonl(line) {
|
|
28631
|
+
const raw = line.trim();
|
|
28632
|
+
if (!raw)
|
|
28633
|
+
return { ok: false, error: "Empty line" };
|
|
28634
|
+
let parsed;
|
|
28635
|
+
try {
|
|
28636
|
+
parsed = JSON.parse(raw);
|
|
28637
|
+
} catch (err) {
|
|
28638
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
28639
|
+
return { ok: false, error: `Invalid JSON: ${msg}` };
|
|
28640
|
+
}
|
|
28641
|
+
const result = EvolveProposalSchema.safeParse(parsed);
|
|
28642
|
+
if (!result.success) {
|
|
28643
|
+
const issues = result.error.issues.map((i) => {
|
|
28644
|
+
const path8 = i.path.length > 0 ? i.path.join(".") : "(root)";
|
|
28645
|
+
return `${path8}: ${i.message}`;
|
|
28646
|
+
}).join("; ");
|
|
28647
|
+
return { ok: false, error: `Schema validation failed: ${issues}` };
|
|
28648
|
+
}
|
|
28649
|
+
return { ok: true, proposal: result.data };
|
|
28650
|
+
}
|
|
28651
|
+
function normalizeTitleForDedup(title) {
|
|
28652
|
+
return title.normalize("NFKC").toLowerCase().replace(/[\p{P}\p{S}\s]+/gu, "").trim();
|
|
28653
|
+
}
|
|
28654
|
+
function deduplicateProposals(existing, incoming) {
|
|
28655
|
+
const seen = new Set;
|
|
28656
|
+
const out = [];
|
|
28657
|
+
const add = (p) => {
|
|
28658
|
+
const key = normalizeTitleForDedup(p.title);
|
|
28659
|
+
if (key.length === 0)
|
|
28660
|
+
return;
|
|
28661
|
+
if (seen.has(key))
|
|
28662
|
+
return;
|
|
28663
|
+
seen.add(key);
|
|
28664
|
+
out.push(p);
|
|
28665
|
+
};
|
|
28666
|
+
for (const p of existing)
|
|
28667
|
+
add(p);
|
|
28668
|
+
for (const p of incoming)
|
|
28669
|
+
add(p);
|
|
28670
|
+
return out;
|
|
28671
|
+
}
|
|
28606
28672
|
var PRIORITY_WEIGHT = {
|
|
28607
28673
|
P0: 10,
|
|
28608
28674
|
P1: 5,
|
|
@@ -28756,6 +28822,186 @@ evolve_score({ markdown: "## Improvement: Rate Limiting\\n**Priority**: P0\\n**E
|
|
|
28756
28822
|
});
|
|
28757
28823
|
}
|
|
28758
28824
|
|
|
28825
|
+
// src/tools/evolve-scan.ts
|
|
28826
|
+
import * as fs8 from "fs";
|
|
28827
|
+
import * as path8 from "path";
|
|
28828
|
+
function splitJsonl(text) {
|
|
28829
|
+
return text.split(/\r?\n/);
|
|
28830
|
+
}
|
|
28831
|
+
function parseJsonl(text) {
|
|
28832
|
+
const proposals = [];
|
|
28833
|
+
const errors5 = [];
|
|
28834
|
+
const lines = splitJsonl(text);
|
|
28835
|
+
for (let i = 0;i < lines.length; i++) {
|
|
28836
|
+
const raw = lines[i] ?? "";
|
|
28837
|
+
if (!raw.trim())
|
|
28838
|
+
continue;
|
|
28839
|
+
const v = validateProposalJsonl(raw);
|
|
28840
|
+
if (v.ok === false) {
|
|
28841
|
+
errors5.push({ line: i + 1, raw, error: v.error });
|
|
28842
|
+
continue;
|
|
28843
|
+
}
|
|
28844
|
+
proposals.push(v.proposal);
|
|
28845
|
+
}
|
|
28846
|
+
return { proposals, errors: errors5 };
|
|
28847
|
+
}
|
|
28848
|
+
function proposalToJson(p) {
|
|
28849
|
+
const out = {
|
|
28850
|
+
title: p.title,
|
|
28851
|
+
priority: p.priority,
|
|
28852
|
+
effort: p.effort,
|
|
28853
|
+
description: p.description
|
|
28854
|
+
};
|
|
28855
|
+
if (p.files && p.files.length > 0)
|
|
28856
|
+
out.files = p.files;
|
|
28857
|
+
if (p.currentState)
|
|
28858
|
+
out.currentState = p.currentState;
|
|
28859
|
+
if (p.inspiration)
|
|
28860
|
+
out.inspiration = p.inspiration;
|
|
28861
|
+
return out;
|
|
28862
|
+
}
|
|
28863
|
+
function formatMaybeCode(s) {
|
|
28864
|
+
return s.replace(/\s+/g, " ").trim();
|
|
28865
|
+
}
|
|
28866
|
+
function markdownEscape(s) {
|
|
28867
|
+
return s.replaceAll("|", "\\|").replaceAll(`
|
|
28868
|
+
`, " ");
|
|
28869
|
+
}
|
|
28870
|
+
function buildReport(args) {
|
|
28871
|
+
const lines = [];
|
|
28872
|
+
lines.push("# Evolve Scan Report");
|
|
28873
|
+
lines.push("");
|
|
28874
|
+
lines.push("## Metadata");
|
|
28875
|
+
lines.push(`- Generated: ${args.generatedAt}`);
|
|
28876
|
+
lines.push(`- Search query: ${args.query && args.query.trim() ? args.query.trim() : "(not provided)"}`);
|
|
28877
|
+
lines.push(`- Threshold: minScore=${args.minScore}, maxProposals=${args.maxProposals}`);
|
|
28878
|
+
lines.push(`- Proposals: existing=${args.existingCount}, incoming=${args.incomingCount}, merged=${args.mergedCount}, accepted=${args.acceptedCount}, rejected=${args.rejectedCount}`);
|
|
28879
|
+
lines.push(`- Invalid JSONL lines skipped: ${args.existingErrors.length + args.incomingErrors.length}`);
|
|
28880
|
+
lines.push("");
|
|
28881
|
+
lines.push("## Feature Matrix");
|
|
28882
|
+
lines.push("");
|
|
28883
|
+
if (args.featureMatrix && args.featureMatrix.trim()) {
|
|
28884
|
+
lines.push(args.featureMatrix.trim());
|
|
28885
|
+
} else {
|
|
28886
|
+
lines.push("_(not provided)_");
|
|
28887
|
+
}
|
|
28888
|
+
lines.push("");
|
|
28889
|
+
lines.push("## Scored Proposals");
|
|
28890
|
+
lines.push("");
|
|
28891
|
+
lines.push(`### Accepted (${args.accepted.length})`);
|
|
28892
|
+
lines.push("");
|
|
28893
|
+
if (args.accepted.length === 0) {
|
|
28894
|
+
lines.push("_(none)_");
|
|
28895
|
+
} else {
|
|
28896
|
+
lines.push("| Title | Score | Priority | Effort | Description | Inspiration | Current state |");
|
|
28897
|
+
lines.push("|---|---:|---|---|---|---|---|");
|
|
28898
|
+
for (const p of args.accepted) {
|
|
28899
|
+
lines.push(`| ${markdownEscape(p.title)} | ${p.score} | ${p.priority} | ${p.effort} | ${markdownEscape(formatMaybeCode(p.description))} | ${markdownEscape(p.inspiration ? formatMaybeCode(p.inspiration) : "")} | ${markdownEscape(p.currentState ? formatMaybeCode(p.currentState) : "")} |`);
|
|
28900
|
+
}
|
|
28901
|
+
}
|
|
28902
|
+
lines.push("");
|
|
28903
|
+
lines.push(`### Rejected (${args.rejected.length})`);
|
|
28904
|
+
lines.push("");
|
|
28905
|
+
if (args.rejected.length === 0) {
|
|
28906
|
+
lines.push("_(none)_");
|
|
28907
|
+
} else {
|
|
28908
|
+
lines.push("| Title | Score | Priority | Effort | Reason |");
|
|
28909
|
+
lines.push("|---|---:|---|---|---|");
|
|
28910
|
+
for (const p of args.rejected) {
|
|
28911
|
+
lines.push(`| ${markdownEscape(p.title)} | ${p.score} | ${p.priority} | ${p.effort} | ${markdownEscape(p.reason ? formatMaybeCode(p.reason) : "")} |`);
|
|
28912
|
+
}
|
|
28913
|
+
}
|
|
28914
|
+
lines.push("");
|
|
28915
|
+
const allErrors = [
|
|
28916
|
+
...args.existingErrors.map((e) => ({ ...e, source: "existing" })),
|
|
28917
|
+
...args.incomingErrors.map((e) => ({ ...e, source: "incoming" }))
|
|
28918
|
+
];
|
|
28919
|
+
if (allErrors.length > 0) {
|
|
28920
|
+
lines.push("## Skipped JSONL Lines");
|
|
28921
|
+
lines.push("");
|
|
28922
|
+
for (const e of allErrors) {
|
|
28923
|
+
lines.push(`- ${e.source} line ${e.line}: ${e.error}`);
|
|
28924
|
+
}
|
|
28925
|
+
lines.push("");
|
|
28926
|
+
}
|
|
28927
|
+
lines.push("## Score Reference");
|
|
28928
|
+
lines.push("");
|
|
28929
|
+
lines.push("P0+Low=30 | P0+Med=20 | P0+High=10 | P1+Low=15 | P1+Med=10 | P1+High=5 | P2+Low=3 | P2+Med=2 | P2+High=1");
|
|
28930
|
+
lines.push("");
|
|
28931
|
+
return lines.join(`
|
|
28932
|
+
`);
|
|
28933
|
+
}
|
|
28934
|
+
function createEvolveScanTool() {
|
|
28935
|
+
return tool({
|
|
28936
|
+
description: `Scan/validate evolve proposals JSONL, merge with existing proposals, score them, and generate a report.
|
|
28937
|
+
|
|
28938
|
+
Writes outputs to:
|
|
28939
|
+
- .opencode/evolve-proposals.jsonl (validated, deduplicated)
|
|
28940
|
+
- .opencode/evolve-report.md (Feature Matrix + Scored Proposals + metadata)
|
|
28941
|
+
|
|
28942
|
+
This tool only writes into .opencode/ and does not modify source code.`,
|
|
28943
|
+
args: {
|
|
28944
|
+
proposalsJsonl: tool.schema.string().optional().describe("Incoming proposals as raw JSONL text (optional; merged into existing file)"),
|
|
28945
|
+
featureMatrix: tool.schema.string().optional().describe("Feature matrix markdown (Phase 2 output) to embed into the report"),
|
|
28946
|
+
query: tool.schema.string().optional().describe("Search query used during research (for report metadata)"),
|
|
28947
|
+
minScore: tool.schema.number().optional().describe("Minimum score to accept (default: 5)"),
|
|
28948
|
+
maxProposals: tool.schema.number().optional().describe("Max proposals to accept (default: 3)")
|
|
28949
|
+
},
|
|
28950
|
+
execute: async (args) => {
|
|
28951
|
+
const generatedAt = new Date().toISOString();
|
|
28952
|
+
const minScore = args.minScore ?? 5;
|
|
28953
|
+
const maxProposals = args.maxProposals ?? 3;
|
|
28954
|
+
const outDir = path8.join(process.cwd(), ".opencode");
|
|
28955
|
+
const proposalsPath = path8.join(outDir, "evolve-proposals.jsonl");
|
|
28956
|
+
const reportPath = path8.join(outDir, "evolve-report.md");
|
|
28957
|
+
fs8.mkdirSync(outDir, { recursive: true });
|
|
28958
|
+
const existingText = fs8.existsSync(proposalsPath) ? fs8.readFileSync(proposalsPath, "utf-8") : "";
|
|
28959
|
+
const existingParsed = existingText ? parseJsonl(existingText) : { proposals: [], errors: [] };
|
|
28960
|
+
const incomingParsed = args.proposalsJsonl ? parseJsonl(args.proposalsJsonl) : { proposals: [], errors: [] };
|
|
28961
|
+
const existingDeduped = deduplicateProposals([], existingParsed.proposals);
|
|
28962
|
+
const merged = deduplicateProposals(existingDeduped, incomingParsed.proposals);
|
|
28963
|
+
const addedCount = merged.length - existingDeduped.length;
|
|
28964
|
+
const existingDupesRemoved = existingParsed.proposals.length - existingDeduped.length;
|
|
28965
|
+
const incomingDupesSkipped = incomingParsed.proposals.length - addedCount;
|
|
28966
|
+
const filtered = filterProposals(merged, { minScore, maxProposals });
|
|
28967
|
+
const accepted = filtered.filter((p) => p.accepted).map((p) => ({ ...p, score: p.score }));
|
|
28968
|
+
const rejected = filtered.filter((p) => !p.accepted).map((p) => ({ ...p, score: p.score, reason: p.reason }));
|
|
28969
|
+
const jsonlOut = merged.map((p) => JSON.stringify(proposalToJson(p))).join(`
|
|
28970
|
+
`) + (merged.length > 0 ? `
|
|
28971
|
+
` : "");
|
|
28972
|
+
fs8.writeFileSync(proposalsPath, jsonlOut, "utf-8");
|
|
28973
|
+
const report = buildReport({
|
|
28974
|
+
generatedAt,
|
|
28975
|
+
query: args.query,
|
|
28976
|
+
minScore,
|
|
28977
|
+
maxProposals,
|
|
28978
|
+
featureMatrix: args.featureMatrix,
|
|
28979
|
+
existingCount: existingParsed.proposals.length,
|
|
28980
|
+
incomingCount: incomingParsed.proposals.length,
|
|
28981
|
+
mergedCount: merged.length,
|
|
28982
|
+
acceptedCount: accepted.length,
|
|
28983
|
+
rejectedCount: rejected.length,
|
|
28984
|
+
existingErrors: existingParsed.errors,
|
|
28985
|
+
incomingErrors: incomingParsed.errors,
|
|
28986
|
+
accepted: accepted.map((p) => ({ ...p, score: scoreProposal(p) })),
|
|
28987
|
+
rejected: rejected.map((p) => ({ ...p, score: scoreProposal(p) }))
|
|
28988
|
+
});
|
|
28989
|
+
fs8.writeFileSync(reportPath, report, "utf-8");
|
|
28990
|
+
const skippedInvalid = existingParsed.errors.length + incomingParsed.errors.length;
|
|
28991
|
+
return [
|
|
28992
|
+
"## evolve_scan complete",
|
|
28993
|
+
`- Wrote: ${proposalsPath}`,
|
|
28994
|
+
`- Wrote: ${reportPath}`,
|
|
28995
|
+
`- Existing proposals: ${existingParsed.proposals.length} (dedup removed ${existingDupesRemoved})`,
|
|
28996
|
+
`- Incoming proposals: ${incomingParsed.proposals.length} (dedup skipped ${incomingDupesSkipped}, invalid skipped ${incomingParsed.errors.length})`,
|
|
28997
|
+
`- Merged proposals: ${merged.length} (accepted ${accepted.length}, rejected ${rejected.length})`,
|
|
28998
|
+
`- Invalid JSONL lines skipped (total): ${skippedInvalid}`
|
|
28999
|
+
].join(`
|
|
29000
|
+
`);
|
|
29001
|
+
}
|
|
29002
|
+
});
|
|
29003
|
+
}
|
|
29004
|
+
|
|
28759
29005
|
// src/hooks/todo-enforcer.ts
|
|
28760
29006
|
var DEFAULT_MAX_ENFORCEMENTS = 5;
|
|
28761
29007
|
var sessionState = new Map;
|
|
@@ -28838,7 +29084,7 @@ ${unfinished.map((t) => `- [ ] ${t.text}`).join(`
|
|
|
28838
29084
|
}
|
|
28839
29085
|
|
|
28840
29086
|
// src/hooks/comment-checker.ts
|
|
28841
|
-
import * as
|
|
29087
|
+
import * as fs9 from "fs";
|
|
28842
29088
|
var AI_SLOP_PATTERNS = [
|
|
28843
29089
|
/\/\/ .{80,}/,
|
|
28844
29090
|
/\/\/ (This|The|We|Here|Note:)/i,
|
|
@@ -28917,7 +29163,7 @@ function createCommentCheckerHook(internalSessions, maxRatio = 0.3, slopThreshol
|
|
|
28917
29163
|
if (!filePath || !isCodeFile(filePath))
|
|
28918
29164
|
return;
|
|
28919
29165
|
try {
|
|
28920
|
-
const content =
|
|
29166
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
28921
29167
|
const result = checkComments(content, filePath, maxRatio, slopThreshold);
|
|
28922
29168
|
if (result.shouldWarn) {
|
|
28923
29169
|
output.output += `
|
|
@@ -29291,6 +29537,9 @@ var OpenCodeUltra = async (ctx) => {
|
|
|
29291
29537
|
if (!disabledTools.has("evolve_apply")) {
|
|
29292
29538
|
toolRegistry.evolve_apply = evolveApply;
|
|
29293
29539
|
}
|
|
29540
|
+
if (!disabledTools.has("evolve_scan")) {
|
|
29541
|
+
toolRegistry.evolve_scan = createEvolveScanTool();
|
|
29542
|
+
}
|
|
29294
29543
|
if (!disabledTools.has("evolve_score")) {
|
|
29295
29544
|
toolRegistry.evolve_score = createEvolveScoreTool();
|
|
29296
29545
|
}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* evolve-filter — Pure scoring and filtering logic for evolve proposals.
|
|
3
3
|
*
|
|
4
4
|
* No side effects. All functions are deterministic.
|
|
5
|
+
* Also exports createEvolveScoreTool() for LLM-facing tool registration.
|
|
5
6
|
*/
|
|
7
|
+
import { tool } from "@opencode-ai/plugin";
|
|
8
|
+
import { z } from "zod";
|
|
6
9
|
export interface EvolveProposal {
|
|
7
10
|
title: string;
|
|
8
11
|
priority: "P0" | "P1" | "P2";
|
|
@@ -12,6 +15,32 @@ export interface EvolveProposal {
|
|
|
12
15
|
currentState?: string;
|
|
13
16
|
inspiration?: string;
|
|
14
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* JSONL schema for evolve proposals.
|
|
20
|
+
*
|
|
21
|
+
* Accepts both canonical keys (description/currentState) and legacy keys
|
|
22
|
+
* (why/how/current_state) used by older evolve prompts.
|
|
23
|
+
*/
|
|
24
|
+
export declare const EvolveProposalSchema: z.ZodType<EvolveProposal>;
|
|
25
|
+
export type ProposalJsonlValidation = {
|
|
26
|
+
ok: true;
|
|
27
|
+
proposal: EvolveProposal;
|
|
28
|
+
} | {
|
|
29
|
+
ok: false;
|
|
30
|
+
error: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Parse and validate a single JSONL line.
|
|
34
|
+
*
|
|
35
|
+
* Returns {ok:false,error} for invalid lines so callers can skip with reason.
|
|
36
|
+
*/
|
|
37
|
+
export declare function validateProposalJsonl(line: string): ProposalJsonlValidation;
|
|
38
|
+
/**
|
|
39
|
+
* Merge existing + incoming proposals, skipping duplicates by normalized title.
|
|
40
|
+
*
|
|
41
|
+
* Normalization: lowercase + punctuation/symbol/whitespace removed.
|
|
42
|
+
*/
|
|
43
|
+
export declare function deduplicateProposals(existing: EvolveProposal[], incoming: EvolveProposal[]): EvolveProposal[];
|
|
15
44
|
export interface FilteredProposal extends EvolveProposal {
|
|
16
45
|
score: number;
|
|
17
46
|
accepted: boolean;
|
|
@@ -38,3 +67,10 @@ export declare function filterProposals(proposals: EvolveProposal[], config?: Fi
|
|
|
38
67
|
* ```
|
|
39
68
|
*/
|
|
40
69
|
export declare function parseProposalsFromMarkdown(markdown: string): EvolveProposal[];
|
|
70
|
+
/**
|
|
71
|
+
* Tool: evolve_score
|
|
72
|
+
*
|
|
73
|
+
* Takes evolve proposal markdown, parses it, scores each proposal,
|
|
74
|
+
* and returns a prioritized list. Pure computation, no agent spawning.
|
|
75
|
+
*/
|
|
76
|
+
export declare function createEvolveScoreTool(): ReturnType<typeof tool>;
|