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
+19
View File
@@ -105,6 +105,25 @@ if (envRoot && fs.existsSync(envRoot) && process.env.SMOKE_TS_FILE && process.en
console.log('SKIP symbols / this.-repair checks (set SMOKE_TS_ROOT, SMOKE_TS_FILE, SMOKE_TS_ANCHOR)')
}
// ---------- token healing, debug log, prewarm
const healedRes = (await fim('export class RelayService {\n private readonly connections = new Map<string, WebSocket>()\n\n disconnect(relayUrl: string) {\n const connection = this.connections.get(relayUrl)\n connection?.close()\n this.connections.del', '\n }\n}\n')).body
check('token healing completes a half-typed word', healedRes.healed === 'del' && healedRes.text.startsWith('ete'), JSON.stringify({ healed: healedRes.healed, text: healedRes.text }))
const dbg = (await api('GET', '/v1/debug/last?n=2')).body as unknown as Record<string, string>[]
check('debug log returns decoded prompts', Array.isArray(dbg) && dbg[0]?.prompt?.includes('<|fim_prefix|>'), `${dbg.length} entries`)
const warm = (await api('POST', '/v1/prewarm', { repo: 'smoke', path: 'src/warm.ts', prefix: 'export const answer = ', suffix: '\n' })).body
check('prewarm fills the cache', warm.warmed === true && warm.processedTokens > 0, JSON.stringify(warm))
const ne400 = await api('POST', '/v1/next-edit', { repo: 'smoke', path: 'src/a.ts', text: 'const a = 1\n', cursor: 5 })
check('next-edit refused for models not trained for it', ne400.status === 400)
if (cfg.models?.['nextedit-plumbing']) {
await api('PUT', '/v1/config', { model: 'nextedit-plumbing' })
for (let i = 0; i < 120 && !(await api('GET', '/health')).body.ok; i++) await new Promise(r => setTimeout(r, 500))
const text = 'export function add(a: number, b: number) {\n return a + b\n}\nconst x = add(1)\n'
const ne = (await api('POST', '/v1/next-edit', { repo: 'smoke', path: 'src/add.ts', text, cursor: text.indexOf('add(1)') + 5 })).body
check('next-edit endpoint returns a region decision (plumbing only)', typeof ne.noEdit === 'boolean' && typeof ne.startLine === 'number' && 'newText' in ne, JSON.stringify({ noEdit: ne.noEdit, lines: [ne.startLine, ne.endLine] }))
await api('PUT', '/v1/config', { model: 'stage-c', mode: 'simple' })
for (let i = 0; i < 120 && !(await api('GET', '/health')).body.ok; i++) await new Promise(r => setTimeout(r, 500))
}
// ---------- edit recording endpoint
const recorded = await api('POST', '/v1/edits', { events: [{ t: Date.now(), repo: 'smoke', path: 'src/a.ts', version: 2, changes: [{ offset: 0, length: 0, text: 'x' }], snapshot: 'x' }] })
check('edit recordings are accepted', recorded.body.recorded === 1)