From f9b992227c73db902e39a2cab5f227e0a83d0eb3 Mon Sep 17 00:00:00 2001
From: Brett Chien
Date: Sat, 29 Aug 2026 16:24:58 +0800
Subject: [PATCH] feat(console,src-tauri): local "Config folder" setting
(studio#128)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Adds a "Config folder" field to the Debug drawer's Config tab — a
user-picked local directory (native folder picker via tauri-plugin-dialog)
that later work will mirror each agent's generated config.toml into
(//config.toml, alongside the existing S3 upload
provision_agent/provision_agent_k8s already do — unchanged) and that the
"view an agent's config" screen (also studio#128, separate follow-up) will
read from directly, no S3 round-trip.
This slice is just the setting itself: plugin registration + capability
grant (dialog:allow-open — the app's capabilities/default.json had no
dialog permission at all before this) + picker UI, persisted like the
existing theme/log-level settings (localStorage), not Tauri's hidden
app-config-dir — this setting points at other local files, so storing it
in the hidden config dir would just be an extra layer of indirection.
Wiring the wizard/view-screen to actually use it lands with those pieces.
Verification: npm run typecheck clean, npm test 106/106 passing, npm run
build succeeds. Rust side (plugin registration, Cargo.toml) not locally
compiled — same pre-existing limitation as every other Rust change this
week; tauri-plugin-dialog's exact API (invoke command name
"plugin:dialog|open", options shape, return type for directory+non-multiple
mode) was checked against the plugin's actual TypeScript source before
using it, not guessed.
Ref #128.
---
console/index.html | 13 +++++++++
console/src/main.ts | 41 +++++++++++++++++++++++++++++
console/src/styles.css | 32 ++++++++++++++++++++++
src-tauri/Cargo.toml | 5 ++++
src-tauri/capabilities/default.json | 1 +
src-tauri/src/lib.rs | 1 +
6 files changed, 93 insertions(+)
diff --git a/console/index.html b/console/index.html
index 22acdf1..e1dada7 100644
--- a/console/index.html
+++ b/console/index.html
@@ -273,6 +273,19 @@
explicit auth error, not a silent drift.
+
+
+
+ — not set —
+
+
+
+ Local folder the New Fleet wizard mirrors each agent's generated
+ config.toml into (<folder>/<agent-name>/config.toml),
+ alongside the S3 copy it deploys from — this is what "view an
+ agent's config" reads from, no S3 round-trip.
+
+
diff --git a/console/src/main.ts b/console/src/main.ts
index 8875e51..7c108cc 100644
--- a/console/src/main.ts
+++ b/console/src/main.ts
@@ -174,6 +174,47 @@ const mcp = mcpEl ? createPane(mcpEl, () => flag("mcpio")) : null;
});
})();
+// Local "Config folder" (studio#128) — where the New Fleet wizard mirrors
+// each agent's generated config.toml (alongside the S3 copy it deploys
+// from) and where the "view an agent's config" screen reads from, no S3
+// round-trip. Persisted like the theme/log-level settings above
+// (localStorage), not Tauri's app-config-dir — this setting *points at*
+// other local files, storing it in the hidden config dir would just be an
+// extra layer of indirection for no reason.
+(function setupConfigFolder(): void {
+ const pathEl = document.getElementById("config-folder-path");
+ const pickBtn = document.getElementById("config-folder-pick");
+ if (!pathEl || !pickBtn) return;
+ const KEY = "oab-studio.configFolder";
+
+ const render = (): void => {
+ let saved: string | null = null;
+ try {
+ saved = localStorage.getItem(KEY);
+ } catch {
+ /* storage unavailable — falls through to the placeholder */
+ }
+ pathEl.textContent = saved || "— not set —";
+ };
+ render();
+
+ pickBtn.addEventListener("click", () => {
+ const invoke = tauriInvoke();
+ if (!invoke) return;
+ invoke("plugin:dialog|open", { options: { directory: true } })
+ .then((path) => {
+ if (!path) return;
+ try {
+ localStorage.setItem(KEY, path);
+ } catch {
+ /* storage unavailable — the choice still applies this session */
+ }
+ render();
+ })
+ .catch((e) => note("error", `config folder pick failed: ${errText(e)}`));
+ });
+})();
+
// Build stamp (injected by vite) — shown under the brand and logged on launch,
// so it's obvious which commit this build is.
const BUILD = `v${__APP_VERSION__} · ${__BUILD_SHA__}`;
diff --git a/console/src/styles.css b/console/src/styles.css
index ea74ab1..03ec2d3 100644
--- a/console/src/styles.css
+++ b/console/src/styles.css
@@ -1244,6 +1244,38 @@ button.act:disabled {
color: var(--muted);
}
+.config-folder {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ max-width: 420px;
+ margin-top: 20px;
+ padding-top: 16px;
+ border-top: 1px solid var(--border);
+}
+.config-folder > label {
+ font-size: 12px;
+ color: var(--muted);
+}
+.config-folder-row {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+.config-folder-path {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 12px;
+ color: var(--text);
+ padding: 6px 8px;
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ background: var(--bg);
+}
+
/* Compose (agent-deployment ADR, slice 1): the deploy panel's bundle-preview
step (`deploy.ts`'s `#deploy-compose`) — the standalone authoring tab this
used to also style is gone, see compose.ts. */
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 4d6d0e0..2eb2d58 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -55,6 +55,11 @@ tauri-plugin-updater = "2"
# commit rather than the floating `dev` branch for reproducibility.
fix-path-env = { git = "https://github.com/tauri-apps/fix-path-env-rs", rev = "c4c45d503ea115a839aae718d02f79e7c7f0f673" }
+# Native folder-picker dialog (studio#128) — lets the operator choose the
+# local "Config folder" the New Fleet wizard mirrors generated config.toml
+# files into, instead of a hidden hardcoded path.
+tauri-plugin-dialog = "2"
+
# Its own workspace so the desktop build stays out of the root workspace's
# `cargo build --workspace` (kept to the small crates + CI).
[workspace]
diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json
index 4a8d596..aacca3c 100644
--- a/src-tauri/capabilities/default.json
+++ b/src-tauri/capabilities/default.json
@@ -9,6 +9,7 @@
"core:default",
"shell:allow-stdin-write",
"shell:allow-kill",
+ "dialog:allow-open",
{
"identifier": "shell:allow-spawn",
"allow": [
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 62c03ca..94f5492 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -773,6 +773,7 @@ pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_updater::Builder::new().build())
+ .plugin(tauri_plugin_dialog::init())
.setup(|app| {
if cfg!(debug_assertions) {
app.handle().plugin(