Codex worktree snapshot: settings-delete-targeted

Co-authored-by: Codex
This commit is contained in:
kdletters
2026-05-16 22:52:10 +08:00
parent 7f16e88e57
commit 01af298c07
115 changed files with 2831 additions and 1324 deletions

View File

@@ -326,49 +326,65 @@ pub struct VisualNovelRuntimeEventRecordInput {
pub occurred_at_micros: i64,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
pub struct VisualNovelAgentSessionProcedureResult {
pub ok: bool,
pub session_json: Option<String>,
pub session: Option<VisualNovelAgentSessionSnapshot>,
pub error_message: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
pub struct VisualNovelWorkProcedureResult {
pub ok: bool,
pub work_json: Option<String>,
pub work: Option<VisualNovelWorkSnapshot>,
pub error_message: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
pub struct VisualNovelWorksProcedureResult {
pub ok: bool,
pub items_json: Option<String>,
pub items: Vec<VisualNovelWorkSnapshot>,
pub error_message: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
pub struct VisualNovelRunProcedureResult {
pub ok: bool,
pub run_json: Option<String>,
pub run: Option<VisualNovelRunSnapshot>,
pub error_message: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
pub struct VisualNovelHistoryProcedureResult {
pub ok: bool,
pub items_json: Option<String>,
pub items: Vec<VisualNovelRuntimeHistoryEntrySnapshot>,
pub error_message: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
pub struct VisualNovelRuntimeEventProcedureResult {
pub ok: bool,
pub event_json: Option<String>,
pub event: Option<VisualNovelRuntimeEventSnapshot>,
pub error_message: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[derive(Clone, Debug, PartialEq, Serialize, SpacetimeType)]
pub struct VisualNovelJsonField {
pub key: String,
pub value: VisualNovelJsonValue,
}
#[derive(Clone, Debug, PartialEq, Serialize, SpacetimeType)]
pub enum VisualNovelJsonValue {
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<VisualNovelJsonValue>),
Object(Vec<VisualNovelJsonField>),
}
#[derive(Clone, Debug, PartialEq, Serialize, SpacetimeType)]
#[serde(rename_all = "camelCase")]
pub struct VisualNovelAgentMessageSnapshot {
pub message_id: String,
@@ -379,7 +395,7 @@ pub struct VisualNovelAgentMessageSnapshot {
pub created_at_micros: i64,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[derive(Clone, Debug, PartialEq, Serialize, SpacetimeType)]
#[serde(rename_all = "camelCase")]
pub struct VisualNovelAgentSessionSnapshot {
pub session_id: String,
@@ -391,15 +407,15 @@ pub struct VisualNovelAgentSessionSnapshot {
pub current_turn: u32,
pub progress_percent: u32,
pub messages: Vec<VisualNovelAgentMessageSnapshot>,
pub draft: Option<JsonValue>,
pub pending_action: Option<JsonValue>,
pub draft: Option<VisualNovelJsonValue>,
pub pending_action: Option<VisualNovelJsonValue>,
pub last_assistant_reply: Option<String>,
pub published_profile_id: Option<String>,
pub created_at_micros: i64,
pub updated_at_micros: i64,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[derive(Clone, Debug, PartialEq, Serialize, SpacetimeType)]
#[serde(rename_all = "camelCase")]
pub struct VisualNovelWorkSnapshot {
pub work_id: String,
@@ -412,7 +428,7 @@ pub struct VisualNovelWorkSnapshot {
pub tags: Vec<String>,
pub cover_image_src: Option<String>,
pub source_asset_ids: Vec<String>,
pub draft: JsonValue,
pub draft: VisualNovelJsonValue,
pub publication_status: String,
pub publish_ready: bool,
pub play_count: u32,
@@ -421,7 +437,7 @@ pub struct VisualNovelWorkSnapshot {
pub published_at_micros: Option<i64>,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[derive(Clone, Debug, PartialEq, Serialize, SpacetimeType)]
#[serde(rename_all = "camelCase")]
pub struct VisualNovelRuntimeHistoryEntrySnapshot {
pub entry_id: String,
@@ -431,13 +447,13 @@ pub struct VisualNovelRuntimeHistoryEntrySnapshot {
pub turn_index: u32,
pub source: String,
pub action_text: Option<String>,
pub steps: JsonValue,
pub steps: VisualNovelJsonValue,
pub snapshot_before_hash: Option<String>,
pub snapshot_after_hash: Option<String>,
pub created_at_micros: i64,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[derive(Clone, Debug, PartialEq, Serialize, SpacetimeType)]
#[serde(rename_all = "camelCase")]
pub struct VisualNovelRunSnapshot {
pub run_id: String,
@@ -448,16 +464,16 @@ pub struct VisualNovelRunSnapshot {
pub current_scene_id: Option<String>,
pub current_phase_id: Option<String>,
pub visible_character_ids: Vec<String>,
pub flags: JsonValue,
pub metrics: JsonValue,
pub flags: VisualNovelJsonValue,
pub metrics: VisualNovelJsonValue,
pub history: Vec<VisualNovelRuntimeHistoryEntrySnapshot>,
pub available_choices: JsonValue,
pub available_choices: VisualNovelJsonValue,
pub text_mode_enabled: bool,
pub created_at_micros: i64,
pub updated_at_micros: i64,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[derive(Clone, Debug, PartialEq, Serialize, SpacetimeType)]
#[serde(rename_all = "camelCase")]
pub struct VisualNovelRuntimeEventSnapshot {
pub event_id: String,
@@ -467,7 +483,7 @@ pub struct VisualNovelRuntimeEventSnapshot {
pub event_kind: String,
pub client_event_id: Option<String>,
pub history_entry_id: Option<String>,
pub payload: JsonValue,
pub payload: VisualNovelJsonValue,
pub occurred_at_micros: i64,
}
@@ -556,12 +572,12 @@ pub fn list_visual_novel_works(
match ctx.try_with_tx(|tx| list_visual_novel_works_tx(tx, input.clone())) {
Ok(items) => VisualNovelWorksProcedureResult {
ok: true,
items_json: Some(to_json_string(&items)),
items,
error_message: None,
},
Err(message) => VisualNovelWorksProcedureResult {
ok: false,
items_json: None,
items: Vec::new(),
error_message: Some(message),
},
}
@@ -586,12 +602,12 @@ pub fn delete_visual_novel_work(
match ctx.try_with_tx(|tx| delete_visual_novel_work_tx(tx, input.clone())) {
Ok(items) => VisualNovelWorksProcedureResult {
ok: true,
items_json: Some(to_json_string(&items)),
items,
error_message: None,
},
Err(message) => VisualNovelWorksProcedureResult {
ok: false,
items_json: None,
items: Vec::new(),
error_message: Some(message),
},
}
@@ -638,12 +654,12 @@ pub fn append_visual_novel_runtime_history_entry(
match ctx.try_with_tx(|tx| append_visual_novel_runtime_history_entry_tx(tx, input.clone())) {
Ok(items) => VisualNovelHistoryProcedureResult {
ok: true,
items_json: Some(to_json_string(&items)),
items,
error_message: None,
},
Err(message) => VisualNovelHistoryProcedureResult {
ok: false,
items_json: None,
items: Vec::new(),
error_message: Some(message),
},
}
@@ -657,12 +673,12 @@ pub fn list_visual_novel_runtime_history(
match ctx.try_with_tx(|tx| list_visual_novel_runtime_history_tx(tx, input.clone())) {
Ok(items) => VisualNovelHistoryProcedureResult {
ok: true,
items_json: Some(to_json_string(&items)),
items,
error_message: None,
},
Err(message) => VisualNovelHistoryProcedureResult {
ok: false,
items_json: None,
items: Vec::new(),
error_message: Some(message),
},
}
@@ -676,12 +692,12 @@ pub fn record_visual_novel_runtime_event(
match ctx.try_with_tx(|tx| record_visual_novel_runtime_event_tx(tx, input.clone())) {
Ok(event) => VisualNovelRuntimeEventProcedureResult {
ok: true,
event_json: Some(to_json_string(&event)),
event: Some(event),
error_message: None,
},
Err(message) => VisualNovelRuntimeEventProcedureResult {
ok: false,
event_json: None,
event: None,
error_message: Some(message),
},
}
@@ -1052,17 +1068,22 @@ fn list_visual_novel_works_tx(
ctx: &ReducerContext,
input: VisualNovelWorksListInput,
) -> Result<Vec<VisualNovelWorkSnapshot>, String> {
let mut items = ctx
.db
.visual_novel_work_profile()
let rows = if input.published_only {
ctx.db
.visual_novel_work_profile()
.by_visual_novel_work_publication_status()
.filter(&VISUAL_NOVEL_PUBLICATION_PUBLISHED.to_string())
.collect::<Vec<_>>()
} else {
require_non_empty(&input.owner_user_id, "visual_novel owner_user_id")?;
ctx.db
.visual_novel_work_profile()
.by_visual_novel_work_owner_user_id()
.filter(&input.owner_user_id)
.collect::<Vec<_>>()
};
let mut items = rows
.iter()
.filter(|row| {
if input.published_only {
row.publication_status == VISUAL_NOVEL_PUBLICATION_PUBLISHED
} else {
row.owner_user_id == input.owner_user_id
}
})
.map(|row| build_work_snapshot(&row))
.collect::<Result<Vec<_>, _>>()?;
items.sort_by(|left, right| {
@@ -1103,10 +1124,9 @@ fn delete_visual_novel_work_tx(
for run in ctx
.db
.visual_novel_runtime_run()
.iter()
.filter(|row| {
row.profile_id == input.profile_id && row.owner_user_id == input.owner_user_id
})
.by_visual_novel_run_profile_id()
.filter(&input.profile_id)
.filter(|row| row.owner_user_id == input.owner_user_id)
.collect::<Vec<_>>()
{
delete_run_children(ctx, &run.run_id, &input.owner_user_id);
@@ -1385,8 +1405,8 @@ fn build_session_snapshot(
let mut messages = ctx
.db
.visual_novel_agent_message()
.iter()
.filter(|message| message.session_id == row.session_id)
.by_visual_novel_agent_message_session_id()
.filter(&row.session_id)
.map(|message| VisualNovelAgentMessageSnapshot {
message_id: message.message_id,
session_id: message.session_id,
@@ -1412,8 +1432,9 @@ fn build_session_snapshot(
current_turn: row.current_turn,
progress_percent: row.progress_percent,
messages,
draft: parse_optional_json_value(&row.draft_json)?,
pending_action: parse_optional_json_value(&row.pending_action_json)?,
draft: parse_optional_json_value(&row.draft_json)?.map(visual_novel_json_from_serde),
pending_action: parse_optional_json_value(&row.pending_action_json)?
.map(visual_novel_json_from_serde),
last_assistant_reply: empty_to_none(&row.last_assistant_reply),
published_profile_id: empty_to_none(&row.published_profile_id),
created_at_micros: row.created_at.to_micros_since_unix_epoch(),
@@ -1433,7 +1454,7 @@ fn build_work_snapshot(row: &VisualNovelWorkProfileRow) -> Result<VisualNovelWor
tags: parse_string_vec_or_empty(&row.tags_json)?,
cover_image_src: empty_to_none(&row.cover_image_src),
source_asset_ids: parse_string_vec_or_empty(&row.source_asset_ids_json)?,
draft: parse_json_value(&row.draft_json)?,
draft: visual_novel_json_from_serde(parse_json_value(&row.draft_json)?),
publication_status: row.publication_status.clone(),
publish_ready: row.publish_ready,
play_count: row.play_count,
@@ -1458,10 +1479,12 @@ fn build_run_snapshot(
current_scene_id: empty_to_none(&row.current_scene_id),
current_phase_id: empty_to_none(&row.current_phase_id),
visible_character_ids: parse_string_vec_or_empty(&row.visible_character_ids_json)?,
flags: parse_json_value_or_object(&row.flags_json)?,
metrics: parse_json_value_or_object(&row.metrics_json)?,
flags: visual_novel_json_from_serde(parse_json_value_or_object(&row.flags_json)?),
metrics: visual_novel_json_from_serde(parse_json_value_or_object(&row.metrics_json)?),
history: build_history_snapshots(ctx, &row.run_id, &row.owner_user_id)?,
available_choices: parse_json_value_or_array(&row.available_choices_json)?,
available_choices: visual_novel_json_from_serde(parse_json_value_or_array(
&row.available_choices_json,
)?),
text_mode_enabled: row.text_mode_enabled,
created_at_micros: row.created_at.to_micros_since_unix_epoch(),
updated_at_micros: row.updated_at.to_micros_since_unix_epoch(),
@@ -1476,8 +1499,9 @@ fn build_history_snapshots(
let mut items = ctx
.db
.visual_novel_runtime_history_entry()
.iter()
.filter(|row| row.run_id == run_id && row.owner_user_id == owner_user_id)
.by_visual_novel_history_run_id()
.filter(&run_id.to_string())
.filter(|row| row.owner_user_id == owner_user_id)
.map(|row| build_history_snapshot(&row))
.collect::<Result<Vec<_>, _>>()?;
items.sort_by(|left, right| {
@@ -1500,7 +1524,7 @@ fn build_history_snapshot(
turn_index: row.turn_index,
source: row.source.clone(),
action_text: empty_to_none(&row.action_text),
steps: parse_json_value_or_array(&row.steps_json)?,
steps: visual_novel_json_from_serde(parse_json_value_or_array(&row.steps_json)?),
snapshot_before_hash: empty_to_none(&row.snapshot_before_hash),
snapshot_after_hash: empty_to_none(&row.snapshot_after_hash),
created_at_micros: row.created_at.to_micros_since_unix_epoch(),
@@ -1518,7 +1542,7 @@ fn build_event_snapshot(
event_kind: row.event_kind.clone(),
client_event_id: empty_to_none(&row.client_event_id),
history_entry_id: empty_to_none(&row.history_entry_id),
payload: parse_json_value_or_object(&row.payload_json)?,
payload: visual_novel_json_from_serde(parse_json_value_or_object(&row.payload_json)?),
occurred_at_micros: row.occurred_at.to_micros_since_unix_epoch(),
})
}
@@ -1579,8 +1603,9 @@ fn delete_run_children(ctx: &ReducerContext, run_id: &str, owner_user_id: &str)
for history in ctx
.db
.visual_novel_runtime_history_entry()
.iter()
.filter(|row| row.run_id == run_id && row.owner_user_id == owner_user_id)
.by_visual_novel_history_run_id()
.filter(&run_id.to_string())
.filter(|row| row.owner_user_id == owner_user_id)
.collect::<Vec<_>>()
{
ctx.db
@@ -1758,6 +1783,30 @@ fn parse_json_value_or_array(value: &str) -> Result<JsonValue, String> {
parse_json_value(value)
}
fn visual_novel_json_from_serde(value: JsonValue) -> VisualNovelJsonValue {
match value {
JsonValue::Null => VisualNovelJsonValue::Null,
JsonValue::Bool(value) => VisualNovelJsonValue::Bool(value),
JsonValue::Number(value) => VisualNovelJsonValue::Number(value.as_f64().unwrap_or(0.0)),
JsonValue::String(value) => VisualNovelJsonValue::String(value),
JsonValue::Array(items) => VisualNovelJsonValue::Array(
items
.into_iter()
.map(visual_novel_json_from_serde)
.collect(),
),
JsonValue::Object(object) => VisualNovelJsonValue::Object(
object
.into_iter()
.map(|(key, value)| VisualNovelJsonField {
key,
value: visual_novel_json_from_serde(value),
})
.collect(),
),
}
}
fn draft_string_field(draft: &JsonValue, key: &str) -> Option<String> {
draft
.get(key)
@@ -1853,7 +1902,7 @@ fn session_result(
) -> VisualNovelAgentSessionProcedureResult {
VisualNovelAgentSessionProcedureResult {
ok: true,
session_json: Some(to_json_string(&session)),
session: Some(session),
error_message: None,
}
}
@@ -1861,7 +1910,7 @@ fn session_result(
fn session_error(message: String) -> VisualNovelAgentSessionProcedureResult {
VisualNovelAgentSessionProcedureResult {
ok: false,
session_json: None,
session: None,
error_message: Some(message),
}
}
@@ -1869,7 +1918,7 @@ fn session_error(message: String) -> VisualNovelAgentSessionProcedureResult {
fn work_result(work: VisualNovelWorkSnapshot) -> VisualNovelWorkProcedureResult {
VisualNovelWorkProcedureResult {
ok: true,
work_json: Some(to_json_string(&work)),
work: Some(work),
error_message: None,
}
}
@@ -1877,7 +1926,7 @@ fn work_result(work: VisualNovelWorkSnapshot) -> VisualNovelWorkProcedureResult
fn work_error(message: String) -> VisualNovelWorkProcedureResult {
VisualNovelWorkProcedureResult {
ok: false,
work_json: None,
work: None,
error_message: Some(message),
}
}
@@ -1885,7 +1934,7 @@ fn work_error(message: String) -> VisualNovelWorkProcedureResult {
fn run_result(run: VisualNovelRunSnapshot) -> VisualNovelRunProcedureResult {
VisualNovelRunProcedureResult {
ok: true,
run_json: Some(to_json_string(&run)),
run: Some(run),
error_message: None,
}
}
@@ -1893,7 +1942,7 @@ fn run_result(run: VisualNovelRunSnapshot) -> VisualNovelRunProcedureResult {
fn run_error(message: String) -> VisualNovelRunProcedureResult {
VisualNovelRunProcedureResult {
ok: false,
run_json: None,
run: None,
error_message: Some(message),
}
}