agent-dump 1.2.2__tar.gz → 1.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agent_dump-1.2.2 → agent_dump-1.2.3}/Cargo.lock +7 -7
- {agent_dump-1.2.2 → agent_dump-1.2.3}/Cargo.toml +1 -1
- {agent_dump-1.2.2 → agent_dump-1.2.3}/PKG-INFO +3 -3
- {agent_dump-1.2.2 → agent_dump-1.2.3}/README.md +2 -2
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/compat/json/diagnostic.rs +22 -3
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/compat/json.rs +12 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/output/export.rs +9 -38
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/claude/mod.rs +19 -20
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/claude/transcript.rs +5 -1
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/codex/enrichment.rs +4 -1
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/codex/mod.rs +10 -4
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/codex/transcript.rs +11 -3
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/contract.rs +1 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/cursor/mod.rs +5 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/desktop/mod.rs +4 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/desktop/tests.rs +33 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/files.rs +64 -22
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/jsonl.rs +60 -15
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/kimi/mod.rs +10 -4
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/kimi/transcript.rs +13 -1
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/kimi/wire.rs +17 -14
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/pi/mod.rs +10 -4
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/registry.rs +21 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/sqlite/mod.rs +43 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/filter.rs +10 -6
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/index/tests.rs +17 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/index.rs +33 -18
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/scanner.rs +5 -4
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/session/cache/tests.rs +5 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/pyproject.toml +1 -1
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/locales/en.json +1 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/locales/zh.json +1 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/insight-handoff.txt +1 -1
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/pm-handoff.txt +1 -1
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/llm.rs +45 -7
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/collect.rs +9 -20
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/interactive.rs +23 -20
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/list.rs +19 -27
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/machine.rs +17 -29
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/maintenance.rs +13 -8
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/reader.rs +1 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/uri.rs +3 -4
- {agent_dump-1.2.2 → agent_dump-1.2.3}/LICENSE +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/Cargo.toml +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/compat/json/encoding.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/compat/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/compat/value.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/config.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/lib.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/output/diagnostics.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/output/formats.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/output/i18n.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/output/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/output/render.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/parallel.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/codex/patch.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/cursor/transcript.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/desktop/cherry.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/desktop/deepchat.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/desktop/minimax.rs +6 -6
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/error.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/pi/transcript.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/source_tests.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/sqlite/connection.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/sqlite/legacy.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/sqlite/v2.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/title.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/context.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/read.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/text.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/query/transcript.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/session/assembly.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/session/cache.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/session/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/session/timestamp.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/storage/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/storage/private_files.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/storage/source_io.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/.gitattributes +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/README.md +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/insight-chunk.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/insight-merge.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/insight-report.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/insight-retry.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/pm-chunk.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/pm-merge.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/pm-report.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/pm-retry.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/read-session-en.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/read-session-zh.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/system.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/resources/prompts/uri.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/rust-toolchain.toml +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/rustfmt.toml +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/cli_args.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/events.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/handoff.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/log.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/model.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/progress.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/prompts.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/reduction.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/sessions.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/collect/summary.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/command.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/date_input.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/main.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/shortcut.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/terminal/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/terminal/reader.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/terminal/selector.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/terminal/tui.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/config.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.3}/src/workflows/read.rs +0 -0
|
@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
|
|
10
10
|
|
|
11
11
|
[[package]]
|
|
12
12
|
name = "agent-dump"
|
|
13
|
-
version = "1.2.
|
|
13
|
+
version = "1.2.3"
|
|
14
14
|
dependencies = [
|
|
15
15
|
"agent-dump-core",
|
|
16
16
|
"caseless",
|
|
@@ -837,9 +837,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
|
837
837
|
|
|
838
838
|
[[package]]
|
|
839
839
|
name = "jiff"
|
|
840
|
-
version = "0.2.
|
|
840
|
+
version = "0.2.38"
|
|
841
841
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
842
|
-
checksum = "
|
|
842
|
+
checksum = "b2b005715dcbeb0089a3c0dab99f2ff1cc3b2525323552703d648585d342a383"
|
|
843
843
|
dependencies = [
|
|
844
844
|
"defmt",
|
|
845
845
|
"jiff-core",
|
|
@@ -864,9 +864,9 @@ dependencies = [
|
|
|
864
864
|
|
|
865
865
|
[[package]]
|
|
866
866
|
name = "jiff-static"
|
|
867
|
-
version = "0.2.
|
|
867
|
+
version = "0.2.38"
|
|
868
868
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
869
|
-
checksum = "
|
|
869
|
+
checksum = "2cc9817253cf7c7ee4684451bd327e88d6f3658014e54a29198625590650695c"
|
|
870
870
|
dependencies = [
|
|
871
871
|
"jiff-core",
|
|
872
872
|
"proc-macro2",
|
|
@@ -1859,9 +1859,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|
|
1859
1859
|
|
|
1860
1860
|
[[package]]
|
|
1861
1861
|
name = "uuid"
|
|
1862
|
-
version = "1.
|
|
1862
|
+
version = "1.28.0"
|
|
1863
1863
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1864
|
-
checksum = "
|
|
1864
|
+
checksum = "7cc1186384beb7dd8eedea376413fd654937285ea6c9cfbb928dc3043ea4b606"
|
|
1865
1865
|
dependencies = [
|
|
1866
1866
|
"getrandom 0.4.3",
|
|
1867
1867
|
"js-sys",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-dump
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Classifier: Environment :: Console
|
|
5
5
|
Classifier: License :: OSI Approved :: MIT License
|
|
6
6
|
Classifier: Programming Language :: Rust
|
|
@@ -462,7 +462,7 @@ File discovery failures include partially unreadable providers. Valid sessions r
|
|
|
462
462
|
|
|
463
463
|
When some session reads or summaries fail, collection continues with successful sessions. The saved Markdown includes a fixed incomplete-report notice with failure and included-session counts; an entirely failed run still fails.
|
|
464
464
|
|
|
465
|
-
Collect discovers candidate sessions without a creation-time cutoff and processes user/assistant visible text only within the requested local dates. A session spanning several days is split into separate daily units before summarization; session counts remain unique URI counts. Text without a reliable timestamp (including undated Kimi context and inferred Cursor times) belongs to no date and is excluded without being reported as a coverage gap. No session creation/update time is substituted. Query filters select candidates; limits apply to unique sessions after text-date filtering. Events, including long individual messages, are split into chunks of at most 3,200 Unicode characters including labels. Chunk summaries are merged in groups of at most eight; large final reports are rendered in separate source-preserving groups. Model inputs are limited to 64,000 characters per request. Oversized metadata or derived summaries fail explicitly; source text is never silently truncated. Partial reports list omitted session URIs. Full input coverage does not mean a summary preserves every detail.
|
|
465
|
+
Collect discovers candidate sessions without a creation-time cutoff and processes user/assistant visible text only within the requested local dates. A session spanning several days is split into separate daily units before summarization; session counts remain unique URI counts. Text without a reliable timestamp (including undated Kimi context and inferred Cursor times) belongs to no date and is excluded without being reported as a coverage gap. No session creation/update time is substituted. Query filters select candidates; limits apply to unique sessions after text-date filtering. Events, including long individual messages, are split into chunks of at most 3,200 Unicode characters including labels. Chunk summaries are merged in groups of at most eight; large final reports are rendered in separate source-preserving groups. Model inputs are limited to 64,000 characters per request. Oversized metadata or derived summaries fail explicitly; source text is never silently truncated. A final report or `--summary` reply that stops at the model output token limit is treated as a failed request, not saved as complete. Partial reports list omitted session URIs. Full input coverage does not mean a summary preserves every detail.
|
|
466
466
|
|
|
467
467
|
PM summaries merge sessions only within the same date and known working directory. Sessions without a working directory retain separate attribution.
|
|
468
468
|
|
|
@@ -559,7 +559,7 @@ Pass `locations[].locator` from search unchanged to `--message`. Positions are o
|
|
|
559
559
|
|
|
560
560
|
`--locate` requires `--search`. It returns messages containing any search term, respecting role filters, while all terms must still match the session. Title-only matches have empty locations; failed location reads have null locations and partial status. Search without --locate is unchanged.
|
|
561
561
|
|
|
562
|
-
`--message` cannot combine with `--head` or `--summary`. Without `--format`, it prints context; `--json` writes a context envelope to stdout with kind=context and data containing uri, locator, total_messages, start/end and messages (position plus normalized message). Invalid or stale locators exit nonzero; JSON diagnostics go only to stderr.
|
|
562
|
+
`--message` cannot combine with `--head` or `--summary`. Without `--format`, it prints context; `--json` writes a context envelope to stdout with kind=context, status (partial when recoverable source diagnostics occur) and data containing uri, locator, total_messages, start/end and messages (position plus normalized message). Invalid or stale locators exit nonzero; JSON diagnostics go only to stderr.
|
|
563
563
|
|
|
564
564
|
Use `--format json,markdown` to export the selected context. Files are named `<id>.messages-<start>-<end>.json` / `.md` under the Provider's output directory, separate from full-session exports. Both formats retain the canonical Session URI, the locator (revision plus target position), the absolute message range, and status. JSON retains normalized message records; Markdown renders their searchable text. Recoverable source diagnostics mark the file `partial` and are reported on stderr. Stale locators are rejected before file creation. Provider format restrictions still apply; raw/print file formats and `--json` with file-export options are rejected. `--output` requires an explicit `--format`; output-directory defaults follow full-session export rules.
|
|
565
565
|
|
|
@@ -438,7 +438,7 @@ File discovery failures include partially unreadable providers. Valid sessions r
|
|
|
438
438
|
|
|
439
439
|
When some session reads or summaries fail, collection continues with successful sessions. The saved Markdown includes a fixed incomplete-report notice with failure and included-session counts; an entirely failed run still fails.
|
|
440
440
|
|
|
441
|
-
Collect discovers candidate sessions without a creation-time cutoff and processes user/assistant visible text only within the requested local dates. A session spanning several days is split into separate daily units before summarization; session counts remain unique URI counts. Text without a reliable timestamp (including undated Kimi context and inferred Cursor times) belongs to no date and is excluded without being reported as a coverage gap. No session creation/update time is substituted. Query filters select candidates; limits apply to unique sessions after text-date filtering. Events, including long individual messages, are split into chunks of at most 3,200 Unicode characters including labels. Chunk summaries are merged in groups of at most eight; large final reports are rendered in separate source-preserving groups. Model inputs are limited to 64,000 characters per request. Oversized metadata or derived summaries fail explicitly; source text is never silently truncated. Partial reports list omitted session URIs. Full input coverage does not mean a summary preserves every detail.
|
|
441
|
+
Collect discovers candidate sessions without a creation-time cutoff and processes user/assistant visible text only within the requested local dates. A session spanning several days is split into separate daily units before summarization; session counts remain unique URI counts. Text without a reliable timestamp (including undated Kimi context and inferred Cursor times) belongs to no date and is excluded without being reported as a coverage gap. No session creation/update time is substituted. Query filters select candidates; limits apply to unique sessions after text-date filtering. Events, including long individual messages, are split into chunks of at most 3,200 Unicode characters including labels. Chunk summaries are merged in groups of at most eight; large final reports are rendered in separate source-preserving groups. Model inputs are limited to 64,000 characters per request. Oversized metadata or derived summaries fail explicitly; source text is never silently truncated. A final report or `--summary` reply that stops at the model output token limit is treated as a failed request, not saved as complete. Partial reports list omitted session URIs. Full input coverage does not mean a summary preserves every detail.
|
|
442
442
|
|
|
443
443
|
PM summaries merge sessions only within the same date and known working directory. Sessions without a working directory retain separate attribution.
|
|
444
444
|
|
|
@@ -535,7 +535,7 @@ Pass `locations[].locator` from search unchanged to `--message`. Positions are o
|
|
|
535
535
|
|
|
536
536
|
`--locate` requires `--search`. It returns messages containing any search term, respecting role filters, while all terms must still match the session. Title-only matches have empty locations; failed location reads have null locations and partial status. Search without --locate is unchanged.
|
|
537
537
|
|
|
538
|
-
`--message` cannot combine with `--head` or `--summary`. Without `--format`, it prints context; `--json` writes a context envelope to stdout with kind=context and data containing uri, locator, total_messages, start/end and messages (position plus normalized message). Invalid or stale locators exit nonzero; JSON diagnostics go only to stderr.
|
|
538
|
+
`--message` cannot combine with `--head` or `--summary`. Without `--format`, it prints context; `--json` writes a context envelope to stdout with kind=context, status (partial when recoverable source diagnostics occur) and data containing uri, locator, total_messages, start/end and messages (position plus normalized message). Invalid or stale locators exit nonzero; JSON diagnostics go only to stderr.
|
|
539
539
|
|
|
540
540
|
Use `--format json,markdown` to export the selected context. Files are named `<id>.messages-<start>-<end>.json` / `.md` under the Provider's output directory, separate from full-session exports. Both formats retain the canonical Session URI, the locator (revision plus target position), the absolute message range, and status. JSON retains normalized message records; Markdown renders their searchable text. Recoverable source diagnostics mark the file `partial` and are reported on stderr. Stale locators are rejected before file creation. Provider format restrictions still apply; raw/print file formats and `--json` with file-export options are rejected. `--output` requires an explicit `--format`; output-directory defaults follow full-session export rules.
|
|
541
541
|
|
|
@@ -39,6 +39,7 @@ pub fn syntax(text: &str, original: &serde_json::Error) -> Error {
|
|
|
39
39
|
let mut parser = Parser {
|
|
40
40
|
chars: text.chars().collect(),
|
|
41
41
|
index: 0,
|
|
42
|
+
depth: 0,
|
|
42
43
|
};
|
|
43
44
|
let failure = if text.starts_with('\u{feff}') {
|
|
44
45
|
Some(("Unexpected UTF-8 BOM (decode using utf-8-sig)", 0))
|
|
@@ -49,7 +50,9 @@ pub fn syntax(text: &str, original: &serde_json::Error) -> Error {
|
|
|
49
50
|
.then_some(("Extra data", parser.index))
|
|
50
51
|
})
|
|
51
52
|
};
|
|
52
|
-
let message = if let Some((message, position)) =
|
|
53
|
+
let message = if let Some((message, position)) =
|
|
54
|
+
failure.filter(|(message, _)| *message != TOO_DEEP)
|
|
55
|
+
{
|
|
53
56
|
let before = &parser.chars[..position];
|
|
54
57
|
let line = before.iter().filter(|c| **c == '\n').count() + 1;
|
|
55
58
|
let column = position
|
|
@@ -70,9 +73,14 @@ pub fn syntax(text: &str, original: &serde_json::Error) -> Error {
|
|
|
70
73
|
|
|
71
74
|
type Failure = (&'static str, usize);
|
|
72
75
|
|
|
76
|
+
// Matches serde_json's recursion limit so deep input cannot overflow the stack.
|
|
77
|
+
const MAX_DEPTH: usize = 128;
|
|
78
|
+
const TOO_DEEP: &str = "recursion limit exceeded";
|
|
79
|
+
|
|
73
80
|
struct Parser {
|
|
74
81
|
chars: Vec<char>,
|
|
75
82
|
index: usize,
|
|
83
|
+
depth: usize,
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
impl Parser {
|
|
@@ -107,8 +115,19 @@ impl Parser {
|
|
|
107
115
|
self.whitespace();
|
|
108
116
|
match self.chars.get(self.index).copied() {
|
|
109
117
|
Some('"') => self.string(),
|
|
110
|
-
Some('{')
|
|
111
|
-
|
|
118
|
+
Some('{' | '[') if self.depth == MAX_DEPTH => {
|
|
119
|
+
Err((TOO_DEEP, self.index))
|
|
120
|
+
}
|
|
121
|
+
Some(open @ ('{' | '[')) => {
|
|
122
|
+
self.depth += 1;
|
|
123
|
+
let result = if open == '{' {
|
|
124
|
+
self.object()
|
|
125
|
+
} else {
|
|
126
|
+
self.array()
|
|
127
|
+
};
|
|
128
|
+
self.depth -= 1;
|
|
129
|
+
result
|
|
130
|
+
}
|
|
112
131
|
_ => {
|
|
113
132
|
for word in
|
|
114
133
|
["null", "true", "false", "NaN", "Infinity", "-Infinity"]
|
|
@@ -156,3 +156,15 @@ impl serde_json::ser::Formatter for Formatter {
|
|
|
156
156
|
writer.write_all(output.as_bytes())
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
+
|
|
160
|
+
#[cfg(test)]
|
|
161
|
+
mod tests {
|
|
162
|
+
use super::*;
|
|
163
|
+
|
|
164
|
+
#[test]
|
|
165
|
+
fn deep_nesting_reports_error_without_overflow() {
|
|
166
|
+
let error = from_str(&"[".repeat(100_000)).unwrap_err();
|
|
167
|
+
|
|
168
|
+
assert!(error.to_string().starts_with("recursion limit exceeded"));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -59,25 +59,14 @@ fn filename(id: &str) -> crate::Result<String> {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
fn absolute_existing_ancestor(path: &Path) -> crate::Result<PathBuf> {
|
|
63
|
-
if path.exists() {
|
|
64
|
-
return Ok(path.canonicalize()?);
|
|
65
|
-
}
|
|
66
|
-
let parent = path.parent().ok_or("Cannot resolve output path")?;
|
|
67
|
-
Ok(absolute_existing_ancestor(parent)?
|
|
68
|
-
.join(path.file_name().ok_or("Invalid output path")?))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
62
|
fn write(
|
|
72
63
|
output: &Path,
|
|
73
64
|
session_id: &str,
|
|
74
65
|
suffix: &str,
|
|
75
|
-
source_root: &Path,
|
|
76
66
|
contents: impl FnOnce(&mut fs::File) -> crate::Result<()>,
|
|
77
67
|
) -> crate::Result<PathBuf> {
|
|
78
68
|
let directory = std::path::absolute(output)?;
|
|
79
|
-
|
|
80
|
-
if resolved.starts_with(source_root.canonicalize()?) {
|
|
69
|
+
if crate::providers::registry::inside_source(&directory)? {
|
|
81
70
|
return Err(
|
|
82
71
|
"Export output must be outside the Provider source directory"
|
|
83
72
|
.into(),
|
|
@@ -114,10 +103,9 @@ pub fn json(
|
|
|
114
103
|
session_id: &str,
|
|
115
104
|
data: &impl serde::Serialize,
|
|
116
105
|
output: &Path,
|
|
117
|
-
source_root: &Path,
|
|
118
106
|
suffix: &str,
|
|
119
107
|
) -> crate::Result<PathBuf> {
|
|
120
|
-
write(output, session_id, suffix,
|
|
108
|
+
write(output, session_id, suffix, |file| {
|
|
121
109
|
let mut writer = io::BufWriter::new(file);
|
|
122
110
|
data.serialize(&mut serde_json::Serializer::with_formatter(
|
|
123
111
|
&mut writer,
|
|
@@ -132,19 +120,17 @@ pub fn markdown(
|
|
|
132
120
|
session_id: &str,
|
|
133
121
|
text: &str,
|
|
134
122
|
output: &Path,
|
|
135
|
-
source_root: &Path,
|
|
136
123
|
) -> crate::Result<PathBuf> {
|
|
137
|
-
markdown_with_suffix(session_id, text, output,
|
|
124
|
+
markdown_with_suffix(session_id, text, output, ".md")
|
|
138
125
|
}
|
|
139
126
|
|
|
140
127
|
fn markdown_with_suffix(
|
|
141
128
|
session_id: &str,
|
|
142
129
|
text: &str,
|
|
143
130
|
output: &Path,
|
|
144
|
-
source_root: &Path,
|
|
145
131
|
suffix: &str,
|
|
146
132
|
) -> crate::Result<PathBuf> {
|
|
147
|
-
write(output, session_id, suffix,
|
|
133
|
+
write(output, session_id, suffix, |file| {
|
|
148
134
|
if cfg!(windows) {
|
|
149
135
|
file.write_all(text.replace('\n', "\r\n").as_bytes())?;
|
|
150
136
|
} else {
|
|
@@ -158,9 +144,8 @@ pub fn raw(
|
|
|
158
144
|
session_id: &str,
|
|
159
145
|
source: &Path,
|
|
160
146
|
output: &Path,
|
|
161
|
-
source_root: &Path,
|
|
162
147
|
) -> crate::Result<PathBuf> {
|
|
163
|
-
write(output, session_id, ".raw.jsonl",
|
|
148
|
+
write(output, session_id, ".raw.jsonl", |file| {
|
|
164
149
|
io::copy(&mut fs::File::open(source)?, file)?;
|
|
165
150
|
Ok(())
|
|
166
151
|
})
|
|
@@ -179,7 +164,6 @@ impl Excerpt<'_> {
|
|
|
179
164
|
&self,
|
|
180
165
|
format: crate::output::formats::OutputFormat,
|
|
181
166
|
output: &Path,
|
|
182
|
-
source_root: &Path,
|
|
183
167
|
) -> crate::Result<PathBuf> {
|
|
184
168
|
use crate::output::formats::OutputFormat;
|
|
185
169
|
let suffix =
|
|
@@ -197,7 +181,6 @@ impl Excerpt<'_> {
|
|
|
197
181
|
&self.data.id,
|
|
198
182
|
&document,
|
|
199
183
|
output,
|
|
200
|
-
source_root,
|
|
201
184
|
&format!("{suffix}.json"),
|
|
202
185
|
)
|
|
203
186
|
}
|
|
@@ -211,7 +194,6 @@ impl Excerpt<'_> {
|
|
|
211
194
|
self.incomplete,
|
|
212
195
|
),
|
|
213
196
|
output,
|
|
214
|
-
source_root,
|
|
215
197
|
&format!("{suffix}.md"),
|
|
216
198
|
),
|
|
217
199
|
OutputFormat::Raw | OutputFormat::Print => {
|
|
@@ -239,17 +221,13 @@ impl SessionExport<'_> {
|
|
|
239
221
|
use crate::providers::contract::RawExport;
|
|
240
222
|
match format {
|
|
241
223
|
OutputFormat::Raw => match self.raw.as_ref().unwrap() {
|
|
242
|
-
RawExport::File(source) =>
|
|
243
|
-
&self.session.id,
|
|
244
|
-
|
|
245
|
-
output,
|
|
246
|
-
self.provider.source_root(),
|
|
247
|
-
),
|
|
224
|
+
RawExport::File(source) => {
|
|
225
|
+
raw(&self.session.id, source, output)
|
|
226
|
+
}
|
|
248
227
|
RawExport::Session => json(
|
|
249
228
|
&self.session.id,
|
|
250
229
|
self.data.unwrap(),
|
|
251
230
|
output,
|
|
252
|
-
self.provider.source_root(),
|
|
253
231
|
".raw.json",
|
|
254
232
|
),
|
|
255
233
|
},
|
|
@@ -261,13 +239,7 @@ impl SessionExport<'_> {
|
|
|
261
239
|
{
|
|
262
240
|
object.insert("summary".into(), summary.into());
|
|
263
241
|
}
|
|
264
|
-
json(
|
|
265
|
-
&self.session.id,
|
|
266
|
-
&payload,
|
|
267
|
-
output,
|
|
268
|
-
self.provider.source_root(),
|
|
269
|
-
".json",
|
|
270
|
-
)
|
|
242
|
+
json(&self.session.id, &payload, output, ".json")
|
|
271
243
|
}
|
|
272
244
|
OutputFormat::Markdown => markdown(
|
|
273
245
|
&self.session.id,
|
|
@@ -276,7 +248,6 @@ impl SessionExport<'_> {
|
|
|
276
248
|
self.data.unwrap(),
|
|
277
249
|
),
|
|
278
250
|
output,
|
|
279
|
-
self.provider.source_root(),
|
|
280
251
|
),
|
|
281
252
|
OutputFormat::Print => unreachable!(),
|
|
282
253
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
pub(super) mod transcript;
|
|
2
2
|
|
|
3
|
-
use crate::compat::value::{field, text
|
|
3
|
+
use crate::compat::value::{field, text};
|
|
4
4
|
use crate::providers::contract::{
|
|
5
5
|
DiagnosticSink, Provider, RecoverableDiagnostic,
|
|
6
6
|
};
|
|
7
|
-
use crate::providers::files::{
|
|
7
|
+
use crate::providers::files::{
|
|
8
|
+
self as file_sessions, SourceFiles, SourceRoots,
|
|
9
|
+
};
|
|
8
10
|
use crate::providers::jsonl;
|
|
9
11
|
use crate::providers::title::{basename, normalize_title};
|
|
10
12
|
use crate::session::timestamp::Timestamp;
|
|
@@ -51,7 +53,7 @@ impl Claude {
|
|
|
51
53
|
})
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
fn files(&mut self) -> crate::Result<
|
|
56
|
+
fn files(&mut self) -> crate::Result<SourceFiles> {
|
|
55
57
|
let files = self.roots.files(Some(2), |path, base| {
|
|
56
58
|
path.extension().is_some_and(|ext| ext == "jsonl")
|
|
57
59
|
&& path.parent() != Some(base)
|
|
@@ -112,11 +114,14 @@ impl Claude {
|
|
|
112
114
|
let mut skipped = 0;
|
|
113
115
|
for entry in value["entries"].as_array().into_iter().flatten() {
|
|
114
116
|
let id = text(&entry["sessionId"]);
|
|
115
|
-
|
|
117
|
+
let summary = &entry["summary"];
|
|
118
|
+
if id.trim().is_empty()
|
|
119
|
+
|| !(summary.is_null() || summary.is_string())
|
|
120
|
+
{
|
|
116
121
|
skipped += 1;
|
|
117
122
|
continue;
|
|
118
123
|
}
|
|
119
|
-
titles.insert(id.to_owned(),
|
|
124
|
+
titles.insert(id.to_owned(), summary.clone());
|
|
120
125
|
}
|
|
121
126
|
if skipped > 0 {
|
|
122
127
|
diagnostics(RecoverableDiagnostic::TitleCacheEntriesSkipped {
|
|
@@ -149,21 +154,11 @@ impl Claude {
|
|
|
149
154
|
.into_owned();
|
|
150
155
|
let created_at = parse_timestamp(text(&header["timestamp"]))
|
|
151
156
|
.unwrap_or(Timestamp::try_from(path.metadata()?.modified()?)?);
|
|
152
|
-
let explicit =
|
|
157
|
+
let explicit = self
|
|
153
158
|
.titles(project, diagnostics)?
|
|
154
159
|
.get(&id)
|
|
155
|
-
.
|
|
156
|
-
|
|
157
|
-
Some(Value::String(title)) => normalize_title(title),
|
|
158
|
-
Some(value) => {
|
|
159
|
-
let kind = crate::compat::value::type_name(value);
|
|
160
|
-
return Err(format!(
|
|
161
|
-
"expected string or bytes-like object, got '{kind}'"
|
|
162
|
-
)
|
|
163
|
-
.into());
|
|
164
|
-
}
|
|
165
|
-
None => None,
|
|
166
|
-
};
|
|
160
|
+
.and_then(Value::as_str)
|
|
161
|
+
.and_then(normalize_title);
|
|
167
162
|
let first_user = scan
|
|
168
163
|
.records
|
|
169
164
|
.iter()
|
|
@@ -244,7 +239,7 @@ impl Provider for Claude {
|
|
|
244
239
|
) -> crate::Result<crate::providers::contract::Discovery> {
|
|
245
240
|
self.titles.clear();
|
|
246
241
|
file_sessions::discover(
|
|
247
|
-
|
|
242
|
+
self.files()?,
|
|
248
243
|
days,
|
|
249
244
|
true,
|
|
250
245
|
Self::scan,
|
|
@@ -261,7 +256,7 @@ impl Provider for Claude {
|
|
|
261
256
|
let files = self.files()?;
|
|
262
257
|
file_sessions::find(
|
|
263
258
|
self.roots.base.clone().as_deref(),
|
|
264
|
-
|
|
259
|
+
files,
|
|
265
260
|
id,
|
|
266
261
|
|path| path.file_stem().is_some_and(|name| name == id),
|
|
267
262
|
|path| self.parse(path, Self::scan(path)?, diagnostics),
|
|
@@ -296,6 +291,10 @@ impl Provider for Claude {
|
|
|
296
291
|
fn source_root(&self) -> &Path {
|
|
297
292
|
self.roots.owned()
|
|
298
293
|
}
|
|
294
|
+
|
|
295
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>> {
|
|
296
|
+
self.roots.select()
|
|
297
|
+
}
|
|
299
298
|
}
|
|
300
299
|
|
|
301
300
|
#[cfg(test)]
|
{agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/claude/transcript.rs
RENAMED
|
@@ -255,12 +255,16 @@ impl Decoder {
|
|
|
255
255
|
continue;
|
|
256
256
|
}
|
|
257
257
|
let parts = output_parts(&item["content"], timestamp);
|
|
258
|
+
let mut updates = updates.clone();
|
|
259
|
+
if item["is_error"] == true {
|
|
260
|
+
updates.insert("status".into(), "error".into());
|
|
261
|
+
}
|
|
258
262
|
if let Some(tool) = backfill(
|
|
259
263
|
&mut self.messages,
|
|
260
264
|
&self.pending,
|
|
261
265
|
&call_id,
|
|
262
266
|
&parts,
|
|
263
|
-
Some(updates
|
|
267
|
+
Some(updates),
|
|
264
268
|
)? {
|
|
265
269
|
if !parts.is_empty() {
|
|
266
270
|
tool.state
|
{agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/codex/enrichment.rs
RENAMED
|
@@ -79,7 +79,10 @@ pub fn subagent_notification(
|
|
|
79
79
|
if !payload.is_object() {
|
|
80
80
|
return None;
|
|
81
81
|
}
|
|
82
|
-
let agent_id = field(&payload, "agent_id").trim()
|
|
82
|
+
let agent_id = match field(&payload, "agent_id").trim() {
|
|
83
|
+
"" => field(&payload, "agent_path").trim().to_owned(),
|
|
84
|
+
agent_id => agent_id.to_owned(),
|
|
85
|
+
};
|
|
83
86
|
let nickname = field(&payload, "nickname").trim().to_owned();
|
|
84
87
|
let completed = if payload["status"].is_object() {
|
|
85
88
|
field(&payload["status"], "completed").trim().to_owned()
|
|
@@ -6,7 +6,9 @@ use crate::compat::value::text;
|
|
|
6
6
|
use crate::providers::contract::{
|
|
7
7
|
DiagnosticSink, Provider, RecoverableDiagnostic,
|
|
8
8
|
};
|
|
9
|
-
use crate::providers::files::{
|
|
9
|
+
use crate::providers::files::{
|
|
10
|
+
self as file_sessions, SourceFiles, SourceRoots,
|
|
11
|
+
};
|
|
10
12
|
use crate::providers::jsonl;
|
|
11
13
|
use crate::providers::title::{basename, normalize_title};
|
|
12
14
|
use crate::session::timestamp::Timestamp;
|
|
@@ -87,7 +89,7 @@ impl Codex {
|
|
|
87
89
|
.cloned())
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
fn files(&mut self) -> crate::Result<
|
|
92
|
+
fn files(&mut self) -> crate::Result<SourceFiles> {
|
|
91
93
|
self.roots.files(None, |path, _| {
|
|
92
94
|
path.extension().is_some_and(|ext| ext == "jsonl")
|
|
93
95
|
})
|
|
@@ -219,7 +221,7 @@ impl Provider for Codex {
|
|
|
219
221
|
) -> crate::Result<crate::providers::contract::Discovery> {
|
|
220
222
|
self.titles = None;
|
|
221
223
|
file_sessions::discover(
|
|
222
|
-
|
|
224
|
+
self.files()?,
|
|
223
225
|
days,
|
|
224
226
|
true,
|
|
225
227
|
Self::scan,
|
|
@@ -237,7 +239,7 @@ impl Provider for Codex {
|
|
|
237
239
|
let files = self.files()?;
|
|
238
240
|
file_sessions::find(
|
|
239
241
|
self.roots.base.clone().as_deref(),
|
|
240
|
-
|
|
242
|
+
files,
|
|
241
243
|
id,
|
|
242
244
|
|path| {
|
|
243
245
|
path.file_name().is_some_and(|name| {
|
|
@@ -280,6 +282,10 @@ impl Provider for Codex {
|
|
|
280
282
|
fn source_root(&self) -> &Path {
|
|
281
283
|
self.roots.owned()
|
|
282
284
|
}
|
|
285
|
+
|
|
286
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>> {
|
|
287
|
+
self.roots.select()
|
|
288
|
+
}
|
|
283
289
|
}
|
|
284
290
|
|
|
285
291
|
#[cfg(test)]
|
{agent_dump-1.2.2 → agent_dump-1.2.3}/crates/agent-dump-core/src/providers/codex/transcript.rs
RENAMED
|
@@ -154,13 +154,17 @@ impl Decoder {
|
|
|
154
154
|
})
|
|
155
155
|
.collect::<Vec<_>>()
|
|
156
156
|
.join("\n\n");
|
|
157
|
+
let is_notification = user_text.starts_with("<subagent_notification>")
|
|
158
|
+
&& user_text.ends_with("</subagent_notification>");
|
|
157
159
|
if self.pending_plan.is_some()
|
|
158
160
|
&& role == "user"
|
|
159
161
|
&& !user_text.is_empty()
|
|
162
|
+
&& !is_notification
|
|
160
163
|
{
|
|
161
164
|
if user_text
|
|
162
165
|
.trim_start()
|
|
163
166
|
.starts_with("PLEASE IMPLEMENT THIS PLAN")
|
|
167
|
+
|| user_text == "Implement the plan."
|
|
164
168
|
{
|
|
165
169
|
self.finish_plan("success", None);
|
|
166
170
|
} else {
|
|
@@ -343,10 +347,13 @@ pub fn read(
|
|
|
343
347
|
) -> crate::Result<SessionData> {
|
|
344
348
|
let mut decoder = Decoder::default();
|
|
345
349
|
let mut stats = Stats::default();
|
|
350
|
+
let mut usage = Value::Null;
|
|
346
351
|
jsonl::scan(&session.source_path, diagnostics, |record, diagnostics| {
|
|
347
|
-
let result = decoder.record(&record, zh).
|
|
348
|
-
let
|
|
349
|
-
|
|
352
|
+
let result = decoder.record(&record, zh).map(|()| {
|
|
353
|
+
let snapshot = &record["payload"]["info"]["total_token_usage"];
|
|
354
|
+
if snapshot.is_object() {
|
|
355
|
+
usage = snapshot.clone();
|
|
356
|
+
}
|
|
350
357
|
});
|
|
351
358
|
if let Err(error) = result {
|
|
352
359
|
diagnostics(RecoverableDiagnostic::MessageConvertFailed(
|
|
@@ -356,6 +363,7 @@ pub fn read(
|
|
|
356
363
|
Ok(())
|
|
357
364
|
})?;
|
|
358
365
|
decoder.finish_plan("fail", None);
|
|
366
|
+
stats.add_tokens(&usage["input_tokens"], &usage["output_tokens"])?;
|
|
359
367
|
stats.message_count = decoder.messages.len();
|
|
360
368
|
let mut data = session.payload(decoder.messages, stats);
|
|
361
369
|
data.directory = session.source_metadata["cwd"].clone();
|
|
@@ -98,6 +98,7 @@ pub trait Provider: Send + Sync {
|
|
|
98
98
|
diagnostics: &mut DiagnosticSink<'_>,
|
|
99
99
|
) -> crate::Result<SessionData>;
|
|
100
100
|
fn source_root(&self) -> &Path;
|
|
101
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>>;
|
|
101
102
|
fn search_roots(&self) -> crate::Result<Vec<(&'static str, PathBuf)>>;
|
|
102
103
|
|
|
103
104
|
fn change_sources(&self, session: &Session) -> Vec<PathBuf> {
|
|
@@ -163,6 +163,11 @@ impl Provider for Cursor {
|
|
|
163
163
|
fn source_root(&self) -> &Path {
|
|
164
164
|
self.database.parent().unwrap()
|
|
165
165
|
}
|
|
166
|
+
|
|
167
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>> {
|
|
168
|
+
self.database = (self.resolve_database)()?;
|
|
169
|
+
Ok(self.database.exists().then(|| self.source_root()))
|
|
170
|
+
}
|
|
166
171
|
fn supports_format(&self, format: OutputFormat) -> bool {
|
|
167
172
|
matches!(format, OutputFormat::Json | OutputFormat::Print)
|
|
168
173
|
}
|
|
@@ -220,6 +220,10 @@ impl Provider for Desktop {
|
|
|
220
220
|
self.database.parent().unwrap()
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>> {
|
|
224
|
+
Ok(self.select_database()?.then(|| self.source_root()))
|
|
225
|
+
}
|
|
226
|
+
|
|
223
227
|
fn supports_format(&self, format: OutputFormat) -> bool {
|
|
224
228
|
format != OutputFormat::Raw
|
|
225
229
|
}
|
|
@@ -408,3 +408,36 @@ fn migration_required_after_lookup_uses_localized_read_failure() {
|
|
|
408
408
|
}
|
|
409
409
|
assert_eq!(std::fs::read(&session.source_path).unwrap(), before);
|
|
410
410
|
}
|
|
411
|
+
|
|
412
|
+
#[test]
|
|
413
|
+
fn minimax_out_of_scope_sessions_skip_storage_checks() {
|
|
414
|
+
let (_directory, mut provider, session, _) = fixture(Kind::MiniMax);
|
|
415
|
+
Connection::open(&session.source_path)
|
|
416
|
+
.unwrap()
|
|
417
|
+
.execute_batch(
|
|
418
|
+
"INSERT INTO local_runtime_sessions VALUES ('hidden-v2', 2, 'pi-agent', 'hidden', 'conversation', 0, NULL, NULL, NULL, 1768478400000, 1768478400000, '{}');
|
|
419
|
+
INSERT INTO local_runtime_sessions VALUES ('cron-pending', 3, 'pi-agent', 'visible', 'cron', 0, NULL, NULL, NULL, 1768478400000, 1768478400000, '{}');
|
|
420
|
+
INSERT INTO local_runtime_messages VALUES ('cron-pending', '[{}]');
|
|
421
|
+
INSERT INTO local_runtime_sessions VALUES ('opencode-v1', 1, 'opencode', 'visible', 'conversation', 0, NULL, NULL, NULL, 1768478400000, 1768478400000, '{}');",
|
|
422
|
+
)
|
|
423
|
+
.unwrap();
|
|
424
|
+
let found = provider.discover(None, &mut |_| Ok(())).unwrap();
|
|
425
|
+
assert!(found.failures.is_empty());
|
|
426
|
+
assert_eq!(
|
|
427
|
+
found
|
|
428
|
+
.sessions
|
|
429
|
+
.iter()
|
|
430
|
+
.map(|s| s.id.as_str())
|
|
431
|
+
.collect::<Vec<_>>(),
|
|
432
|
+
["kept"]
|
|
433
|
+
);
|
|
434
|
+
for id in ["hidden-v2", "cron-pending", "opencode-v1"] {
|
|
435
|
+
assert!(
|
|
436
|
+
provider
|
|
437
|
+
.find(id, &mut |_| Ok(()))
|
|
438
|
+
.unwrap()
|
|
439
|
+
.session
|
|
440
|
+
.is_none()
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
}
|