Commit Graph

248 Commits

Author SHA1 Message Date
63e00c15b1 feat(mcp): add kon-mcp — read-only MCP stdio server over transcripts and tasks
New workspace binary crates/mcp exposes Kon's SQLite store to external
agents (Claude desktop, Cline, any MCP client) without running the Tauri
app. Newline-delimited JSON-RPC 2.0 on stdio, MCP protocol 2024-11-05.

Tools shipped (all read-only):
- list_transcripts — recent transcript summaries, limit 1..200 default 20
- get_transcript   — full text + metadata by id
- search_transcripts — FTS5-backed query, limit 1..100 default 20
- list_tasks       — all tasks (open + done)

No writes. The Tauri app remains the only writer; kon-mcp just opens the
same SQLite file (via kon_storage::init) and reads. Logs land on stderr to
keep stdout clean for the JSON-RPC stream. Smoke-tested end-to-end with
initialize + tools/list over a pipe.

Wire into an MCP client with:
  { "mcpServers": { "kon": { "command": "/path/to/kon-mcp" } } }

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:52:12 +01:00
b8baa65bd2 feat(i18n): scaffold svelte-i18n with en/es/de locales and language selector
initI18n (src/lib/i18n/index.ts) registers three locales and picks the
initial one in order: kon_locale in localStorage > navigator.language short
code > en. +layout.svelte calls it once at app boot; guarded so per-window
re-init is a no-op.

Locale files are deliberately sparse — this is a scaffolding pass so strings
can be migrated incrementally. The Settings → Appearance → Language picker
plus its own description is the first real consumer; everything else
continues to render as hardcoded text until extracted.

Also: split the @chenglou/pretext ambient shim into src/lib/shims.d.ts. The
declaration previously lived in app.d.ts alongside a top-level `export {}`,
which made app.d.ts a module — scoping `declare module` to its own imports
and breaking resolution from src/lib/utils/textMeasure.ts. The fresh
.svelte-kit sync triggered by installing svelte-i18n surfaced it. Ambient
shim files must stay script-scoped (no top-level imports/exports).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:49:03 +01:00
4c0c876ade feat(paste): auto-insert transcript at cursor via wtype/xdotool/ydotool/osascript/SendKeys
Adds an opt-in "auto-paste into focused window" toggle. When enabled, the
dictation pipeline sets the clipboard and then sends a Ctrl+V / Cmd+V
keystroke to whatever window currently has focus — the common case after a
global-hotkey dictation, since Kon's own window never stole focus.

Backend (src-tauri/src/commands/paste.rs) probes for a platform paste tool
and falls back cleanly:
- Linux Wayland: wtype > ydotool > xdotool
- Linux X11: xdotool > ydotool > wtype
- macOS: osascript System Events keystroke
- Windows: PowerShell WScript.Shell SendKeys

detect_paste_backends is a pure probe used by Settings to describe the
available backend next to the toggle (or nudge the user to install one).
paste_text always copies first, so auto-paste failure degrades to the
existing clipboard-only behaviour and surfaces a warn toast.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:45:16 +01:00
36efcf2320 feat(onboarding): parakeet-as-default pinned by test; FirstRunPage handles distil ids
Parakeet-TDT scores 85 on any GPU-equipped English-capable system (Instant
speed + Great accuracy + GPU boost + headroom) vs ~75 for the best distilled
Whisper. A new test in recommendation.rs locks this in so future scoring
tweaks don't silently regress it.

FirstRunPage previously stored settings.modelSize by title-casing a lowercased
alias — which worked for Tiny/Base/Small/Medium but produced
"Whisper-distil-small-en" for the new distil ids. Swap to an id→label map
and pass the raw model id through to download_model/load_model; the backend
already accepts full ids via the whisper_model_id fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:41:22 +01:00
4561810751 feat(whisper): add Distil-Whisper Small and Large v3 as first-class models
Two new registry entries (crates/core/src/model_registry.rs):
- whisper-distil-small-en — 336 MB, ~6× faster than whisper-small-en
- whisper-distil-large-v3 — 1.55 GB, near large-v3 accuracy at medium size

