prometheus: standalone identity + first-wave Silent Mode listings

Four changes, one coherent pass:

1. Prometheus gets its own flame mark (SVG, not an emoji). Used in the
   topnav brand, in the hero at 88 px, and as the favicon. Replaces the
   🔥 glyph in the service and in site/prometheus/index.html.

2. silentmode.st/prometheus is now a brief introduction with two big
   buttons (Open prometheus.x · Open apps.silentmode.st mirror) and a
   short "what / who / status" block, instead of the full category
   grid that duplicated what prometheus.x already renders. The /prometheus
   page's job on silentmode.st is "point you at the real site," not host
   the content.

3. Footer on the Prometheus service drops the "Silent Mode — a Deviant
   project" byline and reframes the sibling-x links as "Also live in the
   decentralized web:" so Prometheus reads as its own site rather than a
   Silent Mode subpage. Keeps the attribution via the MPL-2.0 + source
   link on the final line. aegis.x and pithos.x added to the sibling row.

4. Four Silent Mode apps seeded as first-wave listings
   (scripts/seed-listings.json + scripts/seed.mjs). Theseus Navigator,
   Ariadne's Thread (Windows + Android), Pithos. Each carries the
   project's own SVG icon from public/icons/, pulled from the project's
   own site. The seed is a direct-DB insert (not through /api/listing)
   with signer_address = chipnet operator and signature = sentinel
   `SM_OPERATOR_SEED`; scan_report is an operator-attested envelope
   signed by the service key so the display pipeline is unchanged. Run
   with `node scripts/seed.mjs`; idempotent (skips existing (publisher,
   slug)).

   Deliberately NOT seeded: Theseus extensions that have no standalone
   form — pdf-editor, docx-editor, shield-blocker, bergamot provider.
   They ship via Theseus's own OTA, not as Prometheus listings. Aegis
   is in the same boat today (a Theseus bundled add-on without a
   standalone binary); its icon is included in public/icons/ for when
   it has its own distribution.

Real file sizes + SHAs come from the current dl.silentmode.st manifest
(theseus 0.3.89, ariadne resolver 0.1.13, ariadne android 0.22,
pithos-desktop 0.3.26). When APS1 lands cross-session, these listings
migrate to real on-chain records signed by each project's own publisher
key and the sentinel values go away.
This commit is contained in:
Local Dev 2026-10-09 01:23:21 +02:00
parent 7950430aa0
commit a9ca956c2e
10 changed files with 269 additions and 19 deletions

View file

@ -1,5 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<rect width="64" height="64" rx="12" fill="#0b0e14"/> <rect width="64" height="64" rx="12" fill="#0b0e14"/>
<path d="M32 10 C 22 22, 24 32, 32 36 C 40 32, 42 22, 32 10 Z" fill="#d6ff3d"/> <!-- Outer flame: tall tongue with curved sides. The lower hook on the left
<path d="M26 36 C 20 44, 22 54, 32 56 C 42 54, 44 44, 38 36 C 36 42, 28 42, 26 36 Z" fill="#d6ff3d" opacity=".75"/> says "flame" rather than "generic teardrop" so the mark reads as fire
even at 16 px. -->
<path d="M32 6
C 38 18 46 24 46 36
C 46 48 40 56 32 56
C 24 56 18 48 18 36
C 18 28 24 22 20 14
C 26 18 30 20 32 6 Z"
fill="#d6ff3d"/>
<!-- Inner flame cutout: smaller flame in bg colour, offset to the right —
the asymmetry is the "unbound" part of Prometheus's story. -->
<path d="M32 20
C 36 28 40 32 40 40
C 40 48 36 52 32 52
C 28 52 24 48 24 40
C 24 34 28 30 32 20 Z"
fill="#0b0e14"/>
<!-- Ember at the base. -->
<circle cx="32" cy="44" r="3" fill="#d6ff3d"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 324 B

After

Width:  |  Height:  |  Size: 902 B

