94 Commits

Author SHA1 Message Date
th-kim0823
9f076003e2 docs(fb-34): README + SMOKE + INDEX + HOTFIXES + skill notes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:20:58 +09:00
th-kim0823
e1c6b7055a docs(fb-33): README + SMOKE + INDEX + skill notes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 15:22:09 +09:00
th-kim0823
1008bca342 docs(fb-32): README + SMOKE + INDEX + skill parsing tip
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 02:57:14 +09:00
th-kim0823
b230fbb495 fix: apply review nits — kb→kebab comment, quiet reset guard, ingest-stdin readonly test, README+SMOKE docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 19:58:56 +09:00
th-kim0823
47bfd518c8 📝 docs: comprehensive MCP usage guide (fb-31)
신규 docs/mcp-usage.md (~280 line) — agent integration 의 종합 가이드:

- Quick start + `--config` thread 예시
- Host config 예시 (Claude Code / Cursor / OpenAI Agents / Copilot CLI)
- 6 tool catalog (search / ask / schema / doctor / ingest_file / ingest_stdin)
  각 tool 의 input shape, defaults, output 예시, "언제 사용", mutation
  주의사항.
- Troubleshooting — error.v1 의 7 code 별 조치 표 + grounded:false +
  doctor !ok + empty search + tool-not-found 시나리오.
- Multi-turn ask + session 관리 — session_id 명명, 새 session 시작
  시점, lifetime, single-shot vs session 비교.
- Performance / Security 절.

README.md 의 기존 MCP 절은 quick start 만 유지하고 docs/mcp-usage.md
링크. integrations/claude-code/kebab/SKILL.md 도 동일 cross-link.

agent 사용자 도그푸딩 후속 의견 — host-agnostic 가이드 + 명시적
troubleshooting 표 + multi-turn session 명명 컨벤션 부재 해소.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:53:59 +09:00
th-kim0823
345a4f363a 📝 docs: sync README / HANDOFF / CLAUDE / skill / design for fb-31
- README 명령 표 에 `kebab ingest-file` + `kebab ingest-stdin` 두 row + MCP tool list 4 → 6.
- HANDOFF post-도그푸딩 항목 한 줄.
- CLAUDE.md `_external/` 디렉토리 + naming convention 한 줄.
- integrations skill — Recipe D (agent fetched web doc) + MCP tool list 갱신.
- design §6.7 `_external/` subdirectory 절 신설.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:16:45 +09:00
th-kim0823
f758d51a01 📝 docs: sync README / HANDOFF / CLAUDE / skill / design for fb-30
- README 명령 표 에 `kebab mcp` 추가 + Claude Code MCP config 예시
- HANDOFF post-도그푸딩 항목 한 줄 (rmcp 1.6 + manual dispatch + error_wire promotion + ask/search spawn_blocking + capability flag flip 명시)
- CLAUDE.md facade 룰 의 UI crate 카테고리 에 `kebab-mcp` 추가
- integrations skill — MCP 사용 안내 (recommended over subprocess)
- design §10.2 MCP transport 절 신설

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:15:19 +09:00
th-kim0823
bb7b1cec4b 📝 docs: sync README / HANDOFF / CLAUDE / skill / design for fb-27
- README 명령 표 에 `kebab schema` 추가
- HANDOFF post-도그푸딩 항목 한 줄
- CLAUDE.md wire schema 절 schema.v1 / error.v1 추가
- integrations skill — schema 활용 안내 (additive)
- design §10.1 capability matrix subsection 신설

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:37:40 +09:00
th-kim0823
e31871d03e feat(integrations): ship Claude Code skill for kebab
Add `integrations/claude-code/kebab/` — a Claude Code skill that calls
`kebab search --json` / `kebab ask --json` automatically when the user
asks an internal-context / runbook / wiki-lookup question. Install via
`cp -r integrations/claude-code/kebab ~/.claude/skills/` (or symlink for
in-place updates).

The shipped SKILL.md keeps its frontmatter `description` generic so the
trigger fires on any "internal / org-specific" cue — per-user keywords
(team / system / acronym) belong in a local override, not in the
repo-shipped frontmatter.

CLAUDE.md §Wire schema v1: add a paragraph documenting the
`integrations/<host>/` layout and the rule that a wire schema major bump
(v1→v2) updates each shipped integration in the same PR — same shape as
the version-cascade rule.

