From a123db83ad4094b549c8b9a1b43fa86c8eb1cbbb Mon Sep 17 00:00:00 2001 From: Hare Date: Thu, 2 Jul 2026 01:38:47 +0900 Subject: [PATCH] feat: install workspace backend config template --- .yoi/tickets/00001KWF2210A/item.md | 2 +- .yoi/tickets/00001KWF2210A/thread.md | 25 +++++++++++++ crates/workspace-server/src/config.rs | 45 ++++++++++++++++++++++++ crates/workspace-server/src/lib.rs | 2 +- crates/workspace-server/src/main.rs | 1 + resources/workspace-backend.default.toml | 45 ++++++++++++++++++++++++ 6 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 resources/workspace-backend.default.toml diff --git a/.yoi/tickets/00001KWF2210A/item.md b/.yoi/tickets/00001KWF2210A/item.md index 7c6e43e4..a56ae230 100644 --- a/.yoi/tickets/00001KWF2210A/item.md +++ b/.yoi/tickets/00001KWF2210A/item.md @@ -2,7 +2,7 @@ title: 'Workspace Backend設定ファイルのスキーマを定義する' state: 'closed' created_at: '2026-07-01T14:41:48Z' -updated_at: '2026-07-01T15:48:28Z' +updated_at: '2026-07-01T16:38:31Z' assignee: null queued_by: 'yoi ticket' queued_at: '2026-07-01T15:32:38Z' diff --git a/.yoi/tickets/00001KWF2210A/thread.md b/.yoi/tickets/00001KWF2210A/thread.md index f9ed1f31..cf2aa73d 100644 --- a/.yoi/tickets/00001KWF2210A/thread.md +++ b/.yoi/tickets/00001KWF2210A/thread.md @@ -129,4 +129,29 @@ Validation: - `nix build .#yoi --no-link` +--- + + + +## Implementation report + +Moved the Workspace Backend default config template into runtime resources and wired init-time copying. + +Changes: +- Added `resources/workspace-backend.default.toml` as the packaged template source. +- Embedded the template with `include_str!` from `workspace-server::config`. +- Added `.yoi/workspace-backend.default.toml` as the workspace-local copied template path. +- `yoi-workspace-server serve` now ensures the default template exists after workspace identity initialization and before reading `.local` config. +- Copying uses create-new semantics and does not overwrite an existing workspace-local default template. +- Removed the previously untracked `.yoi/workspace-backend.default.toml` workspace copy from the repository root. + +Validation: +- `cargo fmt --check` +- `cargo test -p yoi-workspace-server` +- `cargo check -p yoi` +- TOML parse check with Deno +- `git diff --check` +- `nix build .#yoi --no-link` + + --- diff --git a/crates/workspace-server/src/config.rs b/crates/workspace-server/src/config.rs index 0e6768c5..1f3465cf 100644 --- a/crates/workspace-server/src/config.rs +++ b/crates/workspace-server/src/config.rs @@ -10,6 +10,10 @@ use crate::server::{AuthConfig, ServerConfig}; use crate::{Error, Result}; pub const WORKSPACE_BACKEND_CONFIG_RELATIVE_PATH: &str = ".yoi/workspace-backend.local.toml"; +pub const WORKSPACE_BACKEND_DEFAULT_CONFIG_RELATIVE_PATH: &str = + ".yoi/workspace-backend.default.toml"; +pub const WORKSPACE_BACKEND_DEFAULT_CONFIG_TEMPLATE: &str = + include_str!("../../../resources/workspace-backend.default.toml"); const DEFAULT_LISTEN: &str = "127.0.0.1:8787"; const DEFAULT_FRONTEND_URL: &str = "http://127.0.0.1:5173"; const DEFAULT_MAX_RECORDS: usize = 200; @@ -88,6 +92,33 @@ impl WorkspaceBackendConfigFile { .join(WORKSPACE_BACKEND_CONFIG_RELATIVE_PATH) } + pub fn default_template_path_for_workspace(workspace_root: impl AsRef) -> PathBuf { + workspace_root + .as_ref() + .join(WORKSPACE_BACKEND_DEFAULT_CONFIG_RELATIVE_PATH) + } + + pub fn ensure_default_template_for_workspace(workspace_root: impl AsRef) -> Result<()> { + let path = Self::default_template_path_for_workspace(workspace_root); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + match fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&path) + { + Ok(mut file) => { + use std::io::Write; + file.write_all(WORKSPACE_BACKEND_DEFAULT_CONFIG_TEMPLATE.as_bytes())?; + file.sync_all()?; + Ok(()) + } + Err(error) if error.kind() == io::ErrorKind::AlreadyExists => Ok(()), + Err(error) => Err(Error::Io(error)), + } + } + pub fn load_for_workspace(workspace_root: impl AsRef) -> Result { let path = Self::path_for_workspace(workspace_root); match fs::read_to_string(&path) { @@ -335,6 +366,20 @@ root = ".local-data" ); } + #[test] + fn copies_default_template_without_overwriting() { + let dir = tempfile::tempdir().unwrap(); + WorkspaceBackendConfigFile::ensure_default_template_for_workspace(dir.path()).unwrap(); + let path = WorkspaceBackendConfigFile::default_template_path_for_workspace(dir.path()); + let raw = fs::read_to_string(&path).unwrap(); + assert_eq!(raw, WORKSPACE_BACKEND_DEFAULT_CONFIG_TEMPLATE); + WorkspaceBackendConfigFile::parse_str(&raw, &path).unwrap(); + + fs::write(&path, "# custom template\n").unwrap(); + WorkspaceBackendConfigFile::ensure_default_template_for_workspace(dir.path()).unwrap(); + assert_eq!(fs::read_to_string(&path).unwrap(), "# custom template\n"); + } + #[test] fn token_value_field_is_not_in_schema() { let error = WorkspaceBackendConfigFile::parse_str( diff --git a/crates/workspace-server/src/lib.rs b/crates/workspace-server/src/lib.rs index 03084929..160ba976 100644 --- a/crates/workspace-server/src/lib.rs +++ b/crates/workspace-server/src/lib.rs @@ -16,7 +16,7 @@ pub mod store; pub use config::{ ResolvedWorkspaceBackendConfig, WORKSPACE_BACKEND_CONFIG_RELATIVE_PATH, - WorkspaceBackendConfigFile, + WORKSPACE_BACKEND_DEFAULT_CONFIG_RELATIVE_PATH, WorkspaceBackendConfigFile, }; pub use identity::{WORKSPACE_IDENTITY_RELATIVE_PATH, WorkspaceIdentity}; pub use records::{ diff --git a/crates/workspace-server/src/main.rs b/crates/workspace-server/src/main.rs index ffc922f5..b7538b0f 100644 --- a/crates/workspace-server/src/main.rs +++ b/crates/workspace-server/src/main.rs @@ -67,6 +67,7 @@ async fn run() -> Result<(), Box> { async fn run_serve(options: ServeOptions) -> Result<(), Box> { let identity = WorkspaceIdentity::load_or_init(&options.workspace)?; + WorkspaceBackendConfigFile::ensure_default_template_for_workspace(&options.workspace)?; let config_file = WorkspaceBackendConfigFile::load_for_workspace(&options.workspace)?; let mut resolved = config_file.resolve(&options.workspace, identity)?; if let Some(db) = options.db { diff --git a/resources/workspace-backend.default.toml b/resources/workspace-backend.default.toml new file mode 100644 index 00000000..44234d90 --- /dev/null +++ b/resources/workspace-backend.default.toml @@ -0,0 +1,45 @@ +# Workspace Backend local config template. +# +# Copied to `.yoi/workspace-backend.default.toml` during workspace init. +# Copy that file to `.yoi/workspace-backend.local.toml` and edit it. +# The `.local` file is intentionally git-ignored. +# +# Omit a key to use the built-in default. TOML has no `null`, so optional +# settings are represented by leaving the key commented out. + +[server] +# Backend HTTP/WebSocket listen address. +listen = "127.0.0.1:8787" + +# Browser-facing frontend URL used by local tooling/display. +frontend_url = "http://127.0.0.1:5173" + +# Static SPA build directory override. Leave commented for dev/API-only mode. +# Relative paths are resolved from the workspace root. +# static_assets_dir = "web/workspace/dist" + +[data] +# Backend data root override. Leave commented to use the user-data default: +# /workspace-server// +# Relative paths are resolved from the workspace root. +# root = ".yoi/workspace-backend.data" + +# Explicit control-plane SQLite DB path override. +# If omitted, this defaults to `/workspace.db`. +# workspace_database_path = ".yoi/workspace-backend.data/workspace.db" + +# Explicit embedded Runtime fs-store root override. +# If omitted, this defaults to `/embedded-runtime`. +# embedded_runtime_store_root = ".yoi/workspace-backend.data/embedded-runtime" + +[limits] +max_records = 200 + +# Remote Runtime sources. Token values must not be written here. +# Use token_ref only after secret-ref resolution is implemented for this config. +# +# [[runtimes.remote]] +# id = "example" +# endpoint = "http://127.0.0.1:8790" +# display_name = "Example Runtime" +# token_ref = "local:example-runtime-token"