Skip to content

Add Copilot CLI V1 capture with hooks, sync, watch, and status - #73

Open
duncankmckinnon wants to merge 53 commits into
mainfrom
copilot-capture-v1
Open

Add Copilot CLI V1 capture with hooks, sync, watch, and status#73
duncankmckinnon wants to merge 53 commits into
mainfrom
copilot-capture-v1

Conversation

@duncankmckinnon

Copy link
Copy Markdown
Owner

Summary

GitHub Copilot CLI recordings are ingested into a local schema-v1 archive of transcript, SQLite, hook, and metadata source records so later V2 projections can run without recapture. thirdeye add --copilot and remove --copilot install or drop only the owned user-level hook file; thirdeye copilot sync, watch, and status resolve --source-home, then COPILOT_HOME, then ~/.copilot, and never export Copilot content. Captured sessions appear in existing list/show/events/search/tail and generic UI event views as raw envelopes, not reconstructed turns or UsageStore rows.

Changes

  • Add capture contracts in src/thirdeye/platforms/copilot/{types,constants,identity}.py: schema version 1 TypedDicts, invocation-time source-home resolution, SHA-256 source_key, and stored IDs copilot-<source_key[:16]>-<native_id> with native-ID and path-traversal rejection.
  • Read session-state/**/events.jsonl and workspace.yaml (transcript.py) and allowlisted session-store.db tables (database.py: sessions, turns, assistant_usage_events) as bounded SourceSlices with locators, incomplete-line waiting, and read-only WAL-aware SQLite (busy timeout 100ms).
  • Persist composed SourceBatches through a per-session lock/journal (archive.py, state.py) that recovers after crash, deduplicates committed source IDs, and writes copilot_transcript/copilot_database/copilot_hook/copilot_metadata events; SessionWriter.append accepts a validated source timestamp; fsops.sync_directory makes journal publish durable.
  • Parse hook stdin into SourceRecords and spool them atomically before taking the capture lock (hook_payload.py, spool.py); install/remove only $COPILOT_HOME/hooks/thirdeye.json (install.py); register the thirdeye-copilot-hook dispatcher.
  • Compose discovery and capture (sources.py, capture.py); make hook receipt fail-open and nonblocking with a bounded follow-up worker (hooks.py, followup.py); add foreground poll-and-ingest (watch.py) and health reporting (status.py).
  • Register thirdeye copilot sync|watch|status, add/remove --copilot, and Copilot as a setup tracing platform; treat Copilot camelCase hook names as native in provenance.py.
  • Document V1 commands and Windows caveats; include Copilot CLI 1.0.83 fixtures plus labeled synthetic V1 cases.
  • Add behavioral coverage for contracts, readers, archive recovery, hooks, composition, watch/status, CLI registration, and generic UI views.

Test plan

  • uv run python -m pytest tests/test_copilot_*.py tests/test_add_command.py tests/test_setup_command.py tests/test_provenance.py tests/web/test_copilot_capture_views.py
  • thirdeye add --copilot writes $COPILOT_HOME/hooks/thirdeye.json (default ~/.copilot/hooks/thirdeye.json) with a resolvable thirdeye-copilot-hook command; thirdeye remove --copilot removes only owned entries and leaves captured sessions and other hooks in place
  • Point --source-home at a home populated from tests/fixtures/copilot/cli-1.0.83 and run thirdeye copilot sync: counts print, prompt bodies stay out of diagnostics, a missing --session-id exits nonzero, and empty discovery is a successful no-op
  • Confirm hook receipt spools before capture, follow-up is nonblocking, and thirdeye copilot status reports resolved paths, readable capabilities, configured hooks, last observed hook, last successful import, and pending follow-up; missing hooks are informational while source errors affect exit status
  • thirdeye copilot watch --source-home PATH --interval 1 performs an initial sync, picks up SQLite-only updates, rejects intervals below 0.1s, and exits cleanly on SIGINT with no remote export
  • Captured sessions show in thirdeye list/show/events/search/tail and generic UI event views as copilot_transcript/copilot_database/copilot_hook/copilot_metadata envelopes with schema_version=1, without turn-sliced views or UsageStore rows

🤖 Generated by workbench pr_writer