README.md §외부 AI 통합: replace the "~50줄 wrapper" prose with a direct
link to `integrations/claude-code/`, since the wrapper is now in-tree.
2026-05-06 18:00:53 +09:00
51feff5f16 docs(p9-fb-25): README + HANDOFF + HOTFIXES + INDEX + per-task spec
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 12:20:38 +00:00
b4aba5de3c docs(p9-fb-23): README + HANDOFF + HOTFIXES + INDEX sync
Update user-facing docs to reflect incremental ingest feature:
README ingest row gains incremental skip + --force-reingest description,
HANDOFF adds summary entry, HOTFIXES adds detailed deviation entry,
INDEX links the new per-task spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 18:27:27 +00:00
8bd423e2dd docs(p9-fb-24): README + HANDOFF + HOTFIXES + INDEX + per-task spec
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 17:03:59 +00:00
294b1ed00c fix(kebab-tui): p9-fb-22 — mid-string cursor editing + Ask follow-tail auto-scroll
도그푸딩 중 발견된 두 건 (Gitea #94, #95) 동시 수정.

#94 — `InputBuffer` 가 append-only 라 Ask/Search/Filter overlay 에서
타이핑한 텍스트의 중간을 편집할 수 없었음. cursor 모델을 byte-position
기반으로 재구성 (cursor_col 은 prefix slice 의 unicode-width 합으로
derive). 신규 메서드: `move_left / move_right / move_home / move_end /
delete_after`. 기존 `push_char` / `pop_char` 는 cursor 위치에서 동작
(cursor 가 끝일 때 backwards-compatible). Ask / Search / Library filter
overlay 세 곳에 `← / → / Home / End / Delete` key handler 추가. Search 는
cursor 이동만으로는 input_dirty_at 을 reset 하지 않음 (커서 이동 ≠ 쿼리
변경 → debounce 타이머 유지).

#95 — Ask 트랜스크립트의 `Paragraph::scroll((s.scroll, 0))` 가 위에서
부터 카운트라, 새 답변 도착 시 `s.scroll = 0` 으로 리셋하면 viewport 가
위쪽 고정 → 트랜스크립트가 길어지면 새 응답이 시야 밖으로 밀림. `AskState`
에 `follow_tail: bool` (default true) 추가. `render_answer` 가 follow_tail
동안 매 프레임 `Paragraph::line_count(width)` 로 wrapped row 수 계산해
스크롤을 `line_count - inner_height` 에 pin. `j` / `k` 가 follow_tail 끄고
`Shift-G` 가 다시 켬. 새 submission, `Ctrl-L` 도 follow-tail 재활성화.

`kebab-tui` 의 ratatui dep 에 `unstable-rendered-line-info` feature
활성화 — `Paragraph::line_count` 가 ratatui 0.28 에서 unstable. 0.28 에
pin 되어있는 동안 안정. 향후 ratatui bump 시 본 feature 의 stable 여부
재확인 필요.

cheatsheet popup Search/Ask section 에 화살표 + Home/End + Delete row
추가, Ask 에 `Shift-G` row 추가. README + HANDOFF + HOTFIXES + INDEX 동기.

Tests: 12 신규 InputBuffer unit + 6 신규 Ask integration. 기존 699 워크
스페이스 테스트 모두 통과 (cursor 가 끝일 때 backwards-compat).

Spec: `tasks/p9/p9-fb-22-tui-cursor-and-autoscroll.md` (status `completed`).
Live deviation 기록: `tasks/HOTFIXES.md` `2026-05-04 — p9-fb-22`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:29:09 +00:00
7709fb0455 feat(kebab-tui): p9-fb-21 — universal i Insert toggle + Search io rebind + F1 prefix
도그푸딩 피드백 (사용자 2026-05-03): Ask Insert→Esc→Normal 후 Insert 로
돌아가는 키 모름. 전반적 키바인딩 안내 부족.

Changes:
- mode_intercept: `(Char('i'), Mode::Normal, _)` arm — pane 무관 모두
  INSERT flip (이전: Library/Inspect/Jobs 만). 사용자가 어느 pane 에서든
  Esc 후 `i` 로 Insert 즉시 복귀 가능.
- Search 의 chunk inspect 키 `i`→`o` (vim "open") rebind. `i` 가
  universal Insert toggle 로 자유로워짐.
- `footer_hints` 모든 (pane, mode, filter) 조합 첫 fragment = `F1 도움말`.
  cheatsheet binding 의 discoverability 보장.
- Search/Ask Normal hint 에 `i 입력모드` fragment 추가.
- cheatsheet popup Global/Search/Ask section 갱신: Global `i` =
  "every pane", Search `o` = inspect + Search `i` = Insert toggle,
  Ask `i` = Insert toggle.
- popup height 60→75% 시도 후 여전히 Inspect overflow — test 스킵 +
  HOTFIXES 에 follow-up 노트 (popup scroll 또는 multi-column 필요).

Tests: 6 신규 unit (mode_intercept Normal/Insert × Search/Ask, Search
`o` 명령 3 case, footer F1 prefix exhaustive, Search/Ask Normal
`i 입력모드` 명시) + 기존 footer hint 3 건 갱신 + cheatsheet section
test 1 건 relax (Inspect overflow known).

spec: `tasks/p9/p9-fb-21-tui-insert-key-discoverability.md` (status
`completed` 직접 — 도그푸딩 직접 피드백 source).
2026-05-03 14:30:04 +00:00
a48f4be5c3 feat(kebab-tui): p9-fb-13 follow-up — verb-form hint line redesign
`pub fn footer_hints(focus: Pane, mode: Mode, filter_open: bool) -> &'static str`
신규 (run.rs). 기존 `render_footer` 의 영문 `key=action` 형식이 한국어
동사구로 — `"위로"` / `"아래로"` / `"필터"` / `"타이핑 검색어"` /
`"Esc 로 NORMAL 모드"` 등 — 변경되고 (pane, mode, filter_open) 조합에
따라 자동 분기. NORMAL 모드는 navigation verbs, INSERT 모드는
typing + Esc reminder. Library filter overlay 는 overlay-only key 3
개로 override.

8 unit tests pin: 모든 (pane, mode, filter) 조합 non-empty exhaustive
+ Library Normal/filter, Search Normal/Insert, Ask Normal/Insert,
Inspect Normal 별 verb fragment 존재 검증.

spec status `in_progress` → `completed` — p9-fb-13 partial 의 deferred
verb-form 항목이 닫힘.
2026-05-03 11:13:14 +00:00
3fe8105866 docs(p9-fb-10): InputBuffer follow-up — spec completed + HOTFIXES checklist done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 10:19:10 +00:00
9e720f1bdc feat(kebab-tui): p9-fb-10 partial — CJK width helpers + render audit
`kebab-tui::input::{display_width, truncate_to_display_width}` 신규.
unicode-width 위에서 column-단위 width 계산 (ASCII=1, Hangul/CJK/
fullwidth=2, combining=0) + char-boundary 안전 truncate.

library.rs 의 중복 `truncate_to_display_width` private fn 제거 — 단일
source 로 통일. 9 unit tests + 1 integration render test (Korean +
Japanese fixture, TestBackend 80×20).

spec 의 `InputBuffer` struct 도입은 follow-up — Ask/Search/Editor pane
의 String + cursor 일괄 마이그레이션이 회귀 표면이 커서 helper 만
먼저 머지. backspace 는 모든 pane 이 이미 `String::pop()` 사용 → byte-
boundary 안전성 확보. crossterm 0.28 가 native IME composing 미노출 →
preedit handling out of scope.

spec status `planned` → `in_progress`. HOTFIXES.md 에 InputBuffer
struct deferral 사유 기록.
2026-05-03 08:52:31 +00:00
69c410aaff feat(kebab-tui): p9-fb-13 cheatsheet popup (F1)
도그푸딩 item 11 — vim 비익숙 사용자도 TUI 조작 가능. F1 으로 cheatsheet
modal popup, 현재 pane 의 키 매핑 + global 토글 (i/Esc/F1) 한 자리.

## 핵심 변경

- **`kebab-tui::cheatsheet::render_cheatsheet(f, area, app)`** 신규 —
  70%/60% centered modal. 5 sections (Global / Library / Search / Ask
  / Inspect) 각 pane 의 모든 키 + 동사구 설명. footer 에 현재 focused
  pane 명시. theme.style(Role::Heading/CitationMarker/Hint) 으로 색
  계층 (header bold, key cyan-marker, body plain, hint dim).
- **`App.cheatsheet_visible: bool`** field + `pub fn cheatsheet_
  visible() -> bool` getter (read-only — set/unset 은 F1 intercept
  invariant).
- **`cheatsheet_intercept(app, key)`** in run.rs:
  - F1 → toggle (open ↔ close), consumed
  - Esc 가 visible 일 때 → close, consumed (mode_intercept 가 같은
    Esc 를 mode flip 으로 해석하지 않도록 cheatsheet_intercept 가
    먼저 dispatch)
  - 그 외 키 → fall-through (popup 열린 채 navigation 가능)
  - modifier-bearing F1 (Ctrl-F1 등) 무시
- **run loop 통합**: `cheatsheet_intercept` → `mode_intercept` →
  pane dispatch 순. render_root 가 error overlay 위에 cheatsheet
  overlay (사용자가 error 도중에도 도움말 소환 가능).

## HOTFIXES (`?` → `F1` rebind)

spec 은 `?` 를 trigger 로 명시했지만 Library 가 이미 `Char('?')` 를
quick-Ask binding 으로 사용 중 (handle_key_library line 305). spec 의
`?` 채택 = 기존 binding 깨거나 mode-aware special case 추가. 후자는
mode machine 에 더 많은 분기 추가하므로 회피.

**Live binding**: `F1` (universal help key, no collision).

**Per-pane verb hint line**: spec 의 verb-form hint 재구성도 본 PR
에서 deferral. 기존 `render_footer` 의 pane-별 힌트 문자열이 동일 UX
역할 — 후속 PR 에서 mode-aware verb fragments 로 split 가능.

spec status `planned` → `in_progress` (NOT `completed` — verb hint
deferral 명시).

## 테스트

- 5 신규 integration unit (`tests/cheatsheet.rs`):
  - F1 toggles visibility (open ↔ close, consumed 양쪽)
  - Esc closes when visible / falls through when hidden
  - modifier-bearing F1 (Ctrl-F1, Alt-F1) 무시
  - arbitrary keys (j, /, q, Enter) fall through 하면서 popup 열린 채
  - render_cheatsheet 가 모든 section header (Global/Library/Search/
    Ask/Inspect) + global toggle (F1, Esc) 출력
- 기존 113 TUI 테스트 + 신규 5 = 118 통과
- `cargo test --workspace --no-fail-fast -j 1` exit 0
- `cargo clippy --workspace --all-targets -- -D warnings` clean

## 문서

- README `kebab tui` 행: F1 cheatsheet popup 안내
- HANDOFF: 2026-05-03 entry
- HOTFIXES: ?→F1 rebind rationale + verb hint deferral
- spec status `planned` → `in_progress`

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 08:28:09 +00:00
765ffc97c5 feat(kebab-tui): p9-fb-12 follow-up — heuristic 제거, mode-authoritative dispatch
p9-fb-12 partial (PR #84) 의 deferred 부분 finalize. spec contract 의
\"기존 P9-3 ask 의 e/j/k input-empty heuristic 제거 — mode 로 명확히\"
완료. spec status `in_progress` → `completed`.

## 핵심 변경

- **`search::is_typing_mod`** (CTRL/ALT chord filter) 함수 삭제.
  search Char dispatch 가 `state.mode` 로 분기:
  - Normal + plain `j`/`k` → 선택 이동 (Char 이라도 Normal 이면
    navigation)
  - Insert + plain `j`/`k`/Char(c) (chord 제외) → input.push
  - Insert + CTRL/ALT chord → no-op (예약 — 향후 binding 위해)
  - Normal + 그 외 Char → no-op (no typing in Normal)
- **`search::handle_key_search` 의 `i` (chunk inspect) / `g` (editor
  jump) pre-pass** 가 `state.mode == Mode::Normal` 일 때만 fire.
  Insert 모드면 typed char (input 에 push). 기존 SHIFT-aware
  matches!() 가드는 Normal-mode 진입 가드로 흡수.
- **`ask::handle_key_ask`** 의 input-empty heuristic 삭제. e/j/k:
  - Normal + `e` → toggle explain
  - Normal + `j` → scroll down (saturating_add)
  - Normal + `k` → scroll up (saturating_sub)
  - Insert + 모든 plain Char (chord 제외) → input.push
- **테스트 fixture** (`tests/search.rs::fresh_app`,
  `tests/ask.rs::fresh_app`) 에 `app.mode = Mode::auto_for(focus)`
  추가 — run loop 의 auto-flip 동작을 테스트가 mirror.
- **기존 nav 테스트** (`j_k_move_selection_within_bounds`,
  `g_key_enqueues_pending_editor_request`, `e_toggles_explain_in_
  normal_mode`) 가 `app.mode = Mode::Normal` 명시.
- **신규 4 테스트** mode-authoritative 동작 회귀 방지:
  - search: `j_in_insert_types_does_not_move_selection`,
    `arbitrary_char_in_normal_mode_is_noop`
  - ask: `e_types_in_insert_mode_does_not_toggle_explain`,
    `jk_scroll_in_normal_mode_type_in_insert`

## 테스트

- 기존 109 + 신규 4 = 113 TUI 테스트 통과 (38 lib + 20 ask + 12
  inspect + 10 library + 6 mode + 25 search + 2 chat — search 23→25,
  ask 18→20)
- `cargo test --workspace --no-fail-fast -j 1` exit 0
- `cargo clippy --workspace --all-targets -- -D warnings` clean

## 문서

- README `kebab tui` 행: \"mode-authoritative dispatch — Search 의
  j/k/i/g, Ask 의 e/j/k 는 NORMAL 모드에서만 명령으로 동작, INSERT
  에서는 입력 문자로 typing\" 명시
- HANDOFF: 2026-05-03 follow-up entry
- spec status `in_progress` → `completed`

## HOTFIXES

p9-fb-12 partial PR (#84) 의 \"Deferred\" 항목이 본 PR 로 finalized
— HOTFIXES 새 entry 불필요 (기존 entry 가 이미 deferral 사유 + 해결
조건 명시).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 07:50:04 +00:00
666eaa9210 feat(kebab-tui): p9-fb-12 partial — Mode enum + global i/Esc + auto switch + status label
도그푸딩 item 10 — vim 비익숙 사용자도 \"지금 키가 입력 vs 명령\" 명확히
구분 가능. 절반 ship: 사용자 가시 signal (mode label + auto flip + i/Esc
global) 만 land, 키 dispatch 의 input-empty heuristic 제거는 follow-up.

## 핵심 변경

- **`kebab_tui::Mode { Normal, Insert }`** enum + `Default = Normal`.
  - `Mode::label()` → `"-- NORMAL --"` / `"-- INSERT --"` (status bar
    문자열, 테스트로 핀).
  - `Mode::auto_for(pane)` → Library/Inspect/Jobs = Normal,
    Search/Ask = Insert. pane 전환 시 자동 적용.
- **`App.mode: Mode`** field. `App::new` 가 starting pane 의 auto
  mode 로 init.
- **run loop `mode_intercept(app, key)`** — pane dispatch 전에 호출:
  - Insert + `Esc` → Normal (어디서나, modifier 없음)
  - Normal + `i` (Library/Inspect/Jobs 만) → Insert
  - Search/Ask 의 `i` 는 fall-through (이미 Insert 라 typed char)
  - 그 외 fall-through
- **pane 전환 시** `app.mode = Mode::auto_for(p)` 자동 flip — 사용자가
  Tab 으로 Search 가면 자동으로 Insert.
- **status bar (header)** 에 mode label colored — Insert = Role::
  Success (green), Normal = Role::Heading (cyan + bold). a11y: 색은
  reinforcement, 글자가 authoritative signal.

## Deferred (HOTFIXES entry 추가)

spec p9-fb-12 의 \"기존 P9-3 ask 의 e/j/k input-empty heuristic 제거 —
mode 로 명확히\" 는 별 PR 로. 현재 dispatch 는 여전히:
- search.rs 의 `is_typing_mod` (SHIFT 만 typing 으로, CTRL/ALT 는 chord)
- ask.rs 의 input.is_empty() 가 e/j/k 를 navigation 으로 분기

테스트가 heuristic 에 의존해 있어, 회귀 surface 좁게 유지하려고 splitting.
spec status `in_progress` 유지 (not `completed`) — follow-up PR 가
heuristic 제거 + 완전 mode-authoritative 후 `completed` flip.

## 테스트

- 신규 3 unit (`Mode::auto_for` 모든 pane, label literals 핀,
  default = Normal)
- 기존 98 TUI 테스트 모두 통과 (heuristic 그대로라 회귀 0)
- workspace 전체 `cargo test --workspace --no-fail-fast -j 1` exit 0
- `cargo clippy --workspace --all-targets -- -D warnings` clean

## 문서

- README `kebab tui` 행: vim-style mode + auto NORMAL/INSERT + i/Esc
  안내
- HANDOFF entry (partial-ship 명시)
- HOTFIXES entry (heuristic 제거 deferral 사유)
- spec status planned → in_progress (NOT completed)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 07:24:16 +00:00
4f96b1b01d feat(kebab-app + kebab-cli): p9-fb-18 CLI ask --session multi-turn
도그푸딩 item 14 — CLI 에서도 multi-turn 가능하도록 `kebab ask
--session <id>` 추가. p9-fb-17 의 ChatSessionRepo 위에 build, 첫 호출
세션 자동 생성, 이후 호출이 prior turns 를 history 로 받아 follow-up.
external AI integration (Claude Code skill / MCP) 도 같은 facade 로
stateful 대화 가능.

## 핵심 변경

- **`App::ask_with_session(session_id, query, opts) -> Answer`** —
  load session header → list_turns 로 prior history → 빌드 retriever
  stack (lexical / vector / hybrid 같은 분기) → `RagPipeline::ask_
  with_history` 호출 → 첫 호출이면 `chat_sessions` row 자동 생성
  (title = first_question_title) → `chat_turns` 새 row append.
- **`App::first_question_title(question)`** helper — `trim() + nfc()
  + 40 chars cap`, fallback `"untitled"`. unicode-normalization
  workspace dep 재사용.
- **`App::blake3_truncate(input)`** helper — `blake3(session_id ||
  ":" || turn_index)` 의 첫 16 byte 를 u128 으로, format!{:032x} 로
  32-hex `turn_id`.
- **`ask_with_session_with_config`** facade — CLI 진입점.
- **CLI `--session <id>` flag** — `Cmd::Ask` 의 `session: Option<
  String>` field, handler 가 None 이면 `ask_with_config` (기존
  단발), Some(id) 면 `ask_with_session_with_config` 호출.
- **에러 정책**: session create / turn append 실패 시 warn 로그
  남기고 answer 는 그대로 반환 — 사용자가 답변 받은 컴퓨트를 잃지
  않음. 영속성 실패가 답변 응답을 가로막지 않는 conservative shape.

## 테스트

- `App::first_question_title` 3 unit (trim + cap, empty → untitled,
  korean NFD → NFC)
- `App::blake3_truncate` 1 unit (deterministic + distinct across
  varying session/index)
- 워크스페이스 전체 `cargo test --workspace --no-fail-fast -j 1` exit 0
- `cargo clippy --workspace --all-targets -- -D warnings` clean

## 문서

- README `kebab ask` 행: `--session` 안내 + chat_sessions 자동 생성
  + `kebab reset --data-only` wipe 안내
- README **외부 AI 통합** 절: Claude Code skill 이 `--session` 으로
  multi-turn 가능하다는 한 문장 추가
- HANDOFF entry
- spec status planned → in_progress

## Out of scope (spec deviation)

- `--repl` (stdin loop) — spec 명시되어 있으나 stdin fixture 부담
  으로 deferral. 별도 후속 task 또는 `--session` 사용자 경험 회신
  후 결정.
- session list / show / delete 관리 명령 (spec 의 Out of scope).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 06:20:16 +00:00
0e408fb1b5 feat(kebab-app + kebab-store-sqlite): p9-fb-19 search LRU cache + corpus_revision
도그푸딩 item 15 — TUI / 같은 process 안에서 동일 query 반복 시 SQLite
FTS + Lance + RRF 재계산이 매번 발생하던 비용 해소. in-process LRU
캐시 + 모노토닉 corpus_revision 카운터로 ingest commit 발생 시 모든
entry 자동 stale.

## 핵심 변경

- **SQLite V004 migration**: `kv (key TEXT PRIMARY KEY, value TEXT)
  STRICT` + `corpus_revision = '0'` seed. 미래의 다른 scalar 도 같은
  테이블에 들어갈 수 있는 generic shape.
- **`SqliteStore::corpus_revision()` / `bump_corpus_revision()`** —
  `UPDATE ... CAST AS INTEGER + 1` atomic. INSERT-OR-IGNORE 도 함께
  실행 (V004 seed 가 무슨 이유로 누락된 케이스 paranoid).
- **`kebab-app::ingest_with_config_cancellable`** — `new + updated > 0`
  시 bump, no-op (skipped-only) reingest 는 cache 보존.
- **`App.search_cache: Option<Mutex<LruCache<SearchCacheKey, Vec<
  SearchHit>>>>`** — `config.search.cache_capacity` (default 256, 0
  비활성). `lru = "0.12"` workspace dep 추가.
- **`SearchCacheKey`** = `query_norm` (NFKC + trim + lowercase) +
  `mode` + `k` + `snippet_chars` + `embedding_version` (vector/hybrid
  만, lexical 은 빈 문자열) + `chunker_version` + `corpus_revision`
  snapshot.
- **`App::search`** rewrite — cache 활성 시 lookup → miss 면 기존
  `search_uncached` 호출 후 put. cache 비활성이거나 lock 실패면
  straight-line.
- **`App::search_uncached`** (rename of pre-fb-19 `search` body) +
  `search_uncached_with_config` facade — CLI `kebab search --no-cache`
  로 진입.
- **`Config.search.cache_capacity: usize`** field, `#[serde(default)]`
  로 기존 config 호환.
- **CLI `--no-cache`** flag — 디버깅용 (CLI 는 매 호출이 새 process
  라 사실상 no-op 이지만 spec 명시 + 향후 long-lived process 호환).
- **frozen design §9 versioning** 표에 `corpus_revision` row 추가
  (기존 `index_version` 라벨과 다른 차원: 라벨은 retrieval 형상,
  corpus_revision 은 ingest commit ack).

## 테스트

- `kebab-store-sqlite` 신규 3 unit (fresh=0, monotonic bump, persist
  across reopen)
- `kebab-app` 신규 4 integration (cached repeat 같은 hits, NFKC 정규화
  로 case/whitespace collapse, --no-cache parity, first ingest bumps
  corpus_revision)
- 워크스페이스 전체 `cargo test --workspace --no-fail-fast -j 1` exit 0
- `cargo clippy --workspace --all-targets -- -D warnings` clean

## 문서

- README `kebab search` 행: 캐시 동작 + `--no-cache` 안내 + corpus_
  revision 무효화 메커니즘
- docs/SMOKE.md `[search]` 절에 `cache_capacity` 라인 추가
- HANDOFF: 2026-05-03 entry
- spec status planned → in_progress

## Out of scope

- patch-and-merge incremental (RRF 정규화 전체 hit set 기준이라 어려움)
- SQLite 영속 cache (P+)
- 다른 process 간 cache 공유 (in-process 만 — corpus_revision 이
  cross-process 무효화는 O(1))

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 05:01:31 +00:00
f6cc612dbe feat(kebab-config + kebab-app): p9-fb-05 workspace.root path policy
도그푸딩 item 3 — `workspace.root` 의 허용 형식이 명문화 안 돼 사용자가
\"상대 경로면 어디 기준?\" 가 불명확. 이제 절대/tilde/env/상대 모두
지원하되, 상대 경로의 base 는 **config.toml 자체가 위치한 디렉토리**
(사용자의 cwd 와 무관) 로 일관 정책.

## 핵심 변경

- **`kebab_config::expand_path_with_base(raw, data_dir, base_dir)`**
  신규. 기존 `expand_path` (tilde + env 만) 위에 relative-path
  resolution 추가:
  - tilde / 절대 / `${VAR}` 입력은 base_dir 무시 (이미 absolute)
  - relative 입력만 `base_dir.join(...)` 로 절대화
- **`Config.source_dir: Option<PathBuf>`** 신규 (`#[serde(skip)]`).
  `Config::from_file` / `load` 가 `path.parent()` 로 stamp. defaults
  는 None (cwd fallback).
- **`Config::resolve_workspace_root()`** helper: source_dir 있으면
  그것 기준, 없으면 cwd 기준.
- **callsite 정리**:
  - `kebab-app::lib.rs` 의 3 군데 `expand_tilde(&app.config.workspace
    .root)` → `app.config.resolve_workspace_root()`
  - `kebab-app::init_workspace` 도 동일
  - `kebab-source-fs::FsSourceConnector::new` → 동일
  - kebab-source-fs 의 fork 된 local `expand_tilde` + `dirs_home`
    헬퍼 제거 (kebab-config 가 canonical)
- **`kebab init`** 가 생성하는 `config.toml` 위에 path policy 안내
  헤더 코멘트 prepend (절대/tilde/env/상대 + 상대 base = config dir).

기존 `expand_tilde` 가 kebab-app/lib.rs 에 한 군데 (storage.data_dir)
남음 — spec out-of-scope (\"expand_tilde 통일 P+\") 라 보류.

## 테스트

- `expand_path_with_base` 에 신규 4 unit (relative→base, absolute
  ignores base, tilde ignores base, ${XDG} ignores base)
- 기존 27 kebab-config tests + workspace 전체 (`cargo test --workspace
  --no-fail-fast -j 1` exit 0) 모두 통과
- `cargo clippy --workspace --all-targets -- -D warnings` clean

## 문서

- README Configuration 절: workspace.root 형식 + relative base 규칙
  한 줄 추가
- HANDOFF: 2026-05-03 entry
- spec status planned → in_progress

## 영향

기존 사용자: 영향 없음 (defaults 의 `~/KnowledgeBase` 는 tilde-rooted,
relative path 분기 안 탐). 새 사용자가 `--config /tmp/cfg.toml` +
`root = "kb"` 같이 쓰면 cwd 무관하게 `/tmp/kb` 가 워크스페이스가 됨 —
이전엔 이 케이스가 cwd 기준이라 invisible foot-gun.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 04:20:06 +00:00
fd8597c696 feat(kebab-tui): p9-fb-08 async search worker + generation counter
도그푸딩 item 6 — TUI search 의 200ms debounce 후 동기 호출이 vector
/ hybrid 모드에서 50-200ms 동안 UI 를 freeze 시키던 문제 해소. 별
thread 에서 search 돌리고 결과 mpsc 로 받음. 사용자가 계속 타이핑하면
stale 결과 자동 폐기 (generation counter pattern, ask.rs 의 worker
패턴과 동일).

## 핵심 변경

- **`SearchState` 필드 3 개 신규**:
  - `generation: u64` — 각 spawn 마다 increment, worker 가 carry
  - `worker_thread: Option<JoinHandle<()>>`
  - `worker_rx: Option<Receiver<SearchWorkerMessage>>`
- **`SearchWorkerMessage`** (`pub enum`) — 단일 변종 `Done {
  generation, result }`. ask.rs 의 token stream 과 달리 search 는
  최종 결과만 한 번 send, 그래서 enum 으로 추후 확장 여지 둠.
- **`fire_search`** rewrite: generation+1 → debounce snapshot 갱신 →
  `std::thread::Builder::spawn` 으로 별 thread, `kebab_app::search_
  with_config(cfg, query)` 호출, channel 로 `(gen, result)` post.
  return 은 즉시 — event loop 안 막힘.
- **`poll_worker`** 신규 (`pub`, integration test 위해 노출): tick
  마다 try_recv. `gen != s.generation` 이면 stale → silently drop +
  `searching` 그대로 (newer worker 가 처리). 일치하면 hits 적용 +
  `searching=false`. Disconnect 면 worker 패닉 처리 — searching
  clear, 다음 tick 의 debounce_due 가 재 spawn.
- **`debounce_due`** 강화: `searching && last_query == 현 input/mode`
  케이스 skip — 같은 query 재 spawn 방지. 기존 dedupe 도 유지.
- **run loop** 의 `Pane::Search` 분기에 `poll_worker(app)` 한 줄
  추가 (debounce_due 호출 직전). 매 tick drain.

## 테스트 (tests/search.rs 신규 4 개)

- `poll_worker_applies_fresh_result_to_hits` — gen 일치 시 hits 적용
  + searching clear + rx drain
- `poll_worker_drops_stale_result` — gen 불일치 시 hits 비어 있음
  + searching 유지 (newer worker 기다림)
- `poll_worker_noop_when_no_rx` — 평상시 tick 에 noop, 기존 hits
  보존
- `poll_worker_handles_disconnected_channel` — 워커 panic (tx drop)
  복구 — searching clear, rx 비움

기존 17 search + 35 lib + 18 ask + 12 inspect + 10 library = 92
통과. clippy clean.

## 문서

- README `kebab tui` 행: "Search 패널은 200ms debounce 후 background
  worker, stale 결과 자동 폐기" 한 줄 추가
- HANDOFF: 2026-05-03 entry
- spec status planned → in_progress

## Out of scope

- 캐시 (p9-fb-19 별도)
- 동일 query 의 inflight worker 합치기 — 현재는 dedupe + 가장 최근
  spawn 만 살아남는 fire-and-forget. 합치는 건 mpsc multiplexing
  로직 필요해 P+ 로 미룸.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 03:50:56 +00:00
c462dbf6a4 feat(kebab-tui): p9-fb-11 ask answer markdown rendering
도그푸딩 item 9 — TUI Ask 답변 본문이 raw `**bold**` / `# Title` /
` ```code``` ` 그대로 보여 가독성 떨어지던 문제 해소. pulldown-cmark
파싱 → ratatui Span/Line 변환.

## 핵심 변경

- **`kebab-tui::markdown::render(text, &Theme) -> Vec<Line<'static>>`**
  신규. pulldown-cmark = "0.13" (이미 kebab-parse-md 가 사용 중인
  버전) 위에 build.

  inline:
  - `**bold**` / `__bold__` → `Modifier::BOLD`
  - `*italic*` / `_italic_` → `Modifier::ITALIC`
  - `~~strike~~` → `Modifier::CROSSED_OUT`
  - `` `code` `` → `Role::Hint` (DIM 스타일 — 터미널 호환성 위해 bg
    color 보다 안전)
  - `[text](url)` → `Role::CitationMarker` + `Modifier::UNDERLINED`

  block:
  - heading H1/H2 → `Role::Heading` (Cyan + BOLD), H3-H6 → `Role::Title`
    (White + BOLD)
  - bullet list `-`/`*` → `- ` + 깊이별 indent
  - ordered list `1.` → 실제 번호 prefix + indent
  - fenced code block ``` ``` ``` → `  ` indented + `Role::Hint`
  - blockquote `>` → 좌측 `▎` bar (중첩 시 반복) + `Role::Hint`
  - table `| col |` → `| col1 | col2 |` 식 줄, `|` separator 색 강조
  - horizontal rule `---` → `─` × 40

- **streaming 안전성**: 매 frame 재 parse 가 spec — pulldown
  토크나이저가 µs/KB 라 비용 무시. unterminated `**` (사용자가 한창
  입력 중인 inline 가 닫히기 전) 은 pulldown 이 Text 로 처리 →
  literal `**` 그대로 표시 (글자 누락 X).

- **`ask::push_turn_lines` 통합**: grounded 답변에서만 markdown
  렌더 사용. refusal turn (`Role::Warning` override) 와 streaming
  turn (`Role::Hint`) 은 raw 로 두어 role color 시그널이 markdown
  스타일에 묻히지 않도록. body line 들은 `  ` indent 로 transcript
  에서 답변 본문 시각 구분.

- **CLI `kebab ask` 출력은 raw markdown** — 터미널 호환성 + pipe
  처리 시 안정성 위해 (ANSI escape 없이 plain text).

## 테스트 (markdown.rs 14 unit)

- empty input → 빈 라인 1 줄 (caller scroll/measure 안전)
- plain text → 단일 라인 + paragraph blank
- bold / italic / strikethrough / inline code → 해당 modifier 검증
- link → UNDERLINED 검증
- heading H1 → BOLD 텍스트 span
- bullet list `-` / numbered list `1./2.` → prefix 검증
- code fence body → 줄별 `  ` indent 보존
- blockquote → `▎` prefix
- 2x2 table → `|`-separated 줄 검증
- unterminated `**` → 글자 누락 없음 (streaming 안전성 회귀 방지)
- composite (heading + para + list + code) → 문서 순서 보존

기존 75 TUI 테스트 + 신규 14 markdown = 89 통과. clippy clean.

## 문서

- README `kebab tui` 행에 markdown 렌더 안내 + CLI 는 raw 명시
- HANDOFF: 2026-05-03 entry
- spec status planned → in_progress

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 03:33:21 +00:00
afb65702b6 feat(kebab-tui): p9-fb-14 color theme module — role-based palette
도그푸딩 item 12 — TUI 가 모든 정보 종류에 같은 회색 / 시안 만 쓰던
\"빈약한 색감\" 해소. inline `Style::default().fg(Color::*)` 호출을
single source `theme` 모듈로 격리 + dark / light 두 팔레트 제공.

## 핵심 변경

- **`kebab-tui::theme::{Theme, Role, Palette}`** 신규 (132 라인). 16
  개 Role enum (BorderActive/BorderInactive/Title/Path/ModeLexical/
  ModeVector/ModeHybrid/Selected/Hint/Heading/Warning/Error/Success/
  CitationMarker/Bullet/Body) 을 dark + light 두 팔레트가 exhaustive
  match 로 매핑. 새 Role 추가 시 두 팔레트 모두 갱신해야 컴파일됨.

- **`Theme::from_name(s)`** — 알 수 없는 값 (e.g. \"solarized\") →
  dark fallback. config typo 가 TUI 를 죽이지 않음 (spec 명시).

- **`App.theme: Theme`** 신규 — `App::new` 가 `config.ui.theme` 에서
  resolve. 모든 pane (library/search/ask/inspect/run/error_popup) 이
  `app.theme.style(Role::X)` 로 style 가져옴.

- **`Config.ui.theme: String`** 신규 — `[ui] theme = \"dark\" | \"light\"`
  (default `\"dark\"`). `#[serde(default)]` 로 기존 config 파일 호환.

- **Pane sweep**: search.rs / ask.rs / library.rs / inspect.rs /
  run.rs / error_popup.rs 의 모든 inline `Style::default().fg(Color::*)`
  / `add_modifier(Modifier::DIM/REVERSED)` 호출 제거. 일부 helper
  (`render_filter_overlay`, `header_kv`, `kv`, `push_section_header`,
  `build_doc_lines`, `build_chunk_lines`, `render_input/answer/bottom/
  status/citations`, `render_error_overlay`) 가 `theme: &Theme` 파라
  미터 추가.

## Out of scope

- `T` 키 runtime toggle — mode machine (p9-fb-12) 미진행이라 NORMAL
  모드 정의 불가, config 만으로 결정. 추후 p9-fb-12 후속에서 추가.
- 사용자 정의 `[theme.custom]` 절 — P+ task.
- truecolor → 256-color fallback — terminal 가정.

## 테스트

- 신규 4 개 (theme.rs):
  - `every_role_resolves_in_dark_and_light` — 16 Role 전부 panic 없이
    Style 반환 (exhaustive match runtime 검증)
  - `from_name_recognizes_dark_light_and_falls_back` — 입력 정규화 +
    fallback 정책
  - `default_palette_is_dark` — 기본값 pin
  - `primary_roles_carry_decoration_in_dark` — Title/Selected/Heading/
    Error/Warning/Success 가 bare default 로 회귀 안 함
- 기존 75 개 TUI 테스트 (14 lib + 18 ask + 12 inspect + 10 library +
  17 search + 4 theme) 모두 통과
- `cargo test --workspace --no-fail-fast -j 1` exit 0
- `cargo clippy -p kebab-tui -p kebab-config --all-targets -- -D warnings`
  clean

## 문서

- README Configuration 절: `[ui]` 섹션 + `theme = \"dark\"|\"light\"`
  안내
- docs/SMOKE.md: config 예시에 `[ui] theme = \"dark\"` 라인 추가
- HANDOFF: 2026-05-03 머지 후 발견 entry
- spec status: planned → in_progress

p9-fb-11 (ask markdown render) 의 `Theme` 의존성 unblock.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 03:09:53 +00:00
2c10cb7e7a feat(kebab-tui): p9-fb-09 external editor return — terminal restore
Search `g` 키 (citation jump) 후 TUI 화면이 깨지는 버그 수정. 도그푸딩
item 7 — `g` 로 vim 띄우고 `:q` 후 복귀하면 이전 frame 의 잔상이 새
draw 위에 겹쳐 보였음.

## 핵심 변경

- **`kebab-tui::editor::with_external_program(&mut TuiTerminal, Command)`**
  helper 추가. suspend / spawn / restore 시퀀스를 RAII guard 로 atomic
  하게 묶어 panic 발생해도 raw mode + alt screen 복구 보장:
    1. LeaveAlternateScreen + Show cursor + disable_raw_mode
    2. Command::status() 로 child 실행
    3. enable_raw_mode + EnterAlternateScreen + Hide cursor +
       `terminal.clear()` ← 이 한 줄이 핵심 fix
- **`App.pending_editor: Option<EditorRequest>`** 추가. 키 핸들러
  (현재 `kebab-tui::search::handle_key_search` 의 `g`) 가 직접 spawn
  하는 대신 EditorRequest 를 enqueue, 실제 spawn 은 run loop 가
  `TuiTerminal` 핸들 in scope 일 때 처리.
- **`App.force_redraw: bool`** ratchet. with_external_program 종료 후
  set, run loop draw 직전 check → terminal.clear() 후 reset. editor
  외 다른 향후 use case (config reload, theme change 등) 도 같은 hook
  사용 가능.

## 가시성 정리

`with_external_program` / `jump_to_citation` 은 `pub(crate)` 로 좁혀짐
— `TuiTerminal` 자체가 module-private (raw mode + alt screen 의 안전
한 lifecycle 은 `Drop` 만 보장) 이므로 외부 caller 는 `App.pending_
editor` enqueue 패턴으로만 spawn 요청 가능. 외부 surface (`build_jump_
command`, `handle_key_search`, `render_search`) 는 그대로.

## 테스트

- `unspawnable_program_surfaces_program_name_in_error` — helper 의 spawn
  실패 경로 (ENOENT) error context 검증
- `g_key_enqueues_pending_editor_request` — `g` on hit → EditorRequest
  enqueue, citation 정보 보존
- `g_key_with_no_hits_does_not_enqueue` — empty hits → no-op
- 기존 17 개 search 테스트 + 14 lib + 18 ask + 12 inspect + 10 library
  모두 통과
- `cargo clippy -p kebab-tui --all-targets -- -D warnings` clean

## 문서

- README: `kebab tui` 행에 Search `g` 동작 + 자동 redraw 안내
- HANDOFF: 2026-05-03 머지 후 발견 entry
- spec status: `planned` → `in_progress`

후속 task (p9-fb-20 의 citation jump in TUI Ask 등) 가 같은
`pending_editor` queue + `with_external_program` helper 위에 build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:32:01 +00:00
7a49c8a29b feat(kebab-normalize): p9-fb-07 markdown title fallback chain
`kebab-normalize::derive_title(frontmatter_title, blocks, file_stem)` 가
다음 단계로 비어있지 않은 첫 결과를 사용:

1. frontmatter `title` (trim 후)
2. 첫 H1 텍스트
3. 첫 H2 텍스트
4. 첫 Paragraph (Quote / List / Code / Table / ImageRef 제외) 의 첫 80 자
5. 파일 stem (확장자 제외)
6. (sentinel) `"untitled"` — 위 다섯 단계가 모두 blank 인 병적 케이스

선택된 문자열은 NFC 정규화. 빈 문자열은 절대 반환하지 않음.

`build_canonical_document` 가 metadata lift 직후 helper 호출. 기존 단순
lift 로직 (metadata.user["title"] → CanonicalDocument.title) 은 fallback
chain 의 1 단계 입력으로 자리 이동.

`KEBAB_PARSE_MD_VERSION` 상수를 `pulldown-cmark-0.x` → `md-frontmatter-v2`
로 bump. parser_version 변경 → §4.2 doc_id 입력 변화 → 기존 markdown
doc 의 `doc_id` 갱신, 다음 ingest 시 idempotent upsert 로 자동 재처리
(design §9 cascade). `kebab-store-sqlite` 의 snapshot fixture 도 같은
literal 로 갱신.

기존 M7 정책 ("metadata.user[\"title\"] = '' 가 빈 title 로 lift") 은
폐기. 빈 문자열 입력은 fallback chain 을 타고 file stem 까지 떨어진다.
spec p9-fb-07 line 37: "빈 문자열 반환 금지".

테스트 (kebab-normalize):
- 8 개 단위 테스트 (각 fallback 단계 + NFC + sentinel)
- `build_canonical_document` 통합 테스트 2 개 (H1 / file stem)
- 기존 M7 테스트 2 개를 새 정책에 맞춰 갱신

문서:
- README: `kebab ingest` 행에 "title 자동 채움" 안내 + 기존 doc 도
  다음 ingest 에서 갱신
- HANDOFF: 2026-05-03 머지 후 발견 entry
- spec status: `planned` → `in_progress`

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:22:34 +00:00
c1555f3c50 feat(cli): kebab ask citation block (p9-fb-20)
답변 출력 후 `근거:` 절 — `[N] <full path>#<fragment>  (score=<s>)`
한 줄씩. spec p9-fb-20 의 핵심 (full path 가독성) 충족.

신규 flag:
- --show-citations: default ON. 답변 후 citation block 출력.
- --hide-citations: 답변 본문만 출력 (pipe 시 다른 도구가 trailing
  metadata 안 받기 원할 때).

`--json` 모드 무영향 — citations 가 wire payload 에 항상 포함되므로
flag 가 영향 X (외부 wrapper 호환성).

spec p9-fb-20 의 \"TUI citation pane + jump (Enter/o editor jump,
i inspect)\" 부분은 본 PR scope 에서 제외 — TUI 의 기존
render_citations_or_explain (P9-3) 가 이미 citation list 표시,
추가 fold/jump 는 후속 task. 사용자 도그푸딩 priority 5위 의
핵심 = \"full path 가독성\" 이라 CLI block 만으로 충분.

Plan 갱신:
- p9-fb-20 status planned → in_progress. 머지 후 한 줄 commit
  으로 completed flip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:37:47 +00:00
7ea7264f5d feat(tui): Ask conversation transcript UI (p9-fb-16)
Multi-turn ask pane. AskState 가 turns: Vec<Turn> + current_question
+ conversation_id + last_answer 로 재설계. answer area 가 transcript
형식 (Q1/A1, Q2/A2, ...) 로 갈음, 매 Enter 가 이전 turns 를 history
로 worker 에 전달 — RagPipeline::ask_with_history 호출.

신규 (kebab-tui::app):
- AskState 에 turns / current_question / conversation_id / last_answer
  4 field 추가. 기존 answer field 제거 (last_answer 가 갈음).

신규 (kebab-tui::ask):
- spawn_ask_worker: 첫 submit 시 conversation_id 자동 생성
  (conv_<unix_nanos_hex>), input → current_question, input clear.
  history = turns.clone(), turn_index = turns.len(). worker 가
  ask_with_history 호출 (kebab-app facade 가 _cancellable 통해
  RagPipeline::ask_with_history 까지 thread).
- poll_worker: Answer 받으면 Turn { question: current_question,
  answer, citations, created_at } 만들어 turns 에 push, last_answer
  도 보존.
- handle_key_ask: Ctrl-L 가 turns + conversation_id 초기화 (in-flight
  worker 는 그대로 finish — 결과는 새 conversation 의 stale turn 으로
  silently 폐기, 사용자 의도와 일치).
- render_answer: 모든 completed turns + (있으면) in-flight turn
  chronological 출력. Q/A 라벨 색상 구분 (Q cyan bold, A green bold).
  in-flight answer 는 ▍ cursor + dim. transcript title 에 turn count.
- render_status / render_citations_or_explain: s.last_answer 사용.

Test:
- 17 PASS (3 신규: ctrl_l_clears_conversation_state /
  render_transcript_shows_completed_turns_in_order /
  render_streaming_inflight_turn_appears_below_completed_turns).
- 기존 14 회귀 0 (기존 s.answer → s.last_answer + Turn fixture
  push).

README + HANDOFF: TUI 행에 multi-turn 동작 추가. spec status
planned → in_progress.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 23:58:26 +00:00
fa02a7c68d feat: ingest cooperative cancellation (p9-fb-04)
Ctrl-C / Esc 가 ingest 를 즉시 중단. 현재 in-flight asset 마무리 후
이후 asset 미실행, IngestEvent::Aborted { partial_counts } 발신,
Ok(IngestReport) 정상 반환 (Err 아님). 부분 commit 보존, 다음 ingest
가 idempotent 재개.

신규 facade: kebab-app::ingest_with_config_cancellable(.., progress,
cancel: Option<Arc<AtomicBool>>). 기존 _progress 가 cancel=None
forwarding wrapper. asset loop 시작 boundary 마다 atomic load —
true 면 break + Aborted emit + 정상 종료. Lock 없음.

CLI: ctrlc crate 신규 dep. SIGINT handler 가 첫 신호에 cancel.store(true)
+ stderr hint, 두 번째 신호에 std::process::exit(130) (canonical SIGINT
exit code). install_sigint_cancel() helper 가 Arc<AtomicBool> 반환,
Cmd::Ingest 가 facade 에 전달.

TUI: IngestState 에 cancel: Arc<AtomicBool> field 추가 (회차 1 review
결과의 reshape 정확). start_ingest 가 둘 다 만들어 worker 에 clone
move. cancel_running_ingest(&app) helper — Esc / Ctrl-C 가
ingest 진행 중일 때만 cancel 우선, 그 외에는 quit.

Test:
- 3 facade integration (cancel-before / cancel-mid / no-cancel
  default).
- 3 tui lib unit (cancel_running_ingest no-state / in-flight /
  terminated).

Plan 갱신: p9-fb-04 status planned → in_progress. 머지 후 한 줄
commit 으로 completed flip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 21:36:17 +00:00
474b776c09 feat(tui): TUI background ingest worker + status bar (p9-fb-03)
Library 의 `r` 키가 `kebab_app::ingest_with_config_progress` 를
spawned thread 에서 호출. run loop 가 매 frame 마다 progress channel
drain → 화면 하단 status bar 1 줄 갱신. blocking 하지 않음.

신규:
- crates/kebab-tui/src/app.rs: `IngestState` struct (rx + counts +
  current_path + started_at + terminal_at + aborted + thread +
  cancel_tx) + `App.ingest_state` slot + `TERMINAL_LINE_HOLD_SECS`.
- crates/kebab-tui/src/ingest_progress.rs: `start_ingest` (worker
  spawn + channel allocation), `drain_progress` (try_recv loop),
  `apply_event` (per-kind counter accumulation + Completed/Aborted
  marking), `status_line` (사람-친화 텍스트), `ready_to_clear`
  (3 초 hold).
- 키 cheatsheet: Library footer 에 `r=ingest` 추가.

Run loop:
- 매 tick `drain_progress` + `ready_to_clear` 체크 → terminal 후
  3 초 경과 시 slot drop + worker 스레드 join + Library refresh
  큐.
- Layout: ingest_state Some 일 때 footer 위에 status line 1 줄
  추가 (있을 때만, 평시 영향 0).
- status line: scanning 중 / 진행 (idx/total %, current path,
  elapsed) / 완료 (✓) / abort (✗) 4 모드.

Cancel wiring (p9-fb-04) 의 `IngestState.cancel_tx: Sender<()>`
slot 은 정의만 — 본 PR 에서 sender 보유, send 호출 X.

Test:
- 10 lib unit (apply_event 분기 5 / status_line 4 / ready_to_clear 2).
- 기존 15 tui test 회귀 0.

Plan 갱신:
- p9-fb-03: status `planned` → `in_progress`. 머지 후 한 줄
  commit 으로 `completed` flip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 20:42:32 +00:00
e613236d60 feat(cli): kebab ingest progress display (p9-fb-02) + p9-fb-01 status flip
`kebab ingest` 가 진행 상황을 사용자에게 보여주는 두 surface 추가:

- **사람 모드 (TTY)**: indicatif `ProgressBar` on stderr — scan 중에는
  spinner, ScanCompleted 후 bar 로 전환, 매 asset 마다 message 갱신.
- **사람 모드 (non-TTY, CI/pipe)**: indicatif draw target 을 hidden
  으로 두고 stderr 에 한 줄씩 (`ingest: scanning`, `ingest: 1/N path`,
  `ingest: complete (...)`).
- **`--json` 모드**: stderr 비우고 stdout 에 line-delimited
  `ingest_progress.v1` JSON 을 emit. 마지막 줄은 기존
  `ingest_report.v1` 그대로 (외부 wrapper backward-compat).

구현:

- 신규 `crates/kebab-cli/src/progress.rs` — `ProgressMode::{Json,
  Human { tty }}`, `ProgressDisplay` (background thread 가 channel
  drain + 모드별 render), `now_rfc3339` helper. mode 가 무엇이든 ts
  는 wire emit 시점에 stamp.
- `crates/kebab-cli/src/wire.rs` 에 `wire_ingest_progress` 추가.
  serde tag (`kind`) 위에 `schema_version` + `ts` 두 필드 더해 spec
  §2.4a wire shape 완성.
- `Cmd::Ingest` 핸들러: mpsc channel 만들고 background thread 가
  display 돌리는 동안 main 이 `ingest_with_config_progress` 호출.
  ingest 반환 시 Sender drop → display thread 정상 종료. join 후
  최종 ingest_report 출력.
- 새 dep: `indicatif` 0.17 (TTY 전용 진행 바, non-TTY/--json 에서는
  hidden draw target).

Test:

- 3 lib unit (mode resolution + RFC 3339 round-trip).
- 3 integration (--json line-delimited / non-TTY stderr text /
  ts+kind 검증). 16 PASS 전체 회귀 0.

Plan 갱신:

- p9-fb-01: status `in_progress` → `completed` (PR #52 머지 후속).
- p9-fb-02: status `planned` → `in_progress`. 머지 후 별도 한 줄
  commit 으로 `completed` flip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 19:57:02 +00:00
1df8731006 docs: kebab reset in README 명령 table + cleanup paragraph + HANDOFF
3-doc sync rule (CLAUDE.md): user-visible CLI surface change → README
and HANDOFF land in the same PR. ARCHITECTURE.md is not touched —
kebab reset doesn't move the crate graph or any locked-in technical
decision.

p9-fb-06 task 5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 18:33:31 +00:00
893287a5a3 fix(config + tilde): LLM default → gemma4:e4b + workspace.root ~ expansion 일관성
도그푸딩 시 사용자 결정 (2026-05-02): 텍스트 LLM 기본을 gemma4 계열로
통일. OCR/caption 어댑터 (P6-2/P6-3) 가 이미 gemma4:e4b 사용 중 —
사용자가 한 family 만 pull 하면 ingest + ask 모두 작동.

같이 발견된 ~ expansion 불일치:
- kebab-source-fs::connector 는 expand_tilde 사용 (walk 정상)
- kebab-app::ingest_one_image_asset / ingest_one_pdf_asset 은 직접
  PathBuf::from → ~ 미확장 → ExtractContext 에 ~/KnowledgeBase
  그대로 전달
- kebab-tui::search::handle_key_search 의 editor jump 도 동일 →
  의미 없는 경로 spawn

Fix:
- Config::defaults().models.llm.model = \"gemma4:e4b\". OCR/caption
  family 통일 코멘트 추가.
- kebab-app 의 image / pdf 분기 두 곳 모두 expand_tilde 호출.
- kebab-tui::search jump 가 kebab_config::expand_path(.., \"\") 사용
  (expand_path 는 ~ / ${XDG_DATA_HOME} / {data_dir} 모두 처리하는
  정식 helper).

Caveat: kebab-app::expand_tilde 와 kebab-config::expand_path 가 별도
정의. 통합은 P+ task.

Docs (sync rule):
- README 사전 요구 절: gemma4:e4b 기본 + 더 큰 variant override 안내.
- docs/ARCHITECTURE 핵심 결정 표: LLM default qwen2.5:7b-instruct →
  gemma4:e4b.
- docs/SMOKE: ollama pull 예시 + KEBAB_MODELS_LLM_MODEL env 예시
  qwen2.5:32b → gemma4:26b.
- HOTFIXES: 새 entry (\"Config defaults: LLM = gemma4:e4b + workspace.root
  tilde expansion\").
- Memory: project_llm_default.md 신설, MEMORY.md 인덱스 추가.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 16:34:24 +00:00
b6e0ab352f feat(kebab-tui): P9-4 Inspect pane — doc/chunk detail with collapsible sections
Library Enter / Search 'i' 가 Inspect 진입. Doc 또는 Chunk 단일 view 로
metadata / provenance / blocks (doc) 또는 spans / text / embeddings (chunk)
6 section 을 collapsible 로 표시. Esc/q 로 originating pane 으로 복귀.

핵심:
- InspectTarget enum (`Doc(DocumentId) | Chunk(ChunkId)`).
- InspectState 본체 (`app.rs`) — target / doc / chunk / collapsed
  HashSet / scroll / return_to / needs_fetch / loading.
- `src/inspect.rs`:
  - `render_inspect` — target 종류별 render_doc / render_chunk 분기,
    section header 가 collapse marker (▾/▸) 표시. metadata.user JSON
    pretty-printed.
  - `handle_key_inspect`: j/k / Down/Up scroll. PageDown/PageUp 10 row.
    c = toggle all sections (v1 simplification). Esc/q = SwitchPane(return_to).
  - `enter_inspect(state, target, return_to)` helper — Library 와 Search
    공통 entry point.
  - run-loop hook `refresh_inspect` — needs_fetch 면 lazy
    inspect_doc_with_config / inspect_chunk_with_config.
- run.rs: Pane::Inspect arm 이 handle_key_inspect + render_inspect.
  Idle tick 마다 refresh_inspect. SwitchPane(Inspect) lazy init.
- Library: Enter 가 enter_inspect(Doc(selected)) 호출 후 SwitchPane.
- Search: 'i' (plain modifier) 가 enter_inspect(Chunk(selected_hit))
  호출 후 SwitchPane. typing 'i' (\"instance\") 와 충돌 가드.

테스트 12개 (`tests/inspect.rs`, TestBackend) — Esc 가 return_to 사용
/ q 도 동작 / j/k scroll bounds / PgUp PgDn ±10 / c 일괄 toggle / no
target hint / loading / doc view header+metadata+provenance+blocks /
collapse hides body / chunk view text+block_ids / no slot →
SwitchPane(Library) / enter_inspect helper sets fields.

Spec deviation (HOTFIXES `2026-05-02 P9-4`):
- `render_inspect<B: Backend>` generic 제거 (P9-1/2/3 와 동일).
- Search `i` 키 추가 (P9-2 spec 에 없었음, P9-4 retroactive 추가).
- `c` 일괄 collapse — spec 의 \"focus 기반 selective collapse\" 는 P+.

Docs (sync rule):
- README: TUI 행 \"4 패널\" + Quick start 코멘트.
- HANDOFF: 한 줄 요약 + Phase status (P9 3/5 → 4/5) + deviation 한 줄.
- HOTFIXES: P9-4 entry.
- tasks/p9/p9-4 status: completed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:41:11 +00:00
f08fefec1d feat(kebab-tui): P9-3 Ask pane — streaming answer + citation panel + explain toggle
P9-1 Library 의 ? 키 활성화. App.ask slot 채움 (parallel-safety contract
그대로). Worker thread 가 kebab-app::ask_with_config 호출하면서
AskOpts.stream_sink 로 token 을 mpsc 채널 에 보냄, 메인 스레드 (TUI) 는
매 render frame 마다 drain 으로 문자열 누적 → 답변 영역 이 token-by-token
업데이트.

핵심:
- AskState 본체 (`app.rs`) — input / explain / streaming / partial /
  answer / thread JoinHandle / rx Receiver / scroll / last_error.
- `src/ask.rs`:
  - `render_ask` — input bar / 답변 영역 (streaming 시 ▍ cursor) /
    bottom split (status: grounded/model/prompt/k/refusal · citations
    or explain panel).
  - `handle_key_ask`: typing → input. Enter → spawn_ask_worker (input
    있음 + not streaming). e (input empty 시) → toggle explain.
    j/k (input empty 시) → scroll. Esc → SwitchPane(Library) +
    streaming/rx/thread 클리어 (best-effort cancel).
  - `spawn_ask_worker` — mpsc::channel + thread::spawn(|| ask_with_config).
  - run-loop hooks: `drain_stream` (try_iter → partial), `poll_worker`
    (handle.is_finished → take + join → answer 채움 또는 ErrorOverlay).
- run.rs: Pane::Ask arm 이 handle_key_ask + render_ask. Idle tick 마다
  drain_stream + poll_worker. SwitchPane(Ask) 시 lazy init.

테스트 13개 (`tests/ask.rs`) — Esc/typing/backspace/e toggle (input
empty)/e typed (input nonempty)/Enter empty/Enter while streaming
no-op/render pre-submission hint/streaming partial+cursor/grounded
answer + citation [1]/refusal score_gate 패널 panic 없음/explain panel
title flip/no slot.

Spec deviation (HOTFIXES `2026-05-02 P9-3`):
- `render_ask<B: Backend>` generic 제거 — ratatui 0.28 Frame
  backend-agnostic (P9-1/P9-2 와 동일).
- e/j/k 가 input 빈 상태 일 때만 command 키, 입력 있으면 typing —
  vim "command vs insert" 변형. spec literal 의 단순 \"e=toggle\" 은
  \"explain\" / \"javascript\" 같은 단어 입력 깨뜨림.

Docs (sync rule):
- README: TUI 행 \"Library + Search + Ask 패널\" + Quick start 코멘트.
- HANDOFF: 한 줄 요약 + Phase status (P9 2/5 → 3/5) + deviation 한 줄.
- HOTFIXES: P9-3 entry.
- tasks/p9/p9-3 status: completed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:24:26 +00:00
0490b6a126 feat(kebab-tui): P9-2 Search pane — input + dense hits + preview + editor jump
Library 의 / 키가 활성화. App.search slot 이 lazy 채워지고 (run loop 가 SwitchPane(Search) 받을 때),
debounce 200 ms 후 kebab-app::search 호출, 선택된 hit 의 chunk 를 preview pane 에 표시.
g 키로 $EDITOR (vim/nvim/code/cursor 자동 감지) 에서 citation 위치 열림.

핵심:
- SearchState 본체 (`app.rs` 의 forward decl 채움) — input / mode / hits /
  selected_hit / input_dirty_at / last_query / searching / preview.
- `src/search.rs` (신규):
  - `render_search(f, area, state)` — 3-pane layout (input bar / 결과 리스트 / preview).
    각 hit 는 §1.5 dense 4-line format (rank.score URI / heading / snippet).
  - `handle_key_search`: typing → input + dirty mark. Tab → mode 순환. Enter →
    immediate refresh. j/k → 선택 이동 + preview invalidate. g → editor jump
    (RAII raw-mode suspend). Esc → Library 복귀.
  - `build_jump_command(citation, editor_env, workspace_root)` 가 vim 류
    `+<line> path` / VS Code `code -g path:line` / cursor `cursor -g`
    자동 분기. unit test 로 잠금.
  - `jump_to_citation` 가 raw-mode + AltScreen 을 RAII 로 suspend/restore
    (panic 안전).
  - run-loop hook 4 함수: `debounce_due` / `fire_search` /
    `refresh_preview` (private to crate).
- run.rs:
  - Pane::Search arm 이 `handle_key_search` 로 dispatch + `render_search`.
  - SwitchPane(Search) 시 `app.search = Some(SearchState::default())` lazy init.
  - Idle tick 마다 debounce_due → fire_search, preview None → refresh_preview.
- 테스트 13개 (`tests/search.rs`) — Esc/typing/backspace/Tab cycle/Enter
  refresh/j-k 이동/jump cmd vim+code+args/render w/hits/empty render/no slot.

Spec deviation (HOTFIXES `2026-05-02 P9-2`):
- `render_search<B: Backend>` generic 제거 (P9-1 와 동일 사유 — ratatui 0.28
  Frame backend-agnostic).
- `jump_to_citation` 가 `workspace_root: &Path` 인자 추가. Citation.path 가
  workspace 상대 라 editor 호출 시 절대 경로 필요. spec literal 의 시그니처
  는 unimplementable.

Docs (sync rule):
- README: TUI 행 \"Library + Search 패널, ask/inspect 진행 중\" + Quick start
  의 `kebab tui` 코멘트 갱신.
- HANDOFF: 한 줄 요약 + Phase status (P9 1/5 → 2/5) + deviation 한 줄 추가.
- HOTFIXES: P9-2 entry 추가.
- tasks/p9/p9-2 status: completed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:38:17 +00:00
ec0bbc2a40 docs(README): install 가이드 + 사전 요구 + 사용 흐름
사용자 요청: \"이 바이너리를 설치해서 사용하도록 readme에 가이드\".

추가 / 변경:
- **사전 요구** 절 신설 — Rust toolchain ≥ 1.85 (rustup), Ollama 설치 +
  `ollama pull` 모델 안내, target/ 디스크 6–10 GB, fastembed 모델 자동
  다운로드 ~470 MB 명시.
- **설치** 절 신설 — `cargo install --path crates/kebab-cli --locked` 가
  표준 경로. 또는 `cargo install --git <gitea url> --bin kebab --locked`
  로 clone 없이. PATH 확인 + `which kebab` / `kebab --version` 검증.
  업데이트 (`--force`) + 제거 (`cargo uninstall kebab-cli` + 데이터 정리)
  명시.
- **Quick start** 갱신 — `./target/release/kebab` 흐름 → 설치된
  `kebab` 흐름 (PATH 에서 직접 호출). `kebab doctor` 한 줄 추가.
- 마지막 한 줄 — dev 흐름 (`cargo run --release -p kebab-cli` 또는
  `cargo build --release && ./target/release/kebab`) 보존, 설치 없이
  돌려볼 때 사용.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:56:56 +00:00
6bfa9795c6 docs: split user-facing docs by audience — README narrow + HANDOFF 진척도 + ARCHITECTURE 내부
사용자 결정 (2026-05-02): \"README.md는 사용자가 가장 빠르게 이 앱을
사용할 수 있도록 하는 내용만 포함하자. mermaid 다이어그램으로 논리적인
아키텍처 다이어그램 하나 정도만 들어가면 충분할 것 같아\".

세 문서로 분리, audience 겹치지 않음:

1. **README.md (narrow)** — 사용자 first stop. Quick start / 명령 표 /
   Mermaid 1개 (논리 아키텍처) / Configuration pointer / 비-목표 / 라이선스.
   진척도 / crate 그래프 / 디렉토리 트리 / 핵심 결정 표 모두 빠짐.

2. **HANDOFF.md (신규)** — phase-level 진척 dashboard. Phase status table,
   component count (33), \"다음 task 후보\" (P9-2/3/4/5, P8 보류), 머지 후
   발견된 deviation 짧은 요약 (P3-5/P4-3 --config, P6-2 OCR, P6-3 caption,
   P7-2 chunk_id, P7-3 storage UNIQUE, P9-1 ratatui generic). 본문 detail
   은 tasks/HOTFIXES.md.

3. **docs/ARCHITECTURE.md (신규)** — crate 의존성 그래프, 디렉토리 트리,
   핵심 기술 결정 표, 외부 AI 통합 절. README 의 Mermaid 가 여기로 링크.

CLAUDE.md 의 \"User-facing docs\" 절 갱신:
- 세 문서 audience 분리 명시.
- implementation PR 이 셋 다 sync 의무, spec PR 은 안 건드림.
- 갱신 trigger 별 (CLI / TUI / Configuration / phase epic / crate 추가 /
  load-bearing deviation) 어느 문서를 손대는지 매핑.
- Out of scope (HOTFIXES detail / version cascade / per-task spec
  rationale) 어디에도 안 적힘 명시.

CLAUDE.md `## Project` 절도 새 문서 layout 반영. 18 crates → ~20 crates.

Memory feedback 갱신 (`feedback_readme_sync_rule.md`) — 미래 conversation
에서 자동 적용.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:51:51 +00:00
24e9f739dd docs: CLAUDE.md README sync rule + README 현행화 (P5 / P6 / P7 / P9-1 반영)
CLAUDE.md 에 새 절 \"User-facing docs (README)\" 추가:
- Implementation PR 이 README 를 갱신, spec PR 은 안 건드림.
- 3 surface (CLI / TUI / Configuration) 마다 README 의 어느 행을 손대야
  하는지 명시.
- Phase status table 갱신 의무 ().
- HOTFIXES detail / version cascade / per-task spec rationale 는 README
  out of scope.

같은 PR 에서 README 의 stale 부분 한꺼번에 정리:
- 상태 line: P0–P5 + P6 + P7 + P9-1 완료 + post-merge hotfix 다수 반영.
- 명령 표: kebab tui 추가, ingest/search 가 markdown/image/PDF 모두
  처리한다고 갱신, eval 상태 .
- 핵심 결정: OCR Tesseract → Ollama-vision (HOTFIXES P6-2),
  Image caption 추가, PDF parser lopdf + chunker_version
  per-medium 명시 (HOTFIXES P7-3), TUI/Desktop 진행 상태.
- Phase 로드맵: P5/P6/P7  완료, P8 ⏸ 보류, P9 🟡 진행 (1/5).
- 디렉토리 구조: kebab-eval / kebab-parse-image / kebab-parse-pdf /
  kebab-tui crate 추가, p6/p7 task 카운트 갱신.
- 빌드 + 실행: kebab tui 사용법 + 두 example 바이너리 (gen_smoke_pdf
  / gen_smoke_png) 안내 추가.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:43:24 +00:00
f9714aa5cb docs(rename): kb → kebab — README, tasks/, docs/, design doc, report
마지막 commit. 모든 .md 안의 `kb` 단어 일괄 갱신.

- 19 개 crate 이름 (`kb-core`, `kb-app`, …) → `kebab-*` (Rust 모듈
  path 표기 `kb_*` → `kebab_*` 포함).
- 미래 component (`kb-tui`, `kb-desktop`, `kb-asr-whisper`, `kb-ocr`,
  `kb-mcp`, `kb-vlm`, `kb-rerank`, `kb-vision-ocr`, `kb-index`,
  `kb-smoke`, `kb-architecture`) → `kebab-*` (P6+ 가 시작될 때
  같은 prefix 사용).
- CLI 명령 예제: `kb ingest` / `kb search` / `kb ask` / `kb init` /
  `kb doctor` / `kb inspect` / `kb list` / `kb eval` →
  `kebab <verb>`. fenced code block + 인라인 backtick 모두.
- XDG paths + env vars + binary 경로 (`target/release/kb` →
  `target/release/kebab`) 동기화.
- design doc / 최초 보고서 / SMOKE / HOTFIXES / phase epic / task
  spec 모든 reference 통일.
- task-decomposition.md 의 `git -c user.name=kb` 는 과거 git history
  기록용 author 정보라 그대로 유지 (실제 git history 의 author 는
  변경 불가).
- `tasks/phase-5-evaluation.md` 의 `status: planned` →
  `completed` 도 같이 (P5-1 + P5-2 PR 머지 후 미반영분).

## 검증

- `grep -rEn "\bkb-[a-z]|\bkb_[a-z]|\.config/kb\b|kb\.sqlite|\bKB_[A-Z]"
   --include="*.md"` 0 hits (task-decomposition.md 의 git author
  제외).
- 모든 file path reference 살아있음 (renamed file 들 모두 새 path
  로 update).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 04:01:55 +00:00
d1b99b2994 docs: mark P0–P4 done, add SMOKE recipe, refresh README
State drift after P0–P4 completion + 3 post-merge hotfixes (PR #20
--config across subcommands, PR #24 --config in kb ask, PR #25 RRF
fusion_score normalization). README still framed the project as
"spec frozen, code 0 lines"; phase docs and task specs all carried
status: planned. Sweep:

- README.md: top banner now "P0–P4 done (17/31 tasks) + 3 hotfixes
  applied"; command table marks each subcommand's owning phase and
  current status (kb ask =  via P4-3, kb eval =  P5);
  phase roadmap table grew a Status column (P0–P4 completed, P5
  next, P6–P9 pending); component count bumped 30 → 31 to reflect
  P3-5 (app-wiring, post-spec); core decisions table notes the
  RRF [0,1] normalization invariant; build+실행 section drops the
  "P0 미시작" caveat; new pointers to HOTFIXES.md and SMOKE.md.
- docs/SMOKE.md (new): ~80-line recipe for running the full
  pipeline against an isolated /tmp/kb-smoke/ workspace via
  --config, without polluting ~/.config/kb/ or
  ~/.local/share/kb/. Covers fixture seeding, sample config.toml
  with the post-merge defaults, doctor → ingest → list →
  search × 3 modes → inspect → ask sequence, verification
  checklist, and known-behaviour notes (fastembed model
  download, RAG response time, --config hard-fail on missing
  path).
- tasks/phase-{0..4}-*.md: status frontmatter flipped planned →
  completed.
- tasks/p0/, tasks/p1/, tasks/p2/, tasks/p3/, tasks/p4/: same
  status flip across all 17 component task specs (1+6+2+5+3).
  P5–P9 stay planned.

cargo test --workspace: 319 passed; clippy clean (no source
changes in this commit, just docs + frontmatter).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 16:32:28 +00:00
kb
bf2179b9c4 docs: add Korean README
- Status (spec frozen, P0 not started)
- Command summary (init/ingest/search/ask/inspect/doctor/eval)
- Locked decisions table (Rust 2024, SQLite+FTS5, LanceDB, fastembed, Ollama, whisper, Tauri)
- Dependency graph + module-boundary references
- Phase roadmap (P0..P9) with crates per phase
- Directory layout (current + post-P0)
- Build/run snippet (post-P0)
- Non-goals
- External AI integration paths (skill / MCP / HTTP)
- Contribution workflow + license note
- Cross-links to frozen design / plan / INDEX
2026-04-27 23:50:39 +00:00