Extension 0.6.0: next-edit, token healing, TS errors context, cursor-move, prewarm
ci / build (push) Canceled after 0s

- shared/nextedit.ts: next-edit prompt format (region rewrite or NO_EDIT, Qwen spare special tokens)
- shared/diagnostics.ts: TS errors near the cursor as context; symbols format 2 adds namespace imports
- shared/prompt.ts: token healing (cut the half-typed word, force it via grammar), errors header section
- daemon: model profiles carry contextFormat/errors/members/nextEdit; /v1/next-edit with edit-burst
  tracking; /v1/prewarm; /v1/debug/last; token healing on by default
- extension: next-edit decorations (Tab apply / Esc dismiss), suggest on cursor move, prewarm on focus,
  Show Last Prompt, update check against releases, diagnostics in the edit recorder
- models/README: training-data attribution; release script profiles for stage-d/stage-e
- .gitea/workflows/ci.yml: build + test, publish release on vscode-v* tags (needs a runner + RELEASE_TOKEN)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J39imRDT8L7xYbWzsVWd8A
This commit is contained in:
2026-10-03 17:21:38 +00:00
co-authored by Claude Opus 5.5
parent af302df26a
commit 87d3c3c3bf
24 changed files with 1090 additions and 53 deletions
+36
View File
@@ -63,3 +63,39 @@ export function statusText(cfg: { enabled: boolean; mode: ContextMode; effective
const mode = cfg.effectiveMode && cfg.effectiveMode !== cfg.mode ? `${cfg.mode}→${cfg.effectiveMode}` : cfg.mode
return `$(sparkle) AC: ${mode}${lastMs !== null ? ` · ${Math.round(lastMs)} ms` : ''}`
}
/** Line-block diff of a region: the first/last changed lines (old and new) after trimming common lines. */
export function lineBlockDiff(oldText: string, newText: string): { oldStart: number; oldEnd: number; newLines: string[]; oldLines: string[] } | null {
const a = oldText.split('\n'), b = newText.split('\n')
let p = 0
while (p < a.length && p < b.length && a[p] === b[p]) p++
if (p === a.length && p === b.length) return null
let s = 0
while (s < a.length - p && s < b.length - p && a[a.length - 1 - s] === b[b.length - 1 - s]) s++
return { oldStart: p, oldEnd: a.length - s, oldLines: a.slice(p, a.length - s), newLines: b.slice(p, b.length - s) }
}
/** Character diff of one line: deleted [start, end) in the old line and the text inserted there. */
export function charDiff(oldLine: string, newLine: string): { start: number; deleteEnd: number; insert: string } {
let p = 0
while (p < oldLine.length && p < newLine.length && oldLine[p] === newLine[p]) p++
let s = 0
while (s < oldLine.length - p && s < newLine.length - p && oldLine[oldLine.length - 1 - s] === newLine[newLine.length - 1 - s]) s++
return { start: p, deleteEnd: oldLine.length - s, insert: newLine.slice(p, newLine.length - s) }
}
/** Where cursor-move triggers make sense for plain FIM: empty line, end of line, or on a line with an error. */
export function insertionMakesSense(lineText: string, column: number, lineHasError: boolean): boolean {
if (!lineText.trim()) return true
if (!lineText.slice(column).trim()) return true
return lineHasError
}
/** Semver-ish comparison of "a.b.c" strings. */
export function newerVersion(candidate: string, current: string): boolean {
const pa = candidate.split('.').map(Number), pb = current.split('.').map(Number)
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) > (pb[i] ?? 0)
}
return false
}