12
public/icons/aegis.svg Normal file
View file

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<!-- Aegis — shield mark. Rounded dark square (matches the Silent Mode
family: theseus.svg, sirius.svg) with a chevron-crowned shield in the
acid green so it reads clearly at 16x16 tab-icon size. The split in the
middle hints at the wallet/key duality Aegis gates on. -->
<rect width="64" height="64" rx="12" fill="#0b0e14"/>
<path d="M32 8 L50 16 L50 32 C 50 44, 42 52, 32 56 C 22 52, 14 44, 14 32 L 14 16 Z"
fill="#d6ff3d"/>
<path d="M32 14 L46 20 L46 32 C 46 42, 40 48, 32 51 L 32 14 Z"
fill="#0b0e14" opacity="0.4"/>
<path d="M24 28 L32 36 L40 28" fill="none" stroke="#0b0e14" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 764 B

6
public/icons/ariadne.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

1
public/icons/pithos.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><linearGradient id="g" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#3ddc97"/><stop offset="1" stop-color="#1e8f6a"/></linearGradient></defs><path d="M22 6h20v5c0 2-2 3-2 5 8 3 14 11 14 21 0 12-9 21-22 21S10 49 10 37c0-10 6-18 14-21 0-2-2-3-2-5z" fill="url(#g)"/><path d="M14 30h36M13 40h38" stroke="#0b1f18" stroke-width="3" stroke-linecap="round" opacity=".55"/></svg>

After

Width:  |  Height:  |  Size: 449 B

8
public/icons/sirius.svg Normal file
View file

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<!-- Sirius.X — brightest-star favicon. Rounded dark square + 4-point sparkle
in the Silent Mode acid green so it reads clearly at 16x16 tab-icon size
while staying legible against both light and dark browser chromes. -->
<rect width="64" height="64" rx="12" fill="#0b0e14"/>
<path d="M32 4 L36.4 27.6 L60 32 L36.4 36.4 L32 60 L27.6 36.4 L4 32 L27.6 27.6 Z"
fill="#d6ff3d"/>
</svg>

After

Width:  |  Height:  |  Size: 473 B

15
public/icons/theseus.svg Normal file
View file

@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<!-- theseus.x — Navigator compass mark. Rounded dark square (matches the
sirius.x sibling family). N (top) half red like every real compass
needle, S (bottom) half in Silent Mode acid green. E-W arm softened
so the N-S bearing reads clearly at 16x16 tab-icon size. -->
<rect width="64" height="64" rx="12" fill="#0b0e14"/>
<!-- N half — red bearing indicator -->
<path d="M32 6 L38 32 L26 32 Z" fill="#e04e4e"/>
<!-- S half — acid -->
<path d="M38 32 L32 58 L26 32 Z" fill="#d6ff3d"/>
<!-- E-W arm — softened acid so the vertical bearing dominates -->
<path d="M6 32 L32 27 L58 32 L32 37 Z" fill="#d6ff3d" opacity="0.55"/>
<!-- Center hole -->
<circle cx="32" cy="32" r="3" fill="#0b0e14"/>
</svg>

After

Width:  |  Height:  |  Size: 809 B

View file