Both are whisper.cpp-compatible GGML binaries hosted on HF by the
distil-whisper org; no runtime change, just wider model choice. English-only
by design (matches upstream Distil-Whisper).

The Settings model picker widens to six options — Tiny, Base, Small,
Distil-S, Medium, Distil-L — ordered roughly by accuracy. Download/load
commands now take the resolved model id (whisper-distil-*) instead of the
lowercased label, so the frontend owns the label↔id mapping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:39:03 +01:00
92d96a0841 feat(whisper): feed profile_terms into initial_prompt at decode time
Previously profile_terms only reached the LLM cleanup stage as the
dictionary_terms suffix. Whisper decoded without any vocabulary hint, so
domain names ('Wren', 'CORBEL') were misspelled on the first pass and the
LLM had to guess at the correction.

build_initial_prompt (src-tauri/src/commands/mod.rs) collapses caller /
profile / terms into a single Whisper prompt:
  caller_prompt > profile_prompt + "Vocabulary: <terms>." > None

transcribe_pcm, transcribe_file, and start_live_transcription_session all
route through the helper, so the three paths stay in lockstep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:35:02 +01:00
d1eb56fac9 feat(llm): wire Phase 3 local LLM runtime via llama-cpp-2
kon-llm now owns a real LlamaBackend + LlamaModel, with three Qwen3 tiers
(1.7B Q4, 4B-Instruct-2507 Q4, 14B Q5) selectable per hardware. Downloads
are resumable with SHA-256 verification and stored under ~/.kon/models/llm.

Engine exposes three high-level surfaces — all greedy/temp-0, GBNF-constrained
where output shape matters:
- cleanup_text (prompt-injection-hardened system prompt; profile terms
  appended as "preserve these spellings" suffix)
- decompose_task (3–7 micro-steps, constrained JSON array)
- extract_tasks (optional-array; empty when no explicit commitments)

post_process_segments now takes an Option<&LlmEngine> and, when loaded and
format_mode != Raw, joins segments → cleanup → replaces segments with the
cleaned text (first segment span). Rule-based path still runs first; LLM
errors log and keep rule-based output.

Tauri commands: recommend_llm_tier, check_llm_model, download_llm_model,
load_llm_model, unload_llm_model, delete_llm_model, get_llm_status,
cleanup_transcript_text_cmd, extract_tasks_from_transcript_cmd,
decompose_and_store (LLM-backed subtasks).

Settings: AI tier toggle (off / cleanup / tasks), model picker with
downloaded/loaded status, download progress events via
kon:llm-download-progress.

Dictation: ensureLlmModelLoaded on mount, cleanupTranscriptIfEnabled after
stop when tier != off and format_mode != Raw, LLM task extraction when
tier=tasks (regex fallback on failure).