duncankmckinnon and others added 30 commits September 10, 2026 13:55
Freeze identity validation, schema version constants, JSON round-trips, and fixture semantics for parallel V1 consumers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep SourceBatch free of SourceSlice fields, document that child hook session IDs are agent IDs, and freeze prefix-collision detection as an archive metadata check.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover parse_hook normalization, spool durability, and copilot provenance regressions so the hook observations task can be verified independently of ingestion.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Cover discovery, all three allowed tables, WAL reads, row revisions,
pagination, schema diagnostics, and cli-1.0.83 usage fixture ingestion.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover commit/cursor/retrieval, timestamp preservation, deduplication,
lifecycle hooks, prefix-collision rejection, fault-injected crash recovery,
and stale-cursor contention with synthetic SourceBatch inputs.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover discovery, bounded reads, malformed lines, snapshot semantics, and cli-1.0.83 fixture ingestion.

Co-authored-by: Cursor <cursoragent@cursor.com>
ISO source times are parsed rather than accepted by string shape, and read/ack skip incomplete hook records with diagnostics.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover install/uninstall merge behavior, shell quoting, malformed config rejection, source-home resolution, and complete event-set verification.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reopen a frozen snapshot after an incomplete tail so appended newlines are ingested, hash the full consumed prefix so same-inode rewrites replay, and reject source files whose resolved paths escape the session directory.

Co-authored-by: Cursor <cursoragent@cursor.com>
Discover sessions from every allowlisted table, identify rows from PRAGMA primary keys, close read-only connections, and paginate against a logical snapshot so live WAL metadata cannot starve later rows.

Co-authored-by: Cursor <cursoragent@cursor.com>
…malformed hook documents.

Live installation must not write a hook that cannot run, unknown non-list hook values must be left unchanged, and add/setup needs the Copilot home, restart, status, and watch guidance.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep closed sessions closed on append, checkpoint lifecycle with the journal, strip contention markers from stored cursors, and finish recovery from load/iter so a crash cannot skip source records or invent timestamps.

Co-authored-by: Cursor <cursoragent@cursor.com>
Key the cursor to the database file incarnation instead of the session snapshot hash so inserts and updates cannot starve later rows.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover source discovery/batch merging, capture sync idempotency, hook spooling, stale-cursor retry, and cli-1.0.83 fixture integration.

Co-authored-by: Cursor <cursoragent@cursor.com>
…errors.

Preserve source exhaustion so sync pages an invocation-time snapshot, keep journal recovery counts after a stale cursor retry, and surface unreadable sources instead of a silent no-op.

Co-authored-by: Cursor <cursoragent@cursor.com>
Stop sync from paging a live SQLite source indefinitely by recording snapshot_end on the composed database cursor and bounding the drain loop.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add assertions for all source kinds, turn-slicer exclusion, hook search, and usage dashboard boundaries so generic views stay raw without V2 projections.

Co-authored-by: Cursor <cursoragent@cursor.com>
duncankmckinnon and others added 23 commits September 10, 2026 15:34
Cover change detection, retry semantics, health reporting, and installation state without requiring CLI registration or hook runtime imports.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover event dispatch, fail-open semantics, env tagging, lease coalescing, and bounded follow-up workers.

Co-authored-by: Cursor <cursoragent@cursor.com>
…usage

Make the compatibility suite fail if token dashboards ingest database snapshots, if search omits tool arguments, or if the outer versioned SourceRecord envelope is confused with payload fields.

Co-authored-by: Cursor <cursoragent@cursor.com>
…eporting.

Watch now treats source disappearance as a one-shot poll, not a permanent error loop, and status validates full source keys, probes real I/O, and surfaces spool diagnostics.

Co-authored-by: Cursor <cursoragent@cursor.com>
Hook and follow-up workers now fail immediately on a busy archive lock instead of waiting, pass explicit event names through to parse_hook, and attach env tags to the written observation rather than the last matching payload.

Co-authored-by: Cursor <cursoragent@cursor.com>
Hook-time env tags no longer walk the full session index, while still matching the observation written at the front of the batch.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover copilot sync/watch/status wiring, add/remove --copilot integration,
setup multiselect, console script registration, and a fixture-backed sync
composition test pending the registration-and-commands implementation.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ach the existing capture layer.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover platform flag listing, sync error propagation, status error rendering, and hook entrypoint importability.

Co-authored-by: Cursor <cursoragent@cursor.com>
Status no longer prints prompt bodies, selected-ID sync treats imported diagnostics as success rather than missing, and path-resolution failures become Click errors instead of tracebacks.

Co-authored-by: Cursor <cursoragent@cursor.com>
… close.

Status now reads live copilot.followup.json leases, and archive lets the last top-level lifecycle hook in a composed batch win so a spooled sessionEnd can close the session.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant