Files
spaces-startos/startos/actions/configureNacho.ts
T
spacesopsandCursor ad64a47d42
Build Service / BuildPackage (push) Has been cancelled
Release v0.1.1:2 with certrelay, nacho, and prebuilt subspaces.
Remove the embedded explorer/indexer stack, switch subspaces to prebuilt images, add certrelay and nacho as always-on services, expose Spaces and Subs APIs, and wire optional HTTP basic auth for subs and subs-prover with the correct SUBS_BASIC_AUTH_PASSWORD env var.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 12:06:16 -04:00

168 lines
4.7 KiB
TypeScript

import { storeJson } from '../fileModels/storeJson'
import { i18n } from '../i18n'
import { sdk } from '../sdk'
import {
dataDir,
NACHO_DEFAULT_IGNORE_NAMES,
NACHO_DEFAULT_WORKSHOP_PDF_LINK_TEXT,
NACHO_DIR,
} from '../utils'
const { InputSpec, Value } = sdk
const IGNORE_NAMES_PATH = `${NACHO_DIR}/ignore_names.txt`
const mainMount = sdk.Mounts.of().mountVolume({
volumeId: 'main',
subpath: null,
mountpoint: dataDir,
readonly: false,
})
// Reads /data/nacho/ignore_names.txt off the main volume via a temp
// subcontainer. Returns null if the file is missing/empty/unreadable so the
// prefill falls back to the package default.
async function readIgnoreNamesFile(effects: any): Promise<string | null> {
try {
const res = await sdk.SubContainer.withTemp(
effects,
{ imageId: 'spaces' },
mainMount,
'nacho-read-ignore-names',
(subc) =>
subc.exec(
[
'sh',
'-c',
`if [ -f ${IGNORE_NAMES_PATH} ]; then cat ${IGNORE_NAMES_PATH}; fi`,
],
{ user: 'root' },
),
)
if (res.exitCode !== 0) return null
const value = (res.stdout ?? '').toString().trim()
return value.length > 0 ? value : null
} catch {
return null
}
}
const inputSpec = InputSpec.of({
ignoreNames: Value.text({
name: i18n('Ignore Names'),
description: i18n(
'Comma-separated list of names for the nacho UI to ignore (EXPO_PUBLIC_IGNORE_NAMES).',
),
warning: null,
footnote: null,
default: NACHO_DEFAULT_IGNORE_NAMES,
required: true,
masked: false,
placeholder: 'fold,swifty',
minLength: 0,
maxLength: null,
}),
workshopPdfLinkText: Value.text({
name: i18n('Workshop PDF Link Text'),
description: i18n(
'Display text for the workshop PDF link in the nacho UI (EXPO_PUBLIC_WORKSHOP_PDF_LINK_TEXT). Leave empty to suppress the label.',
),
warning: null,
footnote: null,
default: NACHO_DEFAULT_WORKSHOP_PDF_LINK_TEXT,
required: false,
masked: false,
placeholder: 'Workshop PDF',
minLength: 0,
maxLength: null,
}),
})
export const configureNacho = sdk.Action.withInput(
// id
'configure-nacho',
// metadata
async ({ effects }) => ({
name: i18n('Configure Nacho'),
description: i18n(
'Set the user-tunable nacho settings. The Ignore Names list is written to /data/nacho/ignore_names.txt (read by nacho at runtime). The Workshop PDF link text is set via EXPO_PUBLIC_WORKSHOP_PDF_LINK_TEXT. Saving restarts the service. To upload a new Workshop PDF, use the separate "Upload Support PDF" action.',
),
warning: null,
allowedStatuses: 'any',
group: null,
visibility: 'enabled',
}),
// input
inputSpec,
// prefill — current values. Ignore Names is sourced from the file on disk
// (the source of truth nacho actually reads), with the default as a fallback.
async ({ effects }) => {
const [store, fileValue] = await Promise.all([
storeJson.read().once(),
readIgnoreNamesFile(effects),
])
return {
ignoreNames: fileValue ?? NACHO_DEFAULT_IGNORE_NAMES,
workshopPdfLinkText:
store?.nachoWorkshopPdfLinkText ??
NACHO_DEFAULT_WORKSHOP_PDF_LINK_TEXT,
}
},
// run
async ({ effects, input }) => {
// Persist the workshop PDF link text in the store (so it stays an
// EXPO_PUBLIC_* env var) and write the ignore names to its file on the
// main volume. mkdir -p first in case /data/nacho doesn't yet exist
// (e.g., the user runs this action before nacho-setup has executed).
await storeJson.merge(effects, {
nachoWorkshopPdfLinkText: input.workshopPdfLinkText ?? '',
})
const ignoreNames = input.ignoreNames
const res = await sdk.SubContainer.withTemp(
effects,
{ imageId: 'spaces' },
mainMount,
'nacho-write-ignore-names',
(subc) =>
subc.exec(
[
'sh',
'-c',
`set -eu; mkdir -p ${NACHO_DIR}; cat > ${IGNORE_NAMES_PATH} && chmod 644 ${IGNORE_NAMES_PATH}`,
],
{ input: ignoreNames, user: 'root' },
),
)
if (res.exitCode !== 0) {
return {
version: '1',
title: i18n('Failure'),
message: i18n('Could not write ignore_names.txt: ${error}', {
error:
((res.stderr ?? '').toString() || `exit ${res.exitCode}`).slice(
0,
300,
),
}),
result: null,
}
}
return {
version: '1',
title: i18n('Success'),
message: i18n(
'Nacho configuration saved. Ignore Names written to /data/nacho/ignore_names.txt; the service is restarting to apply the new values.',
),
result: null,
}
},
)