Interim: both llama-cpp-sys-2 and whisper-rs-sys statically link their own
ggml, so src-tauri/build.rs emits -Wl,--allow-multiple-definition on Linux.
Replace with a system-ggml shared-lib setup as a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:31:51 +01:00
34fce3cf9e feat: OpenWhispr-inspired transcription polish pass
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Major quality pass on top of Phase 2. Five substantive changes plus
cross-cutting touches across audio, hotkey, transcription, and Tauri
command layers.

  Transcription quality

  - Long-audio chunking in commands/transcription.rs: Parakeet and large
    file transcription now chunk-and-recompose with overlap trimming, so
    the live-path chunking advantage extends to file-based workflows.
  - Stateful live speech gate in commands/live.rs on top of the earlier
    duplicate-boundary filtering — distinguishes start-of-speech from
    mid-speech and holds state across chunks.

  Auto-learning corrections

  - New crates/ai-formatting/src/correction_learning.rs: extracts user
    text corrections from viewer edits and proposes additions to the
    active profile's vocabulary.
  - src-tauri/src/commands/profiles.rs bridge for frontend-driven
    confirmation of learned terms.
  - src/routes/viewer/+page.svelte hooks the learning path into the
    segment-edit flow so corrections feed profile_terms without a
    separate 'train this profile' UX.

  Transcript profile provenance

  - Migration v8 (crates/storage/src/migrations.rs) adds profile_id to
    transcripts, defaulting to DEFAULT_PROFILE_ID so existing rows stay
    valid.
  - crates/storage/src/database.rs: TranscriptRow + CRUD carry profile_id.
  - src-tauri/src/commands/transcripts.rs: add_transcript accepts and
    persists profile_id.
  - DictationPage.svelte + FilesPage.svelte send activeProfileId on
    capture so learned corrections are attributed to the right profile.

  Cleanup prompt contract

  - crates/ai-formatting/src/llm_client.rs hardened: the CLEANUP_PROMPT
    now specifies concrete do/do-not rules, ready for a real model-backed
    cleanup pass. The llm_client is still a stub — kon-llm remains unwired
    — but the prompt shape is final.

  Cross-cutting polish

  - Minor touches in audio (capture/decode/resample), hotkey (lib/linux/stub),
    core, transcription (concurrency/model_manager/local_engine/whisper_rs),
    and the rest of src-tauri/src/commands/*: error-path tightening, log
    clarity, TS-migration follow-ups (@ts-nocheck additions for incremental
    typing).

Verified locally: npm run check, cargo test -p kon-ai-formatting,
cargo test -p kon-storage, cargo test -p kon --lib commands::live::tests,
cargo check — all green.

Scope boundary: kon-llm crate is still a stub; task extraction remains
rule-based. Bundled local-LLM runtime is the next clean step and is not
in this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 22:39:08 +01:00
28acdcfa6d fix(dictation): show user's configured hotkey in hints, not hardcoded Ctrl+Shift+R
Both the status-line hint next to the record button and the empty-state
message now read settings.globalHotkey reactively, so 'Press record or
Super+E' (or whatever the user has bound) stays in sync with the actual
shortcut.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:53:07 +01:00
5e09ab9bd3 fix(hotkey): track modifier state manually so Super+key records on KDE Wayland
webkit2gtk under KDE Wayland does not set e.metaKey on subsequent events
after the compositor intercepts Super — but the Super keydown itself is
still delivered with e.key === "Super". Track pressed modifiers from
raw keydown/keyup and OR with the webkit booleans so combos like Super+E
(which OpenWhispr already registers successfully via evdev) can now be
captured in Kon's recorder.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:49:08 +01:00
39c967c33b fix(hotkey): resolve physical-key codes; Super-as-modifier; surface backend registration errors
Three correctness fixes to the hotkey recorder based on dogfood logs:

1. Modifier set now includes Super / OS / Hyper (webkit2gtk on Linux
   fires e.key === "Super" for the Windows key — previously that key
   got captured as the final trigger, producing invalid 'Ctrl+Shift+Super'
   strings the evdev parser rejected).

2. resolveTriggerKey() uses e.code (physical, shift-independent key)
   to resolve shifted punctuation back to the unshifted name the evdev
   parser understands: '+' -> '=', '|' -> '\\', etc. Letters and digits
   also use e.code (KeyA -> A, Digit1 -> 1) to avoid layout quirks.

3. Numpad keys intentionally not mapped to main-keyboard equivalents —
   they are distinct evdev codes. Leaves the parser to reject them so
   the user gets a toast instead of a silently-wrong binding.

Registration failures now surface as a toast and revert
settings.globalHotkey to the last successfully-registered value (if
any), so the UI cannot lie about what is actually bound.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:36:59 +01:00
86228cd517 chore(storage): drop dictionary table (v7) + retire unused storage fns — profile_terms is sole surface 2026-04-19 21:04:13 +01:00
c0308306ae chore(cleanup): drop legacy global dictionary Tauri commands — profile_terms is canonical
Task 16 of Phase 2 Remaining. Removes the three global-dictionary Tauri
commands now that all frontend callers were migrated to the profile-scoped
equivalents in Task 15:

- list_dictionary_command
- add_dictionary_entry_command
- delete_dictionary_entry_command

Also drops the DictionaryDto and its From<DictionaryEntry> impl (dead
alongside the commands), plus the now-unused kon_storage imports
(list_dictionary, add_dictionary_entry, delete_dictionary_entry,
DictionaryEntry). The storage-layer functions and the dictionary table
itself stay until Task 17 drops them.

Codex verification point 5 cleared: zero frontend callers for the legacy
commands (or their _cmd aliases) before deletion.

cargo check -p kon: clean.
cargo test --workspace: 40 passed; pre-existing ensure_x11_on_wayland
doctest failure at src-tauri/src/lib.rs:77 unchanged.
2026-04-19 21:00:30 +01:00
7474cd24ba feat(ui): profile picker + per-profile vocabulary; transcribe invokes carry profileId; drop buildInitialPrompt 2026-04-19 20:57:46 +01:00
7b804eacba feat(store): profiles store with create/update/delete/active selection 2026-04-19 20:53:43 +01:00
6544bcbaa0 feat(transcribe): route dictionary_terms + initial_prompt through active profile 2026-04-19 20:51:41 +01:00
c8952df591 feat(tauri): expose profile + profile_term commands 2026-04-19 20:48:09 +01:00
d8a5b9bef1 feat(storage): profile + profile_terms CRUD with Default-profile guardrails 2026-04-19 20:43:56 +01:00
3f784313aa feat(storage): migration v6 — profiles + profile_terms + Default-guard triggers; seed from dictionary 2026-04-19 20:39:33 +01:00
e5661b9111 deps(transcription): drop whisper-cpp features from transcribe-rs — whisper-rs is sole Whisper backend 2026-04-19 20:23:31 +01:00
381f236bf8 obs(transcription): log initial_prompt presence at WhisperRsBackend boundary 2026-04-19 20:21:40 +01:00
4256383a5b refactor(transcription): LocalEngine dispatches SpeechBackend enum — Whisper now on whisper-rs 2026-04-19 20:20:03 +01:00
c426fa7eb2 feat(transcription): add WhisperRsBackend wrapping whisper-rs with initial_prompt support 2026-04-19 20:16:07 +01:00
6b44570b04 test(transcription): probe whisper-rs 0.16 load + transcribe + initial_prompt 2026-04-19 20:14:17 +01:00
8b9a569b76 deps(transcription): add whisper-rs 0.16 alongside transcribe-rs for Whisper backend swap 2026-04-19 20:10:18 +01:00
d6bf9ed245 refactor(frontend): migrate JS modules to TypeScript
Wholesale JS -> TS migration of the frontend — stores, utils, actions,
and all Svelte component scripts adopt type annotations. Compile-time
surfaces (app.d.ts, lib/types/) added for shared DTO types.

Build plumbing:
  - package.json: dev:frontend script that runs svelte-kit sync first
  - tauri.conf.json: beforeDevCommand points at dev:frontend
  - run.sh: dropped the sed-hack that temporarily blanked beforeDevCommand;
    now relies on npm run dev:frontend to avoid double-Vite
  - jsconfig.json: allowImportingTsExtensions

Preserves all Group 1 behaviour:
  - page.svelte.ts keeps loadHistory / loadTasks Tauri-first, no
    localStorage; saveTranscriptMeta + mapTranscriptRow + mapTaskRow
    intact; update_task_cmd and update_transcript_meta_cmd invocations
    carry the correct payload shape.
  - Toasts, preferences stores typed without behaviour change.
  - Viewer still routes segment edits through saveTranscriptMeta; the
    Task 1.5 TODO markers are gone.

taskExtractor.ts is functionally improved during the migration:
  - multi-task matches in the same sentence
  - list-style shopping-verb expansion (get bread, milk, and cheese)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:05:54 +01:00
6605266587 feat(ai-formatting): collapse adjacent repetitions in Clean/Smart modes + chore(audio): swap deprecated cpal .name() for description-based helper
ai-formatting:
  - rule_based.rs: collapse_repetitions() merges adjacent duplicate
    tokens like 'I I can' -> 'I can' and 'think think that' -> 'think
    that'. Normalises case and punctuation before comparison.
  - pipeline.rs: post_process now calls collapse_repetitions when
    format_mode is Clean or Smart. Added unit coverage.

audio:
  - capture.rs: replace the seven deprecated cpal DeviceTrait::name()
    call sites with a device_display_name() helper that uses the
    non-deprecated description() path. Keeps identical behaviour,
    silences compile warnings, ready for cpal upgrade.

Addresses the 'Christ. Christ.' live-transcription boundary duplicate
Jake saw during Group 1 dogfooding. Does not fix all cross-chunk
overlap cases (see live.rs OVERLAP_SAMPLES for the root cause) but
catches the common stutter pattern at post-processing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:05:36 +01:00
27d85a0b28 fix(tailwind): move ResizeHandles CSS to app.css global sheet
@tailwindcss/vite:generate:serve threw 'Invalid declaration:
getCurrentWindow' on ResizeHandles.svelte?svelte&type=style&lang.css
even after comment sanitisation. The style block is plain CSS with no
Tailwind directives, but the per-component virtual CSS module route
was hitting a parse bug in the Tailwind v4 + Svelte 5 combination.

Workaround: move the CSS into app.css (class names are already
component-specific, no scoping loss) and drop the component-local
<style> block. This sidesteps the virtual-module route entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:42:20 +01:00
ab88dab82a fix(tailwind): strip remaining apostrophes from ResizeHandles comments
Follow-up to 92ac7ea. Two apostrophes remained (KWin's and don't)
that kept tripping Tailwind v4 JIT the same way. Removed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:22:47 +01:00
52551e6666 fix(parakeet): request word-granularity segments (was per-subword 'T Est Ing')
transcribe-rs 0.3.10's ParakeetModel::transcribe_raw ignores its
options argument and calls self.infer(samples, &TimestampGranularity::default())
where default is TimestampGranularity::Token — per-subword segments.

That surfaces in Kon as output like 'T Est Ing One , Two , Three . W Ow ,
This Is T  Ri Ble .' because DictationPage joins segment texts with ' '.

Introduce a thin ParakeetWordGranularity wrapper that implements
SpeechModel and overrides transcribe_raw to call the concrete
ParakeetModel::transcribe_with() with ParakeetParams { timestamp_granularity:
Some(Word) }. Pre-existing bug unrelated to Phase 2 work — surfaced during
Group 1 dogfooding because Parakeet was being tested for the first time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:19:45 +01:00
92ac7eada3 fix(tailwind): strip all backticks from ResizeHandles comments — Tailwind v4 JIT parses backtick-wrapped text as CSS declarations
Follow-up to d1d344b. Tailwind's scanner still saw backtick-quoted
fragments like `decorations: false` and `position: fixed` in the
script comments as CSS property declarations, tripping on the next
JS identifier (getCurrentWindow). Removing all backticks from the
comment block sidesteps the entire scanner path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:13:41 +01:00
d1d344b3dd fix(tailwind): reword ResizeHandles comment to avoid apostrophe+backtick in Tailwind JIT scan
Tailwind v4 JIT scanner mis-tokenised the comment 'Tauri`s `data-tauri-drag-region`'
as an unterminated string literal, breaking dev-server HMR. Comment rewritten
to avoid apostrophes near backticks. No behaviour change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:43:09 +01:00
e248923f5d feat(transcripts): migration v5 meta — starred, tags, template, language, segments persisted 2026-04-19 16:35:17 +01:00
9378980639 feat(tasks): persist list_id/effort/notes + update_task_cmd — close Task 2 metadata gap 2026-04-19 16:23:25 +01:00
db5c739f22 refactor(state): drop kon_tasks localStorage cache — Tauri-first, UI-on-success 2026-04-19 16:14:49 +01:00
6113e6d784 refactor(viewer): drop kon_history localStorage; route edits through update_transcript 2026-04-19 16:06:19 +01:00
5e3bc369de refactor(state): drop kon_history localStorage cache — SQLite canonical 2026-04-19 15:59:04 +01:00
1a849f9e7f chore: regenerate Tauri ACL schemas (updater plugin) — pre-phase2 branch baseline
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:53:16 +01:00
ea48d03cee agent: dogfood polish 2026/04/19 — Linux native chrome + History redesign + mic picker cleanup
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Second dogfood sprint. Headline fix: Linux now uses native KWin/Mutter
decorations instead of fragile frameless `startResizeDragging`, which
collapsed diagonal corner resize to a single axis and made drag feel
laggy. macOS / Windows keep custom chrome via `useCustomChrome` gate.

Other changes:

- Cross-window preferences sync via `kon:preferences-changed` Tauri
  event — theme and font changes propagate live to float/viewer.
- Hotkey recorder rewritten to use capture-phase document listener
  gated by $effect; button focus was unreliable in webkit2gtk.
- History page redesigned for cognitive-load hygiene: title-first
  compact row, inline title input, Edit popout opening /viewer in
  edit mode, clipboard export as .md with YAML frontmatter, manual
  tag chips + + Add tag input, header tag filter (cap 7), global
  Starred filter, `tag:xyz` search syntax.
- `deriveAutoTags` kept as empty hook for post-Task-7 LLM topic tags;
  research found all previous auto-tag chips redundant with row UI.
- Viewer window adds edit mode with debounced-save textarea; native
  title renamed to "Kon - Transcription Editor".
- Window minimums updated per GNOME HIG + WCAG reflow research:
  main 960x600, float 360x480, editor 560x520.
- Microphone picker filters raw ALSA strings (hw:, plughw:, front:,
  sysdefault:, null) and dedupes by CARD=X. New `description` field
  on DeviceInfo reads /proc/asound/cards so Blue Yeti shows as "Blue
  Microphones" instead of the short "Microphones" card name.
- GPU reporting fixed: get_runtime_capabilities now returns
  accelerators=[cpu,vulkan] and whisper.supports_gpu=true, matching
  the transcribe-rs whisper-vulkan feature linked unconditionally.
- ResizeHandles kept for macOS/Windows frameless: 12px edges, 20px
  corners via CSS vars, pointerdown + setPointerCapture, corners
  above edges in z-order, rendered as sibling (not child) of the
  animated layout root so `position: fixed` is viewport-relative.
- Dueling drag-region handlers removed — `data-tauri-drag-region` and
  manual `startDragging()` were stacked on the same elements; kept
  the manual handler which has the button/input early-return logic.

See HANDOVER.md for the full session log and deferred items.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:30:42 +01:00
8c9c9390d8 fix(storage): PRAGMA foreign_keys=ON; atomic transaction in complete_subtask_and_check_parent; uncomplete_task moved to storage layer
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
2026-04-19 11:00:37 +01:00
f54d55d110 fix(tasks): add explicit parentTaskId field to addTask shape — makes !t.parentTaskId filter intent clear 2026-04-19 10:55:30 +01:00
674fc2c4b8 feat(ui): add MicroSteps expand/collapse to WipTaskList; exclude subtasks from WIP count 2026-04-19 10:51:11 +01:00
442fa6656e feat(ui): add MicroSteps component with decompose button, step checklist, and Just Start timer 2026-04-19 10:49:01 +01:00
0bce8e6ec4 feat(tasks): dual-write tasks to SQLite alongside localStorage; boot-load from SQLite on startup 2026-04-19 10:46:07 +01:00
8d3d302b17 feat(tasks): wire decompose_and_store, list_subtasks_cmd, complete_subtask_cmd; add llm_engine to AppState 2026-04-19 10:44:08 +01:00
8640b255e9 feat(llm): add kon-llm stub crate with LlmEngine interface — Phase 3 will wire real model 2026-04-19 10:42:24 +01:00
b1b3c689d6 feat(tasks): add Tauri CRUD commands — create_task_cmd, list_tasks_cmd, complete_task_cmd, delete_task_cmd, uncomplete_task_cmd 2026-04-19 10:39:56 +01:00
6f264d8bec refactor(storage): extract task_row_from helper — consistent with transcript_row_from pattern 2026-04-19 10:37:55 +01:00
35efed53e5 feat(storage): extend task layer for subtasks — get_task_by_id, insert_subtask, list_subtasks, complete_subtask_and_check_parent 2026-04-19 10:34:59 +01:00
fa20cb313a feat(storage): add parent_task_id migration for micro-stepping 2026-04-19 10:21:43 +01:00