By default, the `me` command truncates note/comment bodies to 200
characters in both the activity feed and since-last-check inbox. This
is sensible for overview displays but loses context when you need to
see the full comment text.
The new `--full` flag disables truncation, returning complete note
bodies. This affects:
- Activity feed: Note summaries now show full content
- Since-last-check inbox: Both regular comments and @mentions show
full bodies
Implementation:
- CLI: Added `--full` boolean arg under "Output" help heading
- queries.rs: `query_activity()` and `query_since_last_check()` now
accept a `full_body: bool` parameter that controls SQL body
selection (`n.body` vs `SUBSTR(n.body, 1, 200)`)
- mod.rs: Wired `args.full` through to both query functions
- Tests: Added `activity_full_body_flag` and
`since_last_check_full_body_flag` tests that verify:
- 300-char bodies truncated to 200 without --full
- 300-char bodies preserved in full with --full
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When new projects are added to the config file, `lore sync` doesn't pick
them up because project discovery only happens during `lore init`.
Previously, users had to use `--force` to overwrite their entire config.
The new `--refresh` flag reads the existing config and updates the
database to match, without modifying the config file itself.
Features:
- Validates GitLab authentication before processing
- Registers new projects from config into the database
- Detects orphan projects (in DB but removed from config)
- Interactive mode: prompts to delete orphans (default: No)
- Robot mode: returns JSON with orphan info, no prompts
Usage:
lore init --refresh # Interactive
lore --robot init --refresh # JSON output
Improved UX: When running `lore init` with an existing config and no
flags, the error message now suggests using `--refresh` to register
new projects or `--force` to overwrite the config file.
Implementation:
- Added RefreshOptions and RefreshResult types to init module
- Added run_init_refresh() for core refresh logic
- Added delete_orphan_projects() helper for orphan cleanup
- Added handle_init_refresh() in main.rs for CLI handling
- Added JSON output types for robot mode
- Registered --refresh in autocorrect.rs command flags registry
- --refresh conflicts with --force (mutually exclusive)
These HTML files were generated for one-time analysis/review purposes
and should not be tracked in the repository.
Files removed:
- api-review.html
- gitlore-sync-explorer.html
- phase-a-review.html
Issue discussion sync was ~10x slower than MR discussion sync because it
used a fully sequential pattern: fetch one issue's discussions, write to
DB, repeat. MR sync already used a prefetch pattern with concurrent HTTP
requests followed by sequential DB writes.
This commit brings issue discussion sync to parity with MRs:
Architecture (prefetch pattern):
1. HTTP phase: Concurrent fetches via `join_all()` with batch size
controlled by `dependent_concurrency` config (default 8)
2. Transform phase: Normalize discussions and notes during prefetch
3. DB phase: Sequential writes with proper transaction boundaries
Changes:
- gitlab/client.rs: Add `fetch_all_issue_discussions()` to mirror
the existing MR pattern for API consistency
- discussions.rs: Replace `ingest_issue_discussions()` with:
* `prefetch_issue_discussions()` - async HTTP fetch + transform
* `write_prefetched_issue_discussions()` - sync DB writes
* New structs: `PrefetchedIssueDiscussions`, `PrefetchedDiscussion`
- orchestrator.rs: Update `sync_discussions_sequential()` to use
concurrent prefetch for each batch instead of sequential calls
- surgical.rs: Update single-issue surgical sync to use new functions
- mod.rs: Update public exports
Expected improvement: 5-10x speedup on issue discussion sync (from ~50s
to ~5-10s for large projects) due to concurrent HTTP round-trips.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When `--limit` is omitted, the default value is `usize::MAX` to mean
"unlimited". The previous code used `(limit + 1) as i64` to fetch one
extra row for "has more" detection. This caused integer overflow:
usize::MAX + 1 = 0 (wraps around)
The resulting `LIMIT 0` clause returned zero rows, making the `who`
subcommands appear to find nothing even when data existed.
Fix: Use `saturating_add(1)` to cap at `usize::MAX` instead of wrapping,
then `.min(i64::MAX as usize)` to ensure the value fits in SQLite's
signed 64-bit LIMIT parameter.
Includes regression tests that verify `usize::MAX` limit returns results.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update beads issue tracking state and expand the GitLab TODOs
notifications integration design document with additional
implementation details.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
NEAR is an FTS5 function (NEAR(term1 term2, N)), not an infix operator like
AND/OR/NOT. Passing it through unquoted in Safe mode was incorrect - it would
be treated as a literal term rather than a function call.
Users who need NEAR proximity search should use FtsQueryMode::Raw which
passes the query through verbatim to FTS5.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Several improvements to the ingestion orchestrator:
1. Stale lock reclamation consolidation:
Previously, reclaim_stale_locks() was called redundantly in multiple
drain functions (drain_resource_events, drain_closes_issues, etc.).
Now it's called once at sync entry points (ingest_project_issues,
ingest_project_mrs) to reduce overhead and DB contention.
2. Fix status_enrichment_mode error values:
- "fetched" -> "error" when project path is missing
- "fetched" -> "fetch_error" when GraphQL fetch fails
These values are used in robot mode JSON output and should accurately
reflect the error condition.
3. Add batch_size zero guard:
Added .max(1) to batch_size calculation to prevent panic in .chunks()
when config.sync.dependent_concurrency is 0. This makes the code
defensive against misconfiguration.
These changes improve correctness and reduce unnecessary DB operations
during sync, particularly beneficial for large projects with many entities.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add pre_truncate_description() to prevent unbounded memory allocation when
processing pathologically large descriptions (e.g., 500MB base64 blobs in
issue descriptions).
Previously, the document extraction pipeline would:
1. Allocate memory for the entire description
2. Append to content buffer
3. Only truncate at the end via truncate_hard_cap()
For a 500MB description, this would allocate 500MB+ before truncation.
New approach:
1. Check description size BEFORE appending
2. If over limit, truncate at UTF-8 boundary immediately
3. Add human-readable marker: "[... description truncated from 500.0MB to 2.0MB ...]"
4. Log warning with original size for observability
Also adds format_bytes() helper for human-readable byte sizes (B, KB, MB).
This is applied to both issue and MR document extraction in extractor.rs,
protecting the embedding pipeline from OOM on malformed GitLab data.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhance the timeline command with two major improvements:
1. Entity-direct seeding syntax (bypass search):
lore timeline issue:42 # Timeline for specific issue
lore timeline i:42 # Short form
lore timeline mr:99 # Timeline for specific MR
lore timeline m:99 # Short form
This directly resolves the entity and gathers ALL its discussions without
requiring search/embedding. Useful when you know exactly which entity you want.
2. Round-robin evidence note selection:
Previously, evidence notes were taken in FTS rank order, which could result
in all notes coming from a single high-traffic discussion. Now we:
- Fetch 5x the requested limit (or minimum 50)
- Group notes by discussion_id
- Select round-robin across discussions
- This ensures diverse evidence from multiple conversations
API changes:
- Renamed total_events_before_limit -> total_filtered_events (clearer semantics)
- Added resolve_entity_by_iid() in timeline.rs for IID-based entity resolution
- Added seed_timeline_direct() in timeline_seed.rs for search-free seeding
- Added round_robin_select_by_discussion() helper function
The entity-direct mode uses search_mode: "direct" to distinguish from
"hybrid" or "lexical" search modes in the response metadata.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement `lore related` command for discovering semantically similar entities
using vector embeddings. Supports two modes:
Entity mode:
lore related issues 42 # Find entities similar to issue #42
lore related mrs 99 # Find entities similar to MR !99
Query mode:
lore related "auth bug" # Find entities matching free text query
Key features:
- Uses existing embedding infrastructure (nomic-embed-text via Ollama)
- Computes shared labels between source and results
- Shows similarity scores as percentage (0-100%)
- Warns when all results have low similarity (<30%)
- Warns for short queries (<=2 words) that may produce noisy results
- Filters out discussion/note documents, returning only issues and MRs
- Handles orphaned documents gracefully (skips if entity deleted)
- Robot mode JSON output with {ok, data, meta} envelope
Implementation details:
- distance_to_similarity() converts L2 distance to 0-1 score: 1/(1+distance)
- Uses saturating_add/saturating_mul for overflow safety on limit parameter
- Proper error handling for missing embeddings ("run lore embed first")
- Project scoping via -p flag with fuzzy matching
CLI integration:
- Added to autocorrect.rs command registry
- Added Related variant to Commands enum in cli/mod.rs
- Wired into main.rs with handle_related()
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add foreign key constraint on discussions.merge_request_id to prevent orphaned
discussions when MRs are deleted. SQLite doesn't support ALTER TABLE ADD CONSTRAINT,
so this migration recreates the table with:
1. New table with FK: REFERENCES merge_requests(id) ON DELETE CASCADE
2. Data copy with FK validation (only copies rows with valid MR references)
3. Table swap (DROP old, RENAME new)
4. Full index recreation (all 10 indexes from migrations 002-022)
The migration also includes a CHECK constraint ensuring mutual exclusivity:
- Issue discussions have issue_id NOT NULL and merge_request_id NULL
- MR discussions have merge_request_id NOT NULL and issue_id NULL
Also fixes run_migrations() to properly propagate query errors instead of
silently returning unwrap_or defaults, improving error diagnostics.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Captures design decisions and acceptance criteria for adding GitLab
TODO support to lore. This plan was developed through user interview
to ensure the feature aligns with actual workflows.
Key design decisions:
- Read-only scope (no mark-as-done operations)
- Three integration points: --todos flag, activity enrichment, lore todos
- Account-wide: --project does NOT filter todos (unlike issues/MRs)
- Separate signal: todos don't affect attention state calculation
- Snapshot sync: missing todos = marked done elsewhere = delete locally
The plan covers:
- Database schema (todos table + indexes)
- GitLab API client extensions
- Sync pipeline integration
- Action type handling and grouping
- CLI commands and robot mode schemas
- Non-synced project handling with [external] indicator
Implementation is organized into 5 rollout slices:
A: Schema + Client, B: Sync, C: lore todos, D: lore me, E: Polish
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhances sync status reporting to include granular per-entity counts
that were added in database migration 027. This provides better
visibility into what each sync run actually processed.
New fields in SyncRunInfo and robot mode JSON:
- issues_fetched / issues_ingested: issue sync counts
- mrs_fetched / mrs_ingested: merge request sync counts
- skipped_stale: entities skipped due to staleness
- docs_regenerated / docs_embedded: document pipeline counts
- warnings_count: non-fatal issues during sync
Robot mode optimization:
- Uses skip_serializing_if = "is_zero" to omit zero-value fields
- Reduces JSON payload size for typical sync runs
- Maintains backwards compatibility (fields are additive)
SQL query now reads all 8 new columns from sync_runs table,
with defensive unwrap_or(0) for NULL handling.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates the `lore robot-docs` manifest with comprehensive documentation
for the new since-last-check inbox feature, enabling AI agents to
discover and use the functionality programmatically.
robot-docs manifest additions:
- since_last_check response schema with cursor_iso, groups, events
- --reset-cursor flag documentation
- Design notes: cursor persistence location, --project filter behavior
- Example commands in personal_dashboard section
Agent instruction updates (AGENTS.md, CLAUDE.md):
- Added --mrs, --project, --user flags to command examples
- Added --reset-cursor example
- Aligned both files for consistency
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements a cursor-based notification inbox that surfaces actionable
events from others since the user's last `lore me` invocation. This
addresses the core UX need: "what happened while I was away?"
Event Sources (three-way UNION query):
1. Others' comments on user's open issues/MRs
2. @mentions on ANY item (not restricted to owned items)
3. Assignment/review-request system notes mentioning user
Mention Detection:
- SQL LIKE pre-filter for performance, then regex validation
- Word-boundary-aware: rejects "alice" in "@alice-bot" or "alice@corp.com"
- Domain rejection: "@alice.com" not matched (prevents email false positives)
- Punctuation tolerance: "@alice," "@alice." "(@ alice)" all match
Cursor Watermark Pattern:
- Global watermark computed from ALL projects before --project filtering
- Ensures --project display filter doesn't permanently skip events
- Cursor advances only after successful render (no data loss on errors)
- First run establishes baseline (no inbox shown), subsequent runs show delta
Output:
- Human: color-coded event badges, grouped by entity, actor + timestamp
- Robot: standard envelope with since_last_check object containing
cursor_iso, total_event_count, and groups array with nested events
CLI additions:
- --reset-cursor flag: clears cursor (next run shows no new events)
- Autocorrect: --reset-cursor added to known me command flags
Tests cover:
- Mention with trailing comma/period/parentheses (should match)
- Email-like text "@alice.com" (should NOT match)
- Domain-like text "@alice.example" (should NOT match)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Database(rusqlite::Error) catch-all variant was suggesting
'lore reset --yes' for ALL database errors, including transient
SQLITE_BUSY lock contention. This was wrong on two counts:
1. `lore reset` is not implemented (prints "not yet implemented")
2. Nuking the database is not the fix for a transient lock
Changes:
- Detect SQLITE_BUSY specifically via sqlite_error_code() and provide
targeted advice: "Another process has the database locked" with
common causes (cron sync, concurrent lore command)
- Map SQLITE_BUSY to ErrorCode::DatabaseLocked (exit code 9) instead
of DatabaseError (exit code 10) — semantically correct
- Set BUSY actions to ["lore cron status"] (diagnostic) instead of
the useless "lore sync --force" (--force overrides the app-level
lock table, but SQLITE_BUSY fires before that table is even reached)
- Fix MigrationFailed suggestion: also referenced non-existent
'lore reset', now says "try again" with lore migrate / lore doctor
- Non-BUSY database errors get a simpler suggestion pointing to
lore doctor (no more phantom reset command)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Organizations without GitLab Premium/Ultimate don't have work item
statuses configured - all their issues have status_name = NULL.
Previously, the me command filtered to only 'In Progress' and
'In Review' statuses, showing zero issues for these organizations.
Now includes NULL status as a fallback for graceful degradation.
Implement a personal work dashboard that shows everything relevant to the
configured GitLab user: open issues assigned to them, MRs they authored,
MRs they are reviewing, and a chronological activity feed.
Design decisions:
- Attention state computed from GitLab interaction data (comments, reviews)
with no local state tracking -- purely derived from existing synced data
- Username resolution: --user flag > config.gitlab.username > actionable error
- Project scoping: --project (fuzzy) | --all | default_project | all
- Section filtering: --issues, --mrs, --activity (combinable, default = all)
- Activity feed controlled by --since (default 30d); work item sections
always show all open items regardless of --since
Architecture (src/cli/commands/me/):
- types.rs: MeDashboard, MeSummary, AttentionState data types
- queries.rs: 4 SQL queries (open_issues, authored_mrs, reviewing_mrs,
activity) using existing issue_assignees, mr_reviewers, notes tables
- render_human.rs: colored terminal output with attention state indicators
- render_robot.rs: {ok, data, meta} JSON envelope with field selection
- mod.rs: orchestration (resolve_username, resolve_project_scope, run_me)
- me_tests.rs: comprehensive unit tests covering all query paths
Config additions:
- New optional gitlab.username field in config.json
- Tests for config with/without username
- Existing test configs updated with username: None
CLI wiring:
- MeArgs struct with section filter, since, project, all, user, fields flags
- Autocorrect support for me command flags
- LoreRenderer::try_get() for safe renderer access in me module
- Robot mode field selection presets (me_items, me_activity)
- handle_me() in main.rs command dispatch
Also fixes duplicate assertions in surgical sync tests (removed 6
duplicate assert! lines that were copy-paste artifacts).
Spec: docs/lore-me-spec.md
Replace all MCP Agent Mail references with Liquid Mail in AGENTS.md and
CLAUDE.md. The old system used file reservations and MCP-based messaging
with inbox/outbox/thread semantics. Liquid Mail provides a simpler
post-based shared log with topic-scoped messages, decision conflict
detection, and polling via the liquid-mail CLI.
Key changes:
- Remove entire MCP Agent Mail section (identity registration, file
reservations, macros vs granular tools, common pitfalls)
- Update Beads integration workflow to reference Liquid Mail: replace
reservation + announce patterns with post-based progress logging and
decision-first workflows
- Update bv scope boundary note to reference Liquid Mail
- Append full Liquid Mail integration block to CLAUDE.md: conventions,
typical flow, decision conflicts, posting format, topic rules, context
refresh, live updates, mapping cheat-sheet, quick reference
- Add .liquid-mail.toml project configuration (Honcho backend)
Add the ability to sync specific issues or merge requests by IID without
running a full incremental sync. This enables fast, targeted data refresh
for individual entities — useful for agent workflows, debugging, and
real-time investigation of specific issues or MRs.
Architecture:
- New CLI flags: --issue <IID> and --mr <IID> (repeatable, up to 100 total)
scoped to a single project via -p/--project
- Preflight phase validates all IIDs exist on GitLab before any DB writes,
with TOCTOU-aware soft verification at ingest time
- 6-stage pipeline: preflight -> fetch -> ingest -> dependents -> docs -> embed
- Each stage is cancellation-aware via ShutdownSignal
- Dedicated SyncRunRecorder extensions track surgical-specific counters
(issues_fetched, mrs_ingested, docs_regenerated, etc.)
New modules:
- src/ingestion/surgical.rs: Core surgical fetch/ingest/dependent logic
with preflight_fetch(), ingest_issue_by_iid(), ingest_mr_by_iid(),
and fetch_dependents_for_{issue,mr}()
- src/cli/commands/sync_surgical.rs: Full CLI orchestrator with progress
spinners, human/robot output, and cancellation handling
- src/embedding/pipeline.rs: embed_documents_by_ids() for scoped embedding
- src/documents/regenerator.rs: regenerate_dirty_documents_for_sources()
for scoped document regeneration
Database changes:
- Migration 027: Extends sync_runs with mode, phase, surgical_iids_json,
per-entity counters, and cancelled_at column
- New indexes: idx_sync_runs_mode_started, idx_sync_runs_status_phase_started
GitLab client:
- get_issue_by_iid() and get_mr_by_iid() single-entity fetch methods
Error handling:
- New SurgicalPreflightFailed error variant with entity_type, iid, project,
and reason fields. Shares exit code 6 with GitLabNotFound.
Includes comprehensive test coverage:
- 645 lines of surgical ingestion tests (wiremock-based)
- 184 lines of scoped embedding tests
- 85 lines of scoped regeneration tests
- 113 lines of GitLab client single-entity tests
- 236 lines of sync_run surgical column/counter tests
- Unit tests for SyncOptions, error codes, and CLI validation
Change the `who` command's --limit flag from default=20 to optional,
so omitting it returns all results. This matches the behavior users
expect when they want a complete expert/workload/active/overlap listing
without an arbitrary cap.
Also applies clippy-recommended sort improvements:
- who/reviews: sort_by(|a,b| b.count.cmp(&a.count)) -> sort_by_key with Reverse
- drift: same pattern for frequency sorting
Adds Theme::color_icon() helper to DRY the stage-icon coloring pattern
used in sync output (was inline closure, now shared method).
Introduce a centralized token resolution system that supports both
environment variables and config-file-stored tokens with clear priority
(env var wins). This enables cron-based sync which runs in minimal
shell environments without env vars.
Core changes:
- GitLabConfig gains optional `token` field and `resolve_token()` method
that checks env var first, then config file, returning trimmed values
- `token_source()` returns human-readable provenance ("environment variable"
or "config file") for diagnostics
- `ensure_config_permissions()` enforces 0600 on config files containing
tokens (Unix only, no-op on other platforms)
New CLI commands:
- `lore token set [--token VALUE]` — validates against GitLab API, stores
in config, enforces file permissions. Supports flag, stdin pipe, or
interactive entry.
- `lore token show [--unmask]` — displays masked token with source label
Consumers updated to use resolve_token():
- auth_test: removes manual env var lookup
- doctor: shows token source in health check output
- ingest: uses centralized resolution
Includes 10 unit tests for resolve/source logic and 2 for mask_token.
Add lore cron {install,uninstall,status} to manage a crontab entry that
runs lore sync on a configurable interval. Supports both human and robot
output modes.
Core implementation (src/core/cron.rs):
- install_cron: appends a tagged crontab entry, detects existing entries
- uninstall_cron: removes the tagged entry
- cron_status: reads crontab + checks last-sync time from the database
- Unix-only (#[cfg(unix)]) — compiles out on Windows
CLI wiring:
- CronAction enum and CronArgs in cli/mod.rs with after_help examples
- Robot JSON envelope with RobotMeta timing for all 3 sub-actions
- Dispatch in main.rs
Also in this commit:
- Add after_help example blocks to Status, Auth, Doctor, Init, Migrate,
Health commands for better discoverability
- Add LORE_ICONS env var documentation to CLI help text
- Simplify notes format dispatch in main.rs (removed csv/jsonl paths)
- Update commands/mod.rs re-exports for cron + notes cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove print_list_notes_csv, print_list_notes_jsonl, and csv_escape from
the notes list command. The --format flag's csv and jsonl variants added
complexity without meaningful adoption — robot mode already provides
structured JSON output. Notes now have two output paths: human (default)
and JSON (--robot).
Also removes the corresponding test coverage (csv_escape, csv_output).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add NoColorExpansion correction rule that rewrites --no-color into the
two-arg form --color never, matching clap's expected syntax. The caller
detects the rule variant and inserts the second arg.
Also: add --lock to the sync command's known flags, and remove --format
from the notes command's known flags (format selection was removed).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace serde_json::to_string(&output).unwrap() with match-based error
handling across all robot-mode JSON printers. On serialization failure,
the error is now written to stderr instead of panicking. This hardens
the CLI against unexpected Serialize failures in production.
Affected commands: count (2), embed, generate-docs, ingest (2), search,
stats, sync (2), sync-status, timeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add structured tracing spans to trace and file-history pipelines so debug
logging (-vv) shows path resolution counts, MR match counts, and discussion
counts at each stage. This makes empty-result debugging straightforward.
Add a hints field to TraceResult and FileHistoryResult that carries
machine-readable diagnostic strings explaining *why* results may be empty
(e.g., "Run 'lore sync' to fetch MR file changes"). The CLI renders these
as info lines; robot mode includes them in JSON when non-empty.
Also: fix filter_map(Result::ok) → collect::<Result> in trace.rs (same
pattern fixed in prior commit for file_history/path_resolver), and switch
conn.prepare → conn.prepare_cached for the MR query.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace .filter_map(Result::ok).collect() with .collect::<Result<Vec<_>,_>>()?
in rename chain resolution and suffix probe queries. The old pattern silently
discarded database errors, making failures invisible. Now any rusqlite error
propagates to the caller immediately.
Affected: resolve_rename_chain (2 queries) and resolve_ambiguity (1 query).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split the monolithic who.rs into a who/ directory module with 7 focused
files. The 5 query modes (expert, workload, reviews, active, overlap) share
no query-level code — only types and a few small helpers — making this a
clean mechanical extraction.
New structure:
who/types.rs — all pub result structs/enums (~185 lines)
who/mod.rs — dispatch, shared helpers, JSON envelope (~428 lines)
who/expert.rs — query + render + json for expert mode (~839 lines)
who/workload.rs — query + render + json for workload mode (~370 lines)
who/reviews.rs — query + render + json for reviews mode (~214 lines)
who/active.rs — query + render + json for active mode (~299 lines)
who/overlap.rs — query + render + json for overlap mode (~323 lines)
Token savings: an agent working on any single mode now loads ~400-960 lines
instead of 2,598 (63-85% reduction). Public API unchanged — parent mod.rs
re-exports are identical.
Test re-exports use #[cfg(test)] use (not pub use) to avoid visibility
conflicts with pub(super) items in submodules. All 79 who tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Workload and active modes now exclude discussions on closed issues and
merged/closed MRs by default. Adds --include-closed flag to restore
the previous behavior when needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a bare filename like 'operators.ts' matches multiple full paths,
check if they are the same file connected by renames (via BFS on
mr_file_changes). If so, auto-resolve to the newest path instead of
erroring. Also wires path resolution into file-history and trace
commands so bare filenames work everywhere.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Overhaul the sync command's human output to use semantic colors and a
cleaner rendering architecture. The changes fall into four areas:
Stage lines: Replace direct finish_stage() calls with an
emit_stage_line/emit_stage_block pattern that clears the spinner first,
then prints static lines via MultiProgress::suspend. Stage icons are
now color-coded green (success) or yellow (warning) via color_icon().
A separate "Status" stage line now appears after Issues, summarizing
work-item status enrichment across all projects.
Sub-rows: Replace the imperative print_issue_sub_rows/print_mr_sub_rows
functions with functional issue_sub_rows(), mr_sub_rows(), and new
status_sub_rows() that return Vec<String>. Project paths use
Theme::muted(), error/failure counts use Theme::warning(), and
separators use the dim middle-dot style. Sub-rows are printed atomically
with their parent stage line to avoid interleaving with spinners.
Summary: In print_sync(), counts now use Theme::info().bold() for visual
pop, detail-line separators are individually styled (dim middle-dot),
and a new "Sync completed with issues" headline appears when any stage
had failures. Document errors and embedding failures are surfaced in
both the doc-parts line and the errors line.
Tests: Full coverage for append_failures, summarize_status_enrichment,
should_print_timings, issue_sub_rows, mr_sub_rows, and status_sub_rows.
Add -t/--timings flag to the sync subcommand, allowing users to opt
into a per-stage timing breakdown after the sync summary. Wire the flag
through main.rs into print_sync() which passes it to the new
should_print_timings() gate.
Enrich the data structures that flow through the sync pipeline so
downstream renderers have full error visibility:
- ProjectSummary gains status_errors (issue-side status enrichment
failures per project)
- ProjectStatusEnrichment gains path (project path for sub-row display)
- SyncResult gains documents_errored and embedding_failed so the
summary can surface doc-gen and embed failures separately
- Autocorrect table updated with --timings for fuzzy flag matching