doxa-maps/internal/sync-app-shells.mjs
Doxa Maps d314c44043 internal/ keeps the reason and drops the speaker: no gate quotes or cites the Driver
Every reference to the Driver in internal/ is reworded the same way as in
library/: the reason stays, the speaker and the quote go, an open decision
reads "provisional, pending a product decision", and agent names and decision-
sheet rows are dropped. Where a gate printed the word, its message now names
the reviewer or the ruling instead.

Three spots were code, not comments, and changed with their callers:
- the element census's allowlist field `driver` is now `ruling`, in the gate
  and both presets (same validation: match, ruling, date and card required);
- check:i18n-never-translated's DRIVER-GATED marker is DECISION-PENDING, in
  the entries and in the regex that counts them (its output is otherwise
  byte-identical);
- the package.json description of the census says "ruling".

public-hygiene-check keeps its two patterns for the word: they are what keep
it out of the served folder.
2026-09-29 05:26:25 +00:00

71 lines
3.8 KiB
JavaScript

#!/usr/bin/env node
/**
* sync-app-shells.mjs — point the native app shells at the OUTPUT FOLDER, from the tree's name.
*
* public/ holds only the output folder (decision, card BUILD-OUTPUT-IS-ONE-FOLDER), so the app
* shells load THAT folder as their web root:
* capacitor.config.json "webDir": "public/<tree>"
* `cap copy` hard-fails unless webDir holds an index.html; the tree's front page is its
* index.html (the Plugin Studio), and set-app-start-page then installs the app's start page.
* deployment/src-tauri/tauri.conf.json build.frontendDist "../../public/<tree>"
* windows[].url relative to that folder
* The window url used to carry the tree's name ("doxa-maps/doxa-maps-spa/…"), so renaming the
* tree opened a BLANK desktop window (check:tauri caught it in the zz-maps rename proof).
*
* Both files are hand-formatted JSON, so only those values are replaced in place — nothing else
* moves. Idempotent. generate-tree runs this after writing the tree, so a rename stays ONE line
* (vite.doxa-maps-build-config.json "name").
*
* USAGE node internal/sync-app-shells.mjs [--check] --check: exit 1 if a file is out of date.
*/
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { TREE_NAME } from './_tree-name.mjs'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
/** Returns [{ file, changed: bool, notes: [] }]; writes unless check. */
export function syncAppShells({ check = false } = {}) {
const out = []
// ── Capacitor ──
const cap = resolve(ROOT, 'capacitor.config.json')
if (existsSync(cap)) {
const src = readFileSync(cap, 'utf8')
const want = `public/${TREE_NAME}`
const next = src.replace(/("webDir"\s*:\s*)"[^"]*"/, `$1"${want}"`)
out.push({ file: 'capacitor.config.json', changed: next !== src, notes: [`webDir -> ${want}`] })
if (next !== src && !check) { JSON.parse(next); writeFileSync(cap, next) }
}
// ── Tauri ──
const tauri = resolve(ROOT, 'deployment', 'src-tauri', 'tauri.conf.json')
if (existsSync(tauri)) {
const src = readFileSync(tauri, 'utf8')
const conf = JSON.parse(src)
const want = `../../public/${TREE_NAME}`
let next = src.replace(/("frontendDist"\s*:\s*)"[^"]*"/, `$1"${want}"`)
const notes = [`frontendDist -> ${want}`]
// A window url that still starts with a tree folder (any name that is a sibling of the bundles, i.e.
// the first segment is not a bundle) is made relative to the tree.
for (const w of (conf.app && conf.app.windows) || []) {
if (!w.url || /^[a-z]+:/i.test(w.url)) continue
const segs = w.url.split('/')
if (segs.length > 1 && !existsSync(resolve(ROOT, 'public', TREE_NAME, segs[0])) && existsSync(resolve(ROOT, 'public', TREE_NAME, ...segs.slice(1)))) {
const rel = segs.slice(1).join('/')
next = next.replace(`"url": "${w.url}"`, `"url": "${rel}"`)
notes.push(`window url ${w.url} -> ${rel}`)
}
}
out.push({ file: 'deployment/src-tauri/tauri.conf.json', changed: next !== src, notes })
if (next !== src && !check) { JSON.parse(next); writeFileSync(tauri, next) }
}
return out
}
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
const check = process.argv.includes('--check')
const res = syncAppShells({ check })
for (const r of res) console.log(` ${r.changed ? (check ? 'STALE' : 'wrote') : 'ok '} ${r.file} (${r.notes.join('; ')})`)
if (check && res.some((r) => r.changed)) { console.log('APP-SHELLS: FAIL — run node internal/sync-app-shells.mjs (generate-tree does it on every build).'); process.exit(1) }
console.log(`APP-SHELLS: ${check ? 'PASS — both shells load' : 'synced to'} public/${TREE_NAME}/`)
}