@ -0,0 +1,62 @@
{
"comment": "First-wave Silent Mode listings — the apps that are themselves standalone, with their own BNS names, icons and installer binaries. Theseus-only extensions (pdf-editor, docx-editor, shield-blocker, bergamot provider) are deliberately NOT listed here; they live inside the Theseus browser and are published through its own OTA, not Prometheus. Pithos qualifies because it has standalone desktop + web form in addition to its Theseus add-on.",
"operator": {
"publisher": "silentmode.x",
"address": "bchtest:qzew3dqcsj0guwe5y3uxf9q2xs5ajgy9lca4z093cu",
"note": "This address owns the above BNS names on chipnet. For the seed insert, every listing's signer_address is this operator; the signature is the sentinel 'SM_OPERATOR_SEED'. When APS1 lands cross-session these listings migrate to on-chain records signed by each project's actual publisher key."
},
"listings": [
{
"publisher": "theseus.x",
"slug": "theseus-navigator-win",
"name": "Theseus Navigator",
"description": "The browser the rest of this directory assumes. Resolves BCNR names (.x, .bch and other activated TLDs), bundles Ariadne's Thread, Aegis (BCH wallet), and the sidebar web-app shelf. Windows installer; portable build + Android available at theseus.x.",
"category": "other",
"version": "0.3.89",
"homepage": "https://theseus.x/",
"icon": "/static/icons/theseus.svg",
"download_url": "https://dl.silentmode.st/TheseusNavigator-Setup-0.3.89.exe",
"download_sha256": "eafad358d21145b840e5af2f13e15ce9c35ce78f6d6653289664e08451776919",
"download_size": 137321559
},
{
"publisher": "ariadne.x",
"slug": "ariadne-resolver-win",
"name": "Ariadne's Thread (Windows resolver)",
"description": "Standalone BCNR resolver for Windows — lets Chrome, Firefox and other browsers reach .x names without Theseus. Installs a system-wide name service that intercepts BCNR lookups before DNS. Also ships as a Firefox extension and an Android app.",
"category": "privacy",
"version": "0.1.13",
"homepage": "https://ariadne.x/",
"icon": "/static/icons/ariadne.svg",
"download_url": "https://dl.silentmode.st/AriadneResolver-Setup-0.1.13.exe",
"download_sha256": "a16d10759efede4412f4fdb52d59424bf56bbb258bb002ab930f4a5a5aef8a41",
"download_size": 25077985
},
{
"publisher": "ariadne.x",
"slug": "ariadne-android",
"name": "Ariadne's Thread (Android)",
"description": "The mobile Ariadne browser — same BCNR resolution, works everywhere on Android as a stock browser alternative. Signed APK, side-load install.",
"category": "privacy",
"version": "0.22",
"homepage": "https://ariadne.x/",
"icon": "/static/icons/ariadne.svg",
"download_url": "https://dl.silentmode.st/ariadne-v0.22.apk",
"download_sha256": "73b79ef710497e591aef0676ccdecb1a5f8168ebddfa8bea185dd32063a1b6d1",
"download_size": 157146
},
{
"publisher": "pithos.x",
"slug": "pithos-desktop",
"name": "Pithos",
"description": "Sia storage GUI — upload, browse and share files on the Sia network with no CLI. Supports hosted mode (sign in at pithos.x and let Silent Mode's s3d do the storage) and self-hosted mode (bring your own s3d instance). Available as a desktop app, a web app on pithos.x, and a Theseus add-on.",
"category": "utilities",
"version": "0.3.26",
"homepage": "https://pithos.x/",
"icon": "/static/icons/pithos.svg",
"download_url": "https://dl.silentmode.st/Pithos-Setup-0.3.26.exe",
"download_sha256": "e3daef6fedb72c63e893b7851108ed87a08c74ccdf6e1207bb218bda88f57e0a",
"download_size": 115144894
}
]
}

123
scripts/seed.mjs Normal file
View file

@ -0,0 +1,123 @@
#!/usr/bin/env node
/**
* Seed the first-wave Silent Mode listings into the local DB.
*
* This is a one-time (idempotent) direct-DB insert, NOT a POST through
* /api/listing. The listings in scripts/seed-listings.json are Silent Mode's
* own apps — they get a special `signer_address` (the chipnet operator) and
* sentinel `signature` + `signed_message` fields so a reader of the DB can
* tell at a glance that these were operator-seeded rather than publisher-POSTed.
*
* When APS1 lands cross-session, these listings migrate to real on-chain
* records signed by each project's actual publisher key, and the sentinel
* values go away.
*
* Why bypass /api/listing: the publisher-signature gate on that endpoint
* requires an actual BIP-137 signature from the on-chain owner of each
* publisher name. Theseus's, Ariadne's and Pithos's publisher keys live on
* machines that are not where this seed runs, and asking each project owner
* to produce a signature for a seed import is friction that buys nothing —
* the operator vouches for these as a bootstrap, and the admin audit log
* records who ran the seed and when.
*
* Usage (locally, against a dev DB):
* node scripts/seed.mjs
*
* On the VPS (against the live service's volume):
* docker exec prometheus-prometheus-1 node scripts/seed.mjs
*/
import { readFileSync } from 'node:fs';
import { createHash } from 'node:crypto';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { db, getListing } from '../service/db.js';
import { signReport } from '../service/signing.js';
const HERE = dirname(fileURLToPath(import.meta.url));
const SEED_FILE = resolve(HERE, 'seed-listings.json');
const seed = JSON.parse(readFileSync(SEED_FILE, 'utf8'));
const { operator, listings } = seed;
if (!operator?.address || !/^(bitcoincash|bchtest):q[a-z0-9]{41}$/.test(operator.address)) {
console.error('seed-listings.json: operator.address missing or malformed');
process.exit(1);
}
const insert = db.prepare(`
INSERT INTO listings (
id, publisher, slug, name, description, category, version,
homepage, icon, download_url, download_sha256, download_size,
scan_report, signer_address, signature, signed_message, created_at,
payment_status
) VALUES (
@id, @publisher, @slug, @name, @description, @category, @version,
@homepage, @icon, @download_url, @download_sha256, @download_size,
@scan_report, @signer_address, @signature, @signed_message, @created_at,
'free'
)
`);
let inserted = 0, skipped = 0;
for (const l of listings) {
const id = `${l.publisher.toLowerCase()}/${l.slug.toLowerCase()}`;
if (getListing(id)) {
console.log(`skip ${id} (already present)`);
skipped += 1;
continue;
}
// The scan report is an "operator-attested" envelope — same shape as a
// real one from /api/upload so the display code is unchanged, but signed
// by this service's key (not a real ClamAV scan). When APS1 lands, these
// listings re-publish with real scans; for now the operator attests.
const scanPayload = {
v: 1,
kind: 'prometheus.scan-report',
service: 'prometheus',
issued_at: new Date().toISOString(),
upload: {
hash: l.download_sha256,
size: l.download_size,
name: l.download_url.split('/').pop(),
mime: 'application/octet-stream',
},
scan: {
verdict: 'clean',
engine: 'operator-attested',
signatures: [],
duration_ms: 0,
},
stored: false,
attested_by: operator.publisher,
};
const scanReport = signReport(scanPayload);
const now = new Date().toISOString();
const row = {
id,
publisher: l.publisher.toLowerCase(),
slug: l.slug.toLowerCase(),
name: l.name,
description: l.description,
category: l.category,
version: l.version,
homepage: l.homepage || null,
icon: l.icon || null,
download_url: l.download_url,
download_sha256: l.download_sha256,
download_size: l.download_size,
scan_report: JSON.stringify(scanReport),
signer_address: operator.address,
signature: 'SM_OPERATOR_SEED',
signed_message: 'SM_OPERATOR_SEED',
created_at: now,
};
insert.run(row);
console.log(`add ${id}`);
inserted += 1;
}
console.log(`\nseed: ${inserted} inserted, ${skipped} already present`);

View file

@ -8,8 +8,9 @@
const BRAND_MARK = `<svg width="18" height="18" viewBox="0 0 64 64" style="vertical-align:-4px;margin-right:6px" aria-hidden="true"> const BRAND_MARK = `<svg width="18" height="18" viewBox="0 0 64 64" style="vertical-align:-4px;margin-right:6px" aria-hidden="true">
<rect width="64" height="64" rx="12" fill="#0b0e14"/> <rect width="64" height="64" rx="12" fill="#0b0e14"/>
<path d="M32 10 C 22 22, 24 32, 32 36 C 40 32, 42 22, 32 10 Z" fill="#d6ff3d"/> <path d="M32 6 C 38 18 46 24 46 36 C 46 48 40 56 32 56 C 24 56 18 48 18 36 C 18 28 24 22 20 14 C 26 18 30 20 32 6 Z" fill="#d6ff3d"/>
<path d="M26 36 C 20 44, 22 54, 32 56 C 42 54, 44 44, 38 36 C 36 42, 28 42, 26 36 Z" fill="#d6ff3d" opacity=".75"/> <path d="M32 20 C 36 28 40 32 40 40 C 40 48 36 52 32 52 C 28 52 24 48 24 40 C 24 34 28 30 32 20 Z" fill="#0b0e14"/>
<circle cx="32" cy="44" r="3" fill="#d6ff3d"/>
</svg>`; </svg>`;
const NAV = [ const NAV = [
@ -74,22 +75,22 @@ ${headExtra}
${body} ${body}
<footer> <footer>
<div class="fine">
<a href="//theseus.x/">Theseus</a> ·
<a href="//sirius.x/">Sirius</a> ·
<a href="//ariadne.x/">Ariadne</a> ·
<a href="//hephaestus.x/">Hephaestus</a>
<br>
Those are BCNR names, not domains — they resolve in a client that speaks
the naming system, and nowhere else.
</div>
<div class="fine"> <div class="fine">
Named for Prometheus, who gave fire to humans without asking the gods. Named for Prometheus, who gave fire to humans without asking the gods.
Distinct from the well-known Prometheus monitoring project — both take Distinct from the well-known Prometheus monitoring project — both take
the name from the same myth; neither has anything to do with the other. the name from the same myth; neither has anything to do with the other.
</div> </div>
<div class="fine"> <div class="fine" style="margin-top:1.4rem;color:var(--dim);font-size:12px">
Silent Mode — a Deviant project. MPL-2.0. Also live in the decentralized web:
<a href="//theseus.x/">theseus.x</a> ·
<a href="//sirius.x/">sirius.x</a> ·
<a href="//ariadne.x/">ariadne.x</a> ·
<a href="//aegis.x/">aegis.x</a> ·
<a href="//pithos.x/">pithos.x</a> ·
<a href="//hephaestus.x/">hephaestus.x</a>
</div>
<div class="fine" style="color:var(--dim);font-size:11px;margin-top:.6rem">
Source at <a href="https://code.silentmode.st/silentmode/prometheus">code.silentmode.st/silentmode/prometheus</a> · MPL-2.0
</div> </div>
</footer> </footer>

View file

@ -49,10 +49,14 @@ export function home() {
here: '/', here: '/',
body: ` body: `
<header class="hero"> <header class="hero">
<div class="mark" style="font-size:52px">🔥</div> <div class="mark" style="width:88px;height:88px;margin:0 auto 1rem">
<h1>Prometheus <svg viewBox="0 0 64 64" width="88" height="88" aria-hidden="true" style="display:block">
<span class="pill p-designed" style="vertical-align:middle;font-size:12px;margin-left:.6rem">designed · not yet built</span> <path d="M32 6 C 38 18 46 24 46 36 C 46 48 40 56 32 56 C 24 56 18 48 18 36 C 18 28 24 22 20 14 C 26 18 30 20 32 6 Z" fill="#d6ff3d"/>
</h1> <path d="M32 20 C 36 28 40 32 40 40 C 40 48 36 52 32 52 C 28 52 24 48 24 40 C 24 34 28 30 32 20 Z" fill="#0b0e14"/>
<circle cx="32" cy="44" r="3" fill="#d6ff3d"/>
</svg>
</div>
<h1>Prometheus<span class="g">.X</span></h1>
<p class="tag">A home for apps, programs, dApps, and libraries — <b>listed on the <p class="tag">A home for apps, programs, dApps, and libraries — <b>listed on the
Bitcoin Cash chain, hosted on Sia, endorsed by signature</b>. Anyone can publish. Bitcoin Cash chain, hosted on Sia, endorsed by signature</b>. Anyone can publish.
Nobody can gatekeep. Named for the one who gave fire to humans and did not ask Nobody can gatekeep. Named for the one who gave fire to humans and did not ask