From 724380901f288e4032f4e1993b86db52f22cabcd Mon Sep 17 00:00:00 2001 From: anti Date: Sun, 10 May 2026 01:00:43 -0400 Subject: [PATCH] fix(wizard): emit per-decky service config sections instead of prefix group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [decky.https] relied on ini_loader prefix-matching to propagate config to decky-03/04/05 — silent and fragile. Now emits [decky-03.https], [decky-04.https], [decky-05.https] explicitly so the INI is self-evident and doesn't depend on pattern matching side-effects. --- .../components/DeckyFleet/DeployWizard.tsx | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/decnet_web/src/components/DeckyFleet/DeployWizard.tsx b/decnet_web/src/components/DeckyFleet/DeployWizard.tsx index 1902cdfb..d722ed50 100644 --- a/decnet_web/src/components/DeckyFleet/DeployWizard.tsx +++ b/decnet_web/src/components/DeckyFleet/DeployWizard.tsx @@ -59,29 +59,29 @@ const buildIni = ( } if (mutate) lines.push(`mutate_interval=${mutateEvery}`); lines.push(''); - } - // Per-service overrides emitted as [.] group subsections. - // The INI loader (decnet/ini_loader.py) prefix-matches these onto every - // ``${prefix}-NN`` decky in the batch, so one block covers all clones. - for (const svc of services) { - const cfg = serviceConfigs[svc]; - if (!cfg || Object.keys(cfg).length === 0) continue; - const fieldTypes: Record = {}; - for (const f of serviceSchemas[svc] ?? []) fieldTypes[f.key] = f.type; - lines.push(`[${prefix}.${svc}]`); - for (const [k, v] of Object.entries(cfg)) { - // textarea values may contain newlines that ConfigParser can't carry - // on a single line; wrap them in `b64:` so validate_cfg decodes back - // to the original UTF-8 string. Other types are emitted raw. - let serialised: string; - if (fieldTypes[k] === 'textarea' && typeof v === 'string') { - serialised = `b64:${b64encodeUtf8(v)}`; - } else { - serialised = typeof v === 'string' ? v : String(v); + + // Emit per-service config as [.] so the section + // name unambiguously targets this decky only — no prefix-match magic. + for (const svc of services) { + const cfg = serviceConfigs[svc]; + if (!cfg || Object.keys(cfg).length === 0) continue; + const fieldTypes: Record = {}; + for (const f of serviceSchemas[svc] ?? []) fieldTypes[f.key] = f.type; + lines.push(`[${name}.${svc}]`); + for (const [k, v] of Object.entries(cfg)) { + // textarea values may contain newlines that ConfigParser can't carry + // on a single line; wrap them in `b64:` so validate_cfg decodes back + // to the original UTF-8 string. Other types are emitted raw. + let serialised: string; + if (fieldTypes[k] === 'textarea' && typeof v === 'string') { + serialised = `b64:${b64encodeUtf8(v)}`; + } else { + serialised = typeof v === 'string' ? v : String(v); + } + lines.push(`${k}=${serialised}`); } - lines.push(`${k}=${serialised}`); + lines.push(''); } - lines.push(''); } return lines.join('\n'); };