Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
236839a914 | ||
|
|
bb3246f924 | ||
|
|
038556bb3e | ||
|
|
dca3ea56b9 | ||
|
|
c2ff10015f | ||
|
|
7d9dd4e4a9 | ||
|
|
8918951482 | ||
|
|
911b1529cc | ||
|
|
6f14d8d6bc | ||
|
|
51dd4a8391 | ||
|
|
03027f9769 | ||
|
|
4ae1f759d5 | ||
|
|
5690d2980b |
@@ -37,6 +37,18 @@ jobs:
|
||||
fetch-depth: 0 # the SBOM's version is git describe
|
||||
lfs: false # only the logs and DoE CSVs are in LFS; the build needs neither
|
||||
|
||||
- name: The capsule-signing key
|
||||
env:
|
||||
KEY: ${{ secrets.CAPSULE_SIGN_KEY }}
|
||||
run: | # ci/pki/make-ca.sh; kernel/Makefile signs with SIGN_KEY
|
||||
if [ -n "$KEY" ]; then
|
||||
f="${RUNNER_TEMP:-/tmp}/capsule-signing.key"
|
||||
(umask 077; printf '%s\n' "$KEY" > "$f")
|
||||
echo "SIGN_KEY=$f" >> "$GITHUB_ENV"; echo "The capsules will be signed."
|
||||
else
|
||||
echo "::warning::No CAPSULE_SIGN_KEY secret: the capsules are built unsigned."
|
||||
fi
|
||||
|
||||
- name: Acceptance amd64
|
||||
run: scripts/nightly.sh accept amd64
|
||||
- name: Acceptance aarch64
|
||||
|
||||
@@ -9,6 +9,8 @@ name: Build
|
||||
on:
|
||||
push:
|
||||
branches: [StarForth-v4.0.0] # not master: what reaches it has just passed acceptance (#119)
|
||||
paths-ignore: ['site/**'] # the websites (site/) build nothing here; each run is ~17 min on
|
||||
# the server the wikis share (Captain Bob, 2026-11-07)
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -34,6 +36,18 @@ jobs:
|
||||
fetch-depth: 0 # the SBOM's version is git describe
|
||||
lfs: false # only the logs and DoE CSVs are in LFS; the build needs neither
|
||||
|
||||
- name: The capsule-signing key
|
||||
env:
|
||||
KEY: ${{ secrets.CAPSULE_SIGN_KEY }}
|
||||
run: | # ci/pki/make-ca.sh; kernel/Makefile signs with SIGN_KEY
|
||||
if [ -n "$KEY" ]; then
|
||||
f="${RUNNER_TEMP:-/tmp}/capsule-signing.key"
|
||||
(umask 077; printf '%s\n' "$KEY" > "$f")
|
||||
echo "SIGN_KEY=$f" >> "$GITHUB_ENV"; echo "The capsules will be signed."
|
||||
else
|
||||
echo "::warning::No CAPSULE_SIGN_KEY secret: the capsules are built unsigned."
|
||||
fi
|
||||
|
||||
- name: Boot image
|
||||
run: make boot_image TARGET=${{ matrix.board }}
|
||||
|
||||
@@ -62,5 +76,17 @@ jobs:
|
||||
with:
|
||||
lfs: false
|
||||
|
||||
- name: The capsule-signing key
|
||||
env:
|
||||
KEY: ${{ secrets.CAPSULE_SIGN_KEY }}
|
||||
run: | # ci/pki/make-ca.sh; kernel/Makefile signs with SIGN_KEY
|
||||
if [ -n "$KEY" ]; then
|
||||
f="${RUNNER_TEMP:-/tmp}/capsule-signing.key"
|
||||
(umask 077; printf '%s\n' "$KEY" > "$f")
|
||||
echo "SIGN_KEY=$f" >> "$GITHUB_ENV"; echo "The capsules will be signed."
|
||||
else
|
||||
echo "::warning::No CAPSULE_SIGN_KEY secret: the capsules are built unsigned."
|
||||
fi
|
||||
|
||||
- name: make -C v4 test
|
||||
run: make -C v4 test
|
||||
|
||||
@@ -39,6 +39,18 @@ jobs:
|
||||
fetch-depth: 0 # the SBOM's version is git describe
|
||||
lfs: false # only the logs and DoE CSVs are in LFS; the build needs neither
|
||||
|
||||
- name: The capsule-signing key
|
||||
env:
|
||||
KEY: ${{ secrets.CAPSULE_SIGN_KEY }}
|
||||
run: | # ci/pki/make-ca.sh; kernel/Makefile signs with SIGN_KEY
|
||||
if [ -n "$KEY" ]; then
|
||||
f="${RUNNER_TEMP:-/tmp}/capsule-signing.key"
|
||||
(umask 077; printf '%s\n' "$KEY" > "$f")
|
||||
echo "SIGN_KEY=$f" >> "$GITHUB_ENV"; echo "The capsules will be signed."
|
||||
else
|
||||
echo "::warning::No CAPSULE_SIGN_KEY secret: the capsules are built unsigned."
|
||||
fi
|
||||
|
||||
- name: Acceptance amd64
|
||||
run: scripts/nightly.sh accept amd64
|
||||
- name: Acceptance aarch64
|
||||
|
||||
@@ -33,6 +33,18 @@ jobs:
|
||||
fetch-depth: 0
|
||||
lfs: false
|
||||
|
||||
- name: The capsule-signing key
|
||||
env:
|
||||
KEY: ${{ secrets.CAPSULE_SIGN_KEY }}
|
||||
run: | # ci/pki/make-ca.sh; kernel/Makefile signs with SIGN_KEY
|
||||
if [ -n "$KEY" ]; then
|
||||
f="${RUNNER_TEMP:-/tmp}/capsule-signing.key"
|
||||
(umask 077; printf '%s\n' "$KEY" > "$f")
|
||||
echo "SIGN_KEY=$f" >> "$GITHUB_ENV"; echo "The capsules will be signed."
|
||||
else
|
||||
echo "::warning::No CAPSULE_SIGN_KEY secret: the capsules are built unsigned."
|
||||
fi
|
||||
|
||||
- name: The tag names the tree's version
|
||||
run: |
|
||||
tree="v$(sed -n 's/^LITHOS_VERSION *?= *//p' kernel/Makefile)"
|
||||
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
# make-ca.sh -- the StarshipOS capsule-signing PKI, made once, on the CI box (Captain Bob,
|
||||
# 2026-11-07: "New root CA on the CI box. Valid StarshipOS rather than snake oil intermediate").
|
||||
#
|
||||
# StarshipOS Root CA Ed25519, 20 years, self-signed. Its key never leaves this box:
|
||||
# not in the repository, not in Gitea, not in any image.
|
||||
# StarshipOS Capsule Signing Ed25519, 10 years, signed by the root; CA:TRUE, pathlen:0.
|
||||
# Its certificate is built into every image (capsules/pki/
|
||||
# starshipos-intermediate.der) and checks each capsule at boot;
|
||||
# its key signs the capsules (mkcapsule --sign-key), in CI from
|
||||
# the repository secret CAPSULE_SIGN_KEY.
|
||||
#
|
||||
# Replaces the offline LithosAnanke Root CA and its snakeoil intermediate (FABRIC-2.md,
|
||||
# Milestone 6) for every build. Run as root:
|
||||
#
|
||||
# sudo ci/pki/make-ca.sh [dir] # dir defaults to /var/lib/starshipos-ca
|
||||
#
|
||||
# It refuses to overwrite an existing CA. When it is done it prints the two certificates (public:
|
||||
# paste them where they are wanted) and says how to put the signing key into Gitea. With
|
||||
# GITEA_TOKEN set (a token that may administer the repository), it stores the secret itself.
|
||||
set -euo pipefail
|
||||
umask 077
|
||||
dir=${1:-/var/lib/starshipos-ca}
|
||||
repo=${GITEA_REPO:-rajames/LithosAnanke}
|
||||
api=${GITEA_API:-https://gitea.starshipos-f18.org/api/v1}
|
||||
|
||||
command -v openssl >/dev/null || { echo "make-ca: needs openssl" >&2; exit 1; }
|
||||
[ -e "$dir/root/root.key" ] && { echo "make-ca: $dir already holds a CA; not overwriting it" >&2; exit 1; }
|
||||
mkdir -p "$dir/root" "$dir/signing"
|
||||
cd "$dir"
|
||||
|
||||
cat > ca.cnf <<'CNF'
|
||||
[ req ]
|
||||
distinguished_name = dn
|
||||
prompt = no
|
||||
[ dn ]
|
||||
[ root_ext ]
|
||||
basicConstraints = critical, CA:TRUE
|
||||
keyUsage = critical, keyCertSign, cRLSign
|
||||
subjectKeyIdentifier = hash
|
||||
[ signing_ext ]
|
||||
basicConstraints = critical, CA:TRUE, pathlen:0
|
||||
keyUsage = critical, keyCertSign, cRLSign, digitalSignature
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always
|
||||
CNF
|
||||
|
||||
# the root
|
||||
openssl genpkey -algorithm ed25519 -out root/root.key
|
||||
openssl req -new -x509 -key root/root.key -days 7305 -config ca.cnf -extensions root_ext \
|
||||
-subj "/O=StarshipOS/CN=StarshipOS Root CA" -out root/root.pem
|
||||
|
||||
# the capsule-signing intermediate, signed by the root
|
||||
openssl genpkey -algorithm ed25519 -out signing/signing.key
|
||||
openssl req -new -key signing/signing.key -config ca.cnf \
|
||||
-subj "/O=StarshipOS/CN=StarshipOS Capsule Signing" -out signing/signing.csr
|
||||
openssl x509 -req -in signing/signing.csr -CA root/root.pem -CAkey root/root.key \
|
||||
-CAcreateserial -days 3652 -extfile ca.cnf -extensions signing_ext -out signing/signing.pem
|
||||
openssl x509 -in signing/signing.pem -outform DER -out signing/starshipos-intermediate.der
|
||||
openssl verify -CAfile root/root.pem signing/signing.pem
|
||||
|
||||
chmod 700 root signing; chmod 600 root/* signing/*
|
||||
|
||||
if [ -n "${GITEA_TOKEN:-}" ]; then
|
||||
python3 -c 'import json,sys; print(json.dumps({"data": open(sys.argv[1]).read()}))' signing/signing.key |
|
||||
curl -fsS -o /dev/null -X PUT -H "Authorization: token $GITEA_TOKEN" -H 'Content-Type: application/json' \
|
||||
"$api/repos/$repo/actions/secrets/CAPSULE_SIGN_KEY" -d @- &&
|
||||
echo "make-ca: stored the signing key as $repo's secret CAPSULE_SIGN_KEY"
|
||||
else
|
||||
echo "make-ca: put $dir/signing/signing.key, whole, into $repo's Actions secret CAPSULE_SIGN_KEY"
|
||||
echo " (Settings -> Actions -> Secrets), or run again with GITEA_TOKEN set -- after"
|
||||
echo " removing $dir, since it refuses to overwrite a CA."
|
||||
fi
|
||||
echo
|
||||
echo "=== The root certificate (public) -- $dir/root/root.pem"
|
||||
cat root/root.pem
|
||||
echo "=== The capsule-signing certificate (public) -- $dir/signing/signing.pem"
|
||||
cat signing/signing.pem
|
||||
echo "=== Fingerprints"
|
||||
openssl x509 -in root/root.pem -noout -fingerprint -sha256 -subject -enddate
|
||||
openssl x509 -in signing/signing.pem -noout -fingerprint -sha256 -subject -issuer -enddate
|
||||
@@ -1,7 +1,8 @@
|
||||
# The CI runner image (#120): gitea/runner-images' Ubuntu 24.04 with Node -- which
|
||||
# actions/checkout and upload-artifact run on -- plus everything the jobs install at their start:
|
||||
# what `make ARCH=amd64,aarch64,riscv64 init INIT_DOCS=0` installs (taken from the Makefile
|
||||
# itself, not copied, so the two cannot drift), and Maven and a JRE for the publish steps.
|
||||
# itself, not copied, so the two cannot drift), Maven and a JRE for the publish steps, and
|
||||
# Isabelle's HOL-Library already built, for the proofs.
|
||||
#
|
||||
# Built by .gitea/workflows/runner-image.yml, from a context of the Makefile, boards/ and this file.
|
||||
FROM gitea/runner-images:ubuntu-24.04-v26.11.03
|
||||
@@ -11,4 +12,8 @@ WORKDIR /opt/starship-init
|
||||
RUN make --no-print-directory ARCH=amd64,aarch64,riscv64 init INIT_DOCS=0 \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -y -qq maven default-jre-headless \
|
||||
&& rm -rf /var/lib/apt/lists/* /opt/starship-init/build/cache/downloads
|
||||
# HOL-Library, built once here, into Isabelle's own heaps (system_heaps), so the nightly's proofs
|
||||
# build only the StarForth session: ~2.2 GiB and under a minute, where HOL-Library from scratch
|
||||
# takes ~5.3 GiB and ~11 minutes -- more than the runner had (nightly 174, killed).
|
||||
RUN isabelle build -b -o system_heaps -o threads=1 HOL-Library
|
||||
WORKDIR /
|
||||
|
||||
@@ -6061,3 +6061,47 @@ four conflicts resolved to the branch's files (`92ca805e`).
|
||||
- The first scheduled nightly's publish to Nexus (#17).
|
||||
- The Pi 5 and Mars images booted on their boards (#27, #28); a Pi 4 port (#26).
|
||||
- Revoke the access token `claude-session-20261106` (Settings, Applications).
|
||||
|
||||
## XLVI. The StarshipOS CA: capsules signed in CI, by a root on the CI box (2026-11-07)
|
||||
|
||||
### 1. Found
|
||||
|
||||
Every image built anywhere but Captain Bob's machine carried unsigned capsules: CI, the
|
||||
acceptance runs, the nightly bound for Nexus, a release, the demo. The capsule-signing key -- the
|
||||
snakeoil intermediate of the offline LithosAnanke Root CA (FABRIC-2.md, Milestone 6) -- lived only
|
||||
there, `kernel/Makefile`'s `SIGN_KEY` named its path, and a missing signature is a warning by
|
||||
design (2026-08-26), so they booted: `V4: capsule v4:sys:core.f18 signature: missing (unsigned)`
|
||||
in every accepted log (`logs/20261106-004933`). And `mkcapsule` signed with whatever key it was
|
||||
given: a key that is not the embedded certificate's makes every signature INVALID, which refuses
|
||||
Mama.
|
||||
|
||||
### 2. Ruled
|
||||
|
||||
Captain Bob, 2026-11-07: "New root CA on the CI box. Valid StarshipOS rather than snake oil
|
||||
intermediate."
|
||||
|
||||
### 3. Built
|
||||
|
||||
- `ci/pki/make-ca.sh`, run once on the CI box: **StarshipOS Root CA** (Ed25519, 20 years,
|
||||
self-signed; its key stays on that box, in `/var/lib/starshipos-ca`) and **StarshipOS Capsule
|
||||
Signing** (Ed25519, 10 years, issued by the root, `CA:TRUE, pathlen:0`). It refuses to
|
||||
overwrite a CA, prints both certificates, and stores the signing key as the repository secret
|
||||
`CAPSULE_SIGN_KEY` (or says how).
|
||||
- The image carries `capsules/pki/starshipos-intermediate.der` in place of the snakeoil
|
||||
intermediate; the kernel finds it by one name, `CAPSULE_SIGNING_CERT_NAME` (`capsule_sig.h`).
|
||||
- `mkcapsule` checks the signing key against that certificate before it writes anything, and
|
||||
refuses a key that is not its, or a key with no certificate to check.
|
||||
- `SIGN_KEY` has no default (`kernel/Makefile`, `v4/Makefile`): CI sets it from the secret (a step
|
||||
in `acceptance.yml`, `build.yml`, `nightly.yml`, `release.yml`); unset, the capsules are built
|
||||
unsigned, as before.
|
||||
|
||||
What it is not: the kernel still does not check the intermediate against a root at boot
|
||||
(`x509_ed25519.h`; `ACL.4th`'s `ACL-CA-KEY` is still 0). A signature proves a capsule matches the
|
||||
certificate in the same image. That is unchanged by this, and a ruling of its own.
|
||||
|
||||
### 4. Verified
|
||||
|
||||
With a CA made by `make-ca.sh` in a scratch directory (not the real one): `openssl verify` of the
|
||||
chain OK; `make-ca.sh` refuses a second run; `mkcapsule` with the signing key -- "signing key
|
||||
matches"; with the root's key -- refused; with a key and no certificate -- refused; with no key --
|
||||
unsigned, as before. The acceptance with the real certificate is the PR's.
|
||||
|
||||
+7
-7
@@ -207,7 +207,8 @@ MKCAPSULE_SRC = tools/mkcapsule.c tools/pkcs8_ed25519.c \
|
||||
kernel/src/crypto/ed25519.c \
|
||||
kernel/src/crypto/fe25519.c \
|
||||
kernel/src/crypto/scalar25519.c \
|
||||
kernel/src/crypto/sha512.c
|
||||
kernel/src/crypto/sha512.c \
|
||||
kernel/src/crypto/x509_ed25519.c
|
||||
MKCAPSULE_BIN = $(BUILD_DIR)/tools/mkcapsule
|
||||
# mkartemis: formats and signs an Artemis partition at build with the kernel's own
|
||||
# block-subsystem and artemis_sig code (tools/mkartemis.c), built as v4/Makefile builds them.
|
||||
@@ -215,12 +216,11 @@ MKARTEMIS_SRC = tools/mkartemis.c kernel/src/artemis_sig.c \
|
||||
$(addprefix v3/src/,block_subsystem.c blkio_ram.c blkio_file.c log.c \
|
||||
platform/platform_init.c platform/linux/time.c)
|
||||
MKARTEMIS_BIN = $(BUILD_DIR)/tools/mkartemis
|
||||
# Milestone 6 (Phase 8): the snakeoil intermediate's private key, generated
|
||||
# offline outside this repo entirely (see FABRIC-2.md's Phase 8 §Milestone 6
|
||||
# writeup) -- not present in CI or a fresh checkout, so signing is skipped
|
||||
# gracefully ($(wildcard ...) below) rather than failing the build. Override
|
||||
# with `make SIGN_KEY=/path/to/key.pem ...` on a machine that holds it.
|
||||
SIGN_KEY ?= /home/rajames/CLionProjects/lithosananke-ca/intermediate/snakeoil-intermediate.key
|
||||
# The capsule-signing key: "StarshipOS Capsule Signing"'s private key (ci/pki/make-ca.sh,
|
||||
# FABRIC-3.md XLVI). CI sets SIGN_KEY from the secret CAPSULE_SIGN_KEY; elsewhere set it by hand
|
||||
# (`make SIGN_KEY=/path/to/signing.key ...`). Unset or absent, the capsules are built unsigned,
|
||||
# which boots with a warning per capsule. mkcapsule refuses a key that is not the certificate's.
|
||||
SIGN_KEY ?=
|
||||
SIGN_KEY_ARGS = $(if $(wildcard $(SIGN_KEY)),--sign-key $(SIGN_KEY),)
|
||||
CAPSULE_GENERATED = $(BUILD_DIR)/capsule_generated.c
|
||||
CAPSULE_GENERATED_OBJ = $(BUILD_DIR)/capsule_generated.o
|
||||
|
||||
@@ -171,7 +171,8 @@ typedef struct {
|
||||
*
|
||||
* Milestone 6 (Phase 8): each capsule's payload bytes (the same bytes
|
||||
* content_hash already covers), signed by mkcapsule at build time with
|
||||
* the snakeoil intermediate's private key. has_sig=0 for a capsule built
|
||||
* the capsule-signing key (StarshipOS Capsule Signing, capsule_sig.h;
|
||||
* the snakeoil intermediate's until 2026-11-07). has_sig=0 for a capsule built
|
||||
* before this feature existed or otherwise unsigned -- a real, distinct
|
||||
* state, not "signature is all-zero bytes" (which sig[64] full of 0x00
|
||||
* would otherwise look ambiguous with). Indexed 1:1 with
|
||||
|
||||
@@ -22,6 +22,12 @@
|
||||
|
||||
#include "starkernel/capsule.h"
|
||||
|
||||
/* The certificate whose key the capsules are signed with: "StarshipOS
|
||||
* Capsule Signing", issued by the StarshipOS Root CA (ci/pki/make-ca.sh;
|
||||
* FABRIC-3.md XLVI), replacing the snakeoil intermediate of Milestone 6.
|
||||
* mkcapsule refuses to sign with a key that is not this certificate's. */
|
||||
#define CAPSULE_SIGNING_CERT_NAME "pki:starshipos-intermediate.der"
|
||||
|
||||
typedef enum {
|
||||
CAPSULE_SIG_OK = 0, /* has_sig=1, and it verifies */
|
||||
CAPSULE_SIG_MISSING, /* has_sig=0 -- not signed at all */
|
||||
@@ -31,9 +37,9 @@ typedef enum {
|
||||
|
||||
/*
|
||||
* Verify capsule descs[index]'s Ed25519 signature against the embedded
|
||||
* snakeoil intermediate cert's public key (capsule name
|
||||
* "pki:snakeoil-intermediate.der", found and parsed once, cached for
|
||||
* every later call this boot -- the cert doesn't change mid-boot).
|
||||
* capsule-signing certificate's public key (CAPSULE_SIGNING_CERT_NAME,
|
||||
* found and parsed once, cached for every later call this boot -- the
|
||||
* cert doesn't change mid-boot).
|
||||
*
|
||||
* descs/names/sigs must be the same three parallel arrays
|
||||
* (capsule_get_descriptors()/capsule_get_names()/capsule_get_signatures()),
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
*
|
||||
* x509_extract_ed25519_pubkey() only ever reads SubjectPublicKeyInfo --
|
||||
* no signature verification, no chain validation, no extension parsing.
|
||||
* That's the capsule-PKI use case (Milestone 6): the embedded snakeoil
|
||||
* intermediate cert is trusted because it's baked into the trusted build,
|
||||
* never re-verified against the offline root CA at boot.
|
||||
* That's the capsule-PKI use case (Milestone 6): the embedded capsule-
|
||||
* signing cert (StarshipOS Capsule Signing since 2026-11-07, the snakeoil
|
||||
* intermediate before it) is trusted because it's baked into the trusted
|
||||
* build, never re-verified against its root CA at boot.
|
||||
*
|
||||
* x509_verify_signature()/x509_extract_serial() (added 2026-08-28,
|
||||
* FABRIC-2.md §F.7/§F.17) are for CERTVERIFY -- a regular user's cert,
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include "starkernel/ed25519.h"
|
||||
#include <string.h>
|
||||
|
||||
#define SNAKEOIL_CERT_NAME "pki:snakeoil-intermediate.der"
|
||||
|
||||
/* Cached once per boot: the cert doesn't change mid-boot, and every
|
||||
* capsule birth (Mama, then every child VM) would otherwise re-find and
|
||||
* re-parse the same cert. -1 = not yet attempted, 0 = failed, 1 = ready. */
|
||||
@@ -20,7 +18,7 @@ static int find_and_cache_pubkey(const CapsuleDesc *descs,
|
||||
|
||||
pubkey_state = 0; /* assume failure unless every step below succeeds */
|
||||
for (uint32_t i = 0; i < desc_count; i++) {
|
||||
if (strcmp(names[i].name, SNAKEOIL_CERT_NAME) == 0) {
|
||||
if (strcmp(names[i].name, CAPSULE_SIGNING_CERT_NAME) == 0) {
|
||||
const CapsuleDesc *cert_desc = &descs[i];
|
||||
if (x509_extract_ed25519_pubkey(arena_base + cert_desc->offset,
|
||||
(size_t)cert_desc->length,
|
||||
|
||||
+2
-1
@@ -17,7 +17,8 @@
|
||||
# make -C v4 test-32: v4 with 32-bit cells, every test (the acceptance's last part).
|
||||
# scripts/nightly.sh proofs
|
||||
# isabelle build -c -D proof/: the StarForth session checked afresh every run, whatever is
|
||||
# cached (HOL-Library is reused); its log is logs/<TS>/isabelle/, as a boot's is.
|
||||
# cached (HOL-Library is reused: the CI image has it built, ci/runner-image); its log is
|
||||
# logs/<TS>/isabelle/, as a boot's is.
|
||||
# scripts/nightly.sh images
|
||||
# The board images, into build/nightly/:
|
||||
# raspi5.img.xz Raspberry Pi 5 (make boot_image TARGET=RASPI), for Raspberry Pi Imager
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
__pycache__/
|
||||
@@ -0,0 +1,14 @@
|
||||
# site/brand -- the wikis' banner
|
||||
|
||||
The top bar of both XWikis shows the starshipOS wordmark, not XWiki's logo, and the browser tab's
|
||||
title ends "- StarshipOS" (Captain Bob, 2026-11-07). `starshipos-com.png` and `starshipos-org.png`
|
||||
are the wordmark (Exo 2, white with an orange "OS", transparent), rendered at 2x.
|
||||
|
||||
```
|
||||
XWIKI_USER=rajames XWIKI_PASSWORD=... site/brand/install.sh https://starshipos-f18.com starshipos-com.png
|
||||
XWIKI_USER=rajames XWIKI_PASSWORD=... site/brand/install.sh https://starshipos-f18.org starshipos-org.png
|
||||
```
|
||||
|
||||
The logo belongs to the colour theme, so this makes one of our own, `FlamingoThemes.StarshipOS` (a
|
||||
copy of the stock Iceberg with the wordmark), and makes it the wiki's. To undo: set the wiki's
|
||||
colour theme back to Iceberg (Administration, Look & Feel, Themes).
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
# install.sh -- the wiki's banner says StarshipOS, not XWiki (Captain Bob, 2026-11-07: "The banner
|
||||
# XWiki should not say that").
|
||||
#
|
||||
# site/brand/install.sh https://starshipos-f18.com starshipos-com.png
|
||||
# site/brand/install.sh https://starshipos-f18.org starshipos-org.png
|
||||
#
|
||||
# In XWiki 17 the top bar's logo is the colour theme's. This makes a colour theme of our own,
|
||||
# FlamingoThemes.StarshipOS -- a copy of the stock Iceberg with our wordmark as its logo -- and
|
||||
# makes it the wiki's; the stock theme is not touched (set colorTheme back to
|
||||
# FlamingoThemes.Iceberg to undo). It also makes the browser tab's title "<page> - StarshipOS".
|
||||
# Run again after changing the wordmark: the logo is replaced. XWIKI_USER and XWIKI_PASSWORD as for
|
||||
# site/*/install.sh. Everything goes as XML: XWiki refuses form and plain-text writes without its
|
||||
# form token.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
base=${1:?usage: install.sh <wiki URL> <logo.png>}
|
||||
logo=${2:?usage: install.sh <wiki URL> <logo.png>}
|
||||
rest="$base/rest/wikis/xwiki/spaces"
|
||||
auth=(-u "${XWIKI_USER:?set XWIKI_USER}:${XWIKI_PASSWORD:?set XWIKI_PASSWORD}")
|
||||
theme="$rest/FlamingoThemes/pages/StarshipOS"
|
||||
x() { curl -fsS -m 60 "${auth[@]}" "$@"; }
|
||||
prop() { # prop <object URL> <name> <value>: set one property
|
||||
x -o /dev/null -w " $2: %{http_code}\n" -X PUT -H 'Content-Type: application/xml' \
|
||||
--data-binary "$(python3 -c '
|
||||
import sys
|
||||
from xml.sax.saxutils import escape
|
||||
print("<property xmlns=\"http://www.xwiki.org\" name=\"%s\"><value>%s</value></property>" % (escape(sys.argv[1]), escape(sys.argv[2])))' "$2" "$3")" \
|
||||
"$1/properties/$2"
|
||||
}
|
||||
|
||||
echo "=== $base: the colour theme FlamingoThemes.StarshipOS"
|
||||
x -o /dev/null -w " page: %{http_code}\n" -X PUT -H 'Content-Type: application/xml' --data-binary \
|
||||
'<page xmlns="http://www.xwiki.org"><title>StarshipOS</title><syntax>xwiki/2.1</syntax><content>{{include reference="FlamingoThemesCode.ThemeSheet"/}}</content></page>' \
|
||||
"$theme"
|
||||
x -o /dev/null -w " logo $logo: %{http_code}\n" -X PUT -H 'Content-Type: image/png' --data-binary "@$logo" \
|
||||
"$theme/attachments/$logo"
|
||||
have=$(x -H 'Accept: application/json' "$theme/objects/FlamingoThemesCode.ThemeClass" |
|
||||
python3 -c 'import json,sys; print(len(json.load(sys.stdin).get("objectSummaries") or []))')
|
||||
if [ "$have" = 0 ]; then
|
||||
# Iceberg's theme object, every property as it is, posted to our page
|
||||
x -H 'Accept: application/xml' "$rest/FlamingoThemes/pages/Iceberg/objects/FlamingoThemesCode.ThemeClass/0" |
|
||||
x -o /dev/null -w " theme object, from Iceberg: %{http_code}\n" -X POST -H 'Content-Type: application/xml' \
|
||||
--data-binary @- "$theme/objects"
|
||||
fi
|
||||
prop "$theme/objects/FlamingoThemesCode.ThemeClass/0" logo "$logo"
|
||||
prop "$theme/objects/FlamingoThemesCode.ThemeClass/0" logo-description "StarshipOS"
|
||||
|
||||
echo "=== the wiki's preferences"
|
||||
prefs="$rest/XWiki/pages/XWikiPreferences/objects/XWiki.XWikiPreferences/0"
|
||||
prop "$prefs" colorTheme "FlamingoThemes.StarshipOS"
|
||||
prop "$prefs" title "\$tdoc.getRenderedTitle('plain/1.0') - StarshipOS"
|
||||
|
||||
echo "=== check, as a guest"
|
||||
page=$(curl -sS -m 60 "$base/bin/login/XWiki/XWikiLogin") # a page that shows the chrome to a guest
|
||||
case "$page" in *"FlamingoThemes/StarshipOS/$logo"*) echo " the banner's logo: ours";; *) echo " the banner's logo: NOT ours" >&2; exit 1;; esac
|
||||
case "$page" in *"- StarshipOS</title>"*) echo " the tab's title: ends - StarshipOS";; *) echo " the tab's title: NOT ours" >&2; exit 1;; esac
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,64 @@
|
||||
"""colorlock.py -- keep a page's own colours inside a wiki whose theme forces its own.
|
||||
|
||||
Both XWikis carry a high-contrast theme (skins/flamingo/cssVariablesInit.css on the server) that sets
|
||||
every element black on white with !important. On our pages the design's colours win instead
|
||||
(Captain Bob, 2026-11-07), and on those pages only; the rest of the wiki keeps the theme:
|
||||
|
||||
- every colour an element states in its style="" is made !important -- an inline !important beats
|
||||
any stylesheet's;
|
||||
- a stylesheet scoped to the page's root (class "ssos") covers the elements that state no colour:
|
||||
".ssos *" outranks the theme's "*" (both !important, the more specific wins).
|
||||
"""
|
||||
import re
|
||||
|
||||
ROOT_CLASS = "ssos"
|
||||
STYLE = """<style>
|
||||
.ssos, .ssos *, .ssos *::before, .ssos *::after { background-color: transparent !important; color: inherit !important; border-color: #22324D !important; }
|
||||
.ssos a, .ssos a * { color: #F5891F !important; }
|
||||
.ssos a:hover { color: #FFB061 !important; }
|
||||
.ssos input, .ssos textarea, .ssos select { background-color: #0A1222 !important; color: #EEF2F7 !important; border-color: #34486A !important; }
|
||||
.ssos ::placeholder { color: #A3AEC2 !important; opacity: 1 !important; }
|
||||
.ssos img { background-color: transparent !important; }
|
||||
</style>"""
|
||||
COLOUR_PROPS = re.compile(r"^\s*(color|background|background-color|border|border-(top|right|bottom|left)|"
|
||||
r"border-color|border-(top|right|bottom|left)-color|accent-color|fill)\s*:", re.I)
|
||||
|
||||
|
||||
def _lock_style(m):
|
||||
decls = []
|
||||
for d in m.group(1).split(";"):
|
||||
if d.strip() and COLOUR_PROPS.match(d) and "!important" not in d:
|
||||
d = d.rstrip() + " !important"
|
||||
decls.append(d)
|
||||
return 'style="%s"' % ";".join(decls)
|
||||
|
||||
|
||||
def lock(html, root_marker):
|
||||
"""root_marker: the opening text of the page's root element, e.g. '<div style="background: #0A1222'."""
|
||||
assert html.count(root_marker) >= 1, root_marker
|
||||
html = html.replace(root_marker, root_marker.replace("<div ", '<div class="%s" ' % ROOT_CLASS, 1), 1)
|
||||
html = re.sub(r'style="([^"]*)"', _lock_style, html)
|
||||
return STYLE + "\n" + html
|
||||
|
||||
|
||||
# For visitors (guests) only, the page is the design alone: XWiki's own chrome -- the top bar with
|
||||
# Register and Log-in, the breadcrumb, the title and "Last modified", the page menu, the side panels,
|
||||
# the footer and the welcome tour -- is hidden, and the design runs the full width. Logged in, the
|
||||
# wiki is all there, to edit with. (Captain Bob, 2026-11-07: "Menu bar".)
|
||||
GUEST_CHROME = """{{velocity}}
|
||||
#if ($isGuest)
|
||||
#[[{{html clean="false"}}<style>
|
||||
#menuview, #hierarchy_breadcrumb, .document-header, #xdocFooter, #footerglobal, #leftPanels, #rightPanels,
|
||||
#leftPanelsToggle, #rightPanelsToggle, .tour, .tour-backdrop, #bootstrap_tour_restart, .xtour-restart,
|
||||
#xwikimaincontainerinner > a.btn { display: none !important; }
|
||||
html, body, #xwikimaincontainer, #xwikimaincontainerinner, #contentcontainer, #contentcolumn, .main,
|
||||
#mainContentArea, #xwikicontent, #mainContentArea .row { background-color: #0A1222 !important; }
|
||||
#contentcontainer, #contentcolumn, .main, #mainContentArea, #xwikicontent, #mainContentArea .row {
|
||||
width: 100% !important; max-width: none !important; margin: 0 !important; padding: 0 !important; border: 0 !important; float: none !important; }
|
||||
#xwikicontent > .ssos { border: 0 !important; }
|
||||
#xwikimaincontainer { padding: 0 !important; }
|
||||
.main hr:not(.ssos hr), #xwikicontent > :not(.ssos) { display: none !important; }
|
||||
</style>{{/html}}]]#
|
||||
#end
|
||||
{{/velocity}}
|
||||
"""
|
||||
@@ -0,0 +1,120 @@
|
||||
{{velocity}}
|
||||
#if ($isGuest)
|
||||
#[[{{html clean="false"}}<style>
|
||||
#menuview, #hierarchy_breadcrumb, .document-header, #xdocFooter, #footerglobal, #leftPanels, #rightPanels,
|
||||
#leftPanelsToggle, #rightPanelsToggle, .tour, .tour-backdrop, #bootstrap_tour_restart, .xtour-restart,
|
||||
#xwikimaincontainerinner > a.btn { display: none !important; }
|
||||
html, body, #xwikimaincontainer, #xwikimaincontainerinner, #contentcontainer, #contentcolumn, .main,
|
||||
#mainContentArea, #xwikicontent, #mainContentArea .row { background-color: #0A1222 !important; }
|
||||
#contentcontainer, #contentcolumn, .main, #mainContentArea, #xwikicontent, #mainContentArea .row {
|
||||
width: 100% !important; max-width: none !important; margin: 0 !important; padding: 0 !important; border: 0 !important; float: none !important; }
|
||||
#xwikicontent > .ssos { border: 0 !important; }
|
||||
#xwikimaincontainer { padding: 0 !important; }
|
||||
.main hr:not(.ssos hr), #xwikicontent > :not(.ssos) { display: none !important; }
|
||||
</style>{{/html}}]]#
|
||||
#end
|
||||
{{/velocity}}
|
||||
{{html clean="false"}}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
.ssos, .ssos *, .ssos *::before, .ssos *::after { background-color: transparent !important; color: inherit !important; border-color: #22324D !important; }
|
||||
.ssos a, .ssos a * { color: #F5891F !important; }
|
||||
.ssos a:hover { color: #FFB061 !important; }
|
||||
.ssos input, .ssos textarea, .ssos select { background-color: #0A1222 !important; color: #EEF2F7 !important; border-color: #34486A !important; }
|
||||
.ssos ::placeholder { color: #A3AEC2 !important; opacity: 1 !important; }
|
||||
.ssos img { background-color: transparent !important; }
|
||||
</style>
|
||||
<div class="ssos" style="background: #0A1222 !important; color: #EEF2F7 !important; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6; min-height: 0">
|
||||
|
||||
<header style="border-bottom: 1px solid #22324D !important">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="/bin/view/Main/" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7 !important; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: #F5891F !important">OS</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px">
|
||||
<a href="/bin/view/Main/" style="color: #C8D1DE !important; text-decoration: none">Home</a>
|
||||
<a href="/bin/view/Inquiries/" aria-current="page" style="color: #EEF2F7 !important; text-decoration: none; border-bottom: 2px solid #F5891F !important">Inquiries</a>
|
||||
<a href="https://starshipos-f18.org/" style="color: #F5891F !important; text-decoration: none">Contributors →</a>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 80px 24px 32px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">Inquiries</p>
|
||||
<h1 style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: clamp(36px, 5vw, 56px); line-height: 1.1">Talk to the bridge.</h1>
|
||||
<p style="margin: 0; max-width: 640px; font-size: 18px; color: #C8D1DE !important">Licensing, research collaboration, press or plain curiosity — every message is read by a human. Want to contribute code? Head to <a href="https://starshipos-f18.org/">starshipos-f18.org</a>.</p>
|
||||
</section>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 32px 24px 96px; display: flex; flex-wrap: wrap; gap: 48px; align-items: flex-start">
|
||||
|
||||
<form action="https://starshipos-f18.org/bin/view/PublicInquiry/" method="post" aria-label="Inquiry form" style="flex: 999 1 520px; min-width: 0; background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 32px; display: flex; flex-direction: column; gap: 20px">
|
||||
<div aria-hidden="true" style="position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden"><label for="q-website">Leave this empty</label><input id="q-website" name="website" type="text" tabindex="-1" autocomplete="off"></div>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px">
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-name" style="font-size: 14px; color: #C8D1DE !important">Name</label>
|
||||
<input id="q-name" name="name" type="text" autocomplete="name" style="min-height: 48px; padding: 0 14px; background: #0A1222 !important; border: 1px solid #34486A !important; border-radius: 4px; color: #EEF2F7 !important; font-family: inherit; font-size: 15px">
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-email" style="font-size: 14px; color: #C8D1DE !important">Email</label>
|
||||
<input id="q-email" name="email" type="email" autocomplete="email" style="min-height: 48px; padding: 0 14px; background: #0A1222 !important; border: 1px solid #34486A !important; border-radius: 4px; color: #EEF2F7 !important; font-family: inherit; font-size: 15px">
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-org" style="font-size: 14px; color: #C8D1DE !important">Organization <span style="color: #A3AEC2 !important">(optional)</span></label>
|
||||
<input id="q-org" name="organization" type="text" autocomplete="organization" style="min-height: 48px; padding: 0 14px; background: #0A1222 !important; border: 1px solid #34486A !important; border-radius: 4px; color: #EEF2F7 !important; font-family: inherit; font-size: 15px">
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-topic" style="font-size: 14px; color: #C8D1DE !important">Topic</label>
|
||||
<select id="q-topic" name="topic" style="min-height: 48px; padding: 0 14px; background: #0A1222 !important; border: 1px solid #34486A !important; border-radius: 4px; color: #EEF2F7 !important; font-family: inherit; font-size: 15px">
|
||||
<option>General question</option>
|
||||
<option>Licensing</option>
|
||||
<option>Research collaboration</option>
|
||||
<option>Hardware / FPGA</option>
|
||||
<option>Press & media</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-msg" style="font-size: 14px; color: #C8D1DE !important">Message</label>
|
||||
<textarea id="q-msg" name="message" rows="7" style="padding: 12px 14px; background: #0A1222 !important; border: 1px solid #34486A !important; border-radius: 4px; color: #EEF2F7 !important; font-family: inherit; font-size: 15px; resize: vertical"></textarea>
|
||||
</div>
|
||||
<div style="display: flex; align-items: flex-start; gap: 12px">
|
||||
<input id="q-list" name="announcements" type="checkbox" style="width: 20px; height: 20px; margin: 3px 0 0; accent-color: #F5891F !important">
|
||||
<label for="q-list" style="font-size: 14px; color: #C8D1DE !important">Also add me to launch announcements (low volume, unsubscribe anytime).</label>
|
||||
</div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; gap: 16px">
|
||||
<button type="submit" style="min-height: 48px; padding: 0 28px; background: #F5891F !important; color: #0A1222 !important; border: 0 !important; border-radius: 4px; font-family: inherit; font-weight: 700; font-size: 15px; cursor: pointer">Send inquiry</button>
|
||||
<span style="font-size: 13px; color: #A3AEC2 !important">Replies usually within a few days.</span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<aside aria-label="Direct addresses" style="flex: 1 1 300px; display: flex; flex-direction: column; gap: 24px">
|
||||
<h2 style="margin: 0; font-family: 'Exo 2', sans-serif; font-size: 24px">Or write directly</h2>
|
||||
<div style="border-top: 1px solid #22324D !important; padding-top: 16px">
|
||||
<div style="font-size: 13px; color: #A3AEC2 !important">General</div>
|
||||
<a href="mailto:info@starshipos.com" style="font-size: 16px">info@starshipos.com</a>
|
||||
</div>
|
||||
<div style="border-top: 1px solid #22324D !important; padding-top: 16px">
|
||||
<div style="font-size: 13px; color: #A3AEC2 !important">Licensing & partnerships</div>
|
||||
<a href="mailto:licensing@starshipos.com" style="font-size: 16px">licensing@starshipos.com</a>
|
||||
</div>
|
||||
<div style="border-top: 1px solid #22324D !important; padding-top: 16px">
|
||||
<div style="font-size: 13px; color: #A3AEC2 !important">Press & media</div>
|
||||
<a href="mailto:press@starshipos.com" style="font-size: 16px">press@starshipos.com</a>
|
||||
</div>
|
||||
<div style="border-top: 1px solid #22324D !important; padding-top: 16px">
|
||||
<div style="font-size: 13px; color: #A3AEC2 !important">Security reports</div>
|
||||
<a href="mailto:security@starshipos.org" style="font-size: 16px">security@starshipos.org</a>
|
||||
</div>
|
||||
<p style="margin: 0; padding-top: 16px; border-top: 1px solid #22324D !important; font-size: 13px; color: #A3AEC2 !important">StarshipOS is developed in Ashland, Ohio.</p>
|
||||
</aside>
|
||||
|
||||
</section>
|
||||
|
||||
<footer style="border-top: 1px solid #22324D !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2 !important">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="/bin/view/Main/" style="color: #C8D1DE !important">Home</a><a href="https://starshipos-f18.org/" style="color: #C8D1DE !important">starshipos-f18.org</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
{{/html}}
|
||||
@@ -0,0 +1,152 @@
|
||||
{{velocity}}
|
||||
#if ($isGuest)
|
||||
#[[{{html clean="false"}}<style>
|
||||
#menuview, #hierarchy_breadcrumb, .document-header, #xdocFooter, #footerglobal, #leftPanels, #rightPanels,
|
||||
#leftPanelsToggle, #rightPanelsToggle, .tour, .tour-backdrop, #bootstrap_tour_restart, .xtour-restart,
|
||||
#xwikimaincontainerinner > a.btn { display: none !important; }
|
||||
html, body, #xwikimaincontainer, #xwikimaincontainerinner, #contentcontainer, #contentcolumn, .main,
|
||||
#mainContentArea, #xwikicontent, #mainContentArea .row { background-color: #0A1222 !important; }
|
||||
#contentcontainer, #contentcolumn, .main, #mainContentArea, #xwikicontent, #mainContentArea .row {
|
||||
width: 100% !important; max-width: none !important; margin: 0 !important; padding: 0 !important; border: 0 !important; float: none !important; }
|
||||
#xwikicontent > .ssos { border: 0 !important; }
|
||||
#xwikimaincontainer { padding: 0 !important; }
|
||||
.main hr:not(.ssos hr), #xwikicontent > :not(.ssos) { display: none !important; }
|
||||
</style>{{/html}}]]#
|
||||
#end
|
||||
{{/velocity}}
|
||||
{{html clean="false"}}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
.ssos, .ssos *, .ssos *::before, .ssos *::after { background-color: transparent !important; color: inherit !important; border-color: #22324D !important; }
|
||||
.ssos a, .ssos a * { color: #F5891F !important; }
|
||||
.ssos a:hover { color: #FFB061 !important; }
|
||||
.ssos input, .ssos textarea, .ssos select { background-color: #0A1222 !important; color: #EEF2F7 !important; border-color: #34486A !important; }
|
||||
.ssos ::placeholder { color: #A3AEC2 !important; opacity: 1 !important; }
|
||||
.ssos img { background-color: transparent !important; }
|
||||
</style>
|
||||
<div class="ssos" style="background: #0A1222 !important; color: #EEF2F7 !important; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6; min-height: 0">
|
||||
|
||||
<header style="border-bottom: 1px solid #22324D !important">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="/bin/view/Main/" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7 !important; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: #F5891F !important">OS</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px">
|
||||
<a href="#system" style="color: #C8D1DE !important; text-decoration: none">System</a>
|
||||
<a href="#research" style="color: #C8D1DE !important; text-decoration: none">Research</a>
|
||||
<a href="#silicon" style="color: #C8D1DE !important; text-decoration: none">Silicon</a>
|
||||
<a href="/bin/view/Inquiries/" style="color: #C8D1DE !important; text-decoration: none">Inquiries</a>
|
||||
<a href="https://starshipos-f18.org/" style="color: #F5891F !important; text-decoration: none">Contributors →</a>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 96px 24px 72px; display: flex; flex-wrap: wrap; align-items: center; gap: 56px">
|
||||
<div style="flex: 999 1 520px; min-width: 0">
|
||||
<p style="margin: 0 0 20px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0 !important">ok> bare metal · FORTH · C99</p>
|
||||
<h1 style="margin: 0 0 24px; font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: clamp(40px, 6vw, 68px); line-height: 1.05; letter-spacing: -0.01em">An operating system that obeys a conservation law.</h1>
|
||||
<p style="margin: 0 0 36px; max-width: 620px; font-size: 18px; color: #C8D1DE !important">StarshipOS is a bare-metal operating system built from the ground up in StarForth and C99. One compudynamic engine governs every word, message, block and virtual machine — and holds K≡1.0 on every architecture it runs on.</p>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 16px">
|
||||
<a href="#system" style="display: inline-block; padding: 14px 24px; background: #F5891F !important; color: #0A1222 !important; font-weight: 700; text-decoration: none; border-radius: 4px">See how it works</a>
|
||||
<a href="/bin/view/Inquiries/" style="display: inline-block; padding: 14px 24px; border: 1px solid #34486A !important; color: #EEF2F7 !important; text-decoration: none; border-radius: 4px">Make an inquiry</a>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex: 1 1 400px; display: flex; justify-content: center">
|
||||
<img src="/bin/download/Main/WebHome/badge.jpg" alt="StarshipOS badge: Santino the mascot inside a ring on a starfield" style="width: 100%; max-width: 540px; height: auto; display: block; border-radius: 8px; border: 1px solid #22324D !important">
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-label="At a glance" style="border-top: 1px solid #22324D !important; border-bottom: 1px solid #22324D !important; background: #0E182B !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 24px">
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">38,400+</div><div style="font-size: 14px; color: #A3AEC2 !important">experimental runs validating K≡1.0</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">3 ISAs</div><div style="font-size: 14px; color: #A3AEC2 !important">amd64 · aarch64 · riscv64</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">FORTH-79</div><div style="font-size: 14px; color: #A3AEC2 !important">compliant core, live at the ok> prompt</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">Patent pending</div><div style="font-size: 14px; color: #A3AEC2 !important">LithosAnanke kernel architecture</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="system" style="max-width: 1120px; margin: 0 auto; padding: 96px 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">The system</p>
|
||||
<h2 style="margin: 0 0 48px; font-family: 'Exo 2', sans-serif; font-size: 40px; line-height: 1.15; max-width: 760px">One engine. One fabric. Everything in it obeys the same physics.</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px">
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 24px">StarForth</h3>
|
||||
<p style="margin: 0 0 16px; font-size: 13px; color: #F5891F !important">the language and the VM</p>
|
||||
<p style="margin: 0; color: #C8D1DE !important">A FORTH-79 compliant adaptive virtual machine written in C99. Words execute by heat: what the system uses, it keeps close. Everything a user touches is StarForth — there is no compiler inside the box.</p>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 24px">LithosAnanke</h3>
|
||||
<p style="margin: 0 0 16px; font-size: 13px; color: #F5891F !important">the microkernel</p>
|
||||
<p style="margin: 0; color: #C8D1DE !important">A bare-metal microkernel built around the Stadium — a single fabric where words, messages, blocks and VMs live side by side, all governed by one compudynamic engine.</p>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 24px">The fleet</h3>
|
||||
<p style="margin: 0 0 16px; font-size: 13px; color: #F5891F !important">VMs that are born, not spawned</p>
|
||||
<p style="margin: 0; color: #C8D1DE !important">Hera births and governs the fleet. Artemis keeps the blocks. Console draws a vector framebuffer. Hermes, in the kernel, carries every message — and every message is checked against its ACL.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 32px; border-top: 1px solid #22324D !important; padding-top: 48px">
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7 !important">Phenomenon first</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2 !important">Observe the behaviour, then write the mathematics. Document before code.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7 !important">Parity first</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2 !important">The same machine on every ISA, proven by reproducible dictionary hashes.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7 !important">Identity on a key</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2 !important">Your certificate lives on a thumb drive. No key, no session.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7 !important">Minimal by design</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2 !important">A small core of primitives; everything else composed in FORTH.</p></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="research" style="max-width: 1120px; margin: 0 auto; padding: 72px 24px">
|
||||
<div style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 40px; display: flex; flex-wrap: wrap; gap: 40px; align-items: center">
|
||||
<div style="flex: 999 1 480px; min-width: 0">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">Research</p>
|
||||
<h2 style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: 32px; line-height: 1.2">James Law: K≡1.0</h2>
|
||||
<p style="margin: 0; color: #C8D1DE !important">A conservation invariant that holds regardless of instruction set. Validated across 38,400+ runs in 128 configurations under QEMU on amd64, aarch64 and riscv64, and published on SSRN.</p>
|
||||
</div>
|
||||
<div style="flex: 1 1 220px; display: flex; flex-direction: column; gap: 12px">
|
||||
<a href="https://starshipos-f18.org/" style="display: inline-block; padding: 14px 20px; background: #F5891F !important; color: #0A1222 !important; font-weight: 700; text-decoration: none; border-radius: 4px; text-align: center">Read the paper</a>
|
||||
<a href="https://starshipos-f18.org/" style="display: inline-block; padding: 14px 20px; border: 1px solid #34486A !important; color: #EEF2F7 !important; text-decoration: none; border-radius: 4px; text-align: center">Design docs on the .org</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="silicon" style="max-width: 1120px; margin: 0 auto; padding: 48px 24px 96px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">Next: silicon</p>
|
||||
<h2 style="margin: 0 0 20px; font-family: 'Exo 2', sans-serif; font-size: 40px; line-height: 1.15; max-width: 760px">From virtual machine to fabric.</h2>
|
||||
<p style="margin: 0; max-width: 720px; color: #C8D1DE !important">StarForth V4 is being brought up as a mesh of tiny stack-machine cores on FPGA — words as instructions, messaging in hardware, and the compudynamic engine steering what runs and when. Same machine, same parity, now in logic.</p>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="bridge-h" style="max-width: 1120px; margin: 0 auto; padding: 0 24px 96px">
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 48px; align-items: center; background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 8px; padding: 32px">
|
||||
<img src="/bin/download/Main/WebHome/captain-bob.jpg" alt="Painted portrait of Captain Bob at a keyboard with a mug of coffee, wearing a StarshipOS jacket" style="flex: 1 1 260px; width: 100%; max-width: 340px; aspect-ratio: 2 / 3; height: auto; object-fit: cover; border-radius: 6px; display: block">
|
||||
<div style="flex: 999 1 420px; min-width: 0">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0 !important">From the bridge</p>
|
||||
<h2 id="bridge-h" style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: 36px; line-height: 1.15">Built by one engineer, in the open.</h2>
|
||||
<p style="margin: 0 0 24px; color: #C8D1DE !important">StarshipOS is designed and built by Captain Bob — Robert Allan James — drawing on roughly fifty years of embedded-systems work. Development happens in Ashland, Ohio, and in public on starshipos-f18.org.</p>
|
||||
<a href="/bin/view/Inquiries/" style="display: inline-block; padding: 14px 24px; border: 1px solid #34486A !important; color: #EEF2F7 !important; text-decoration: none; border-radius: 4px">Get in touch</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="signup-h" style="border-top: 1px solid #22324D !important; background: #0E182B !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 64px 24px; display: flex; flex-wrap: wrap; gap: 32px; align-items: center; justify-content: space-between">
|
||||
<div style="flex: 1 1 360px; min-width: 0">
|
||||
<h2 id="signup-h" style="margin: 0 0 8px; font-family: 'Exo 2', sans-serif; font-size: 28px">Launch announcements</h2>
|
||||
<p style="margin: 0; color: #A3AEC2 !important; font-size: 14px">Milestones, releases and papers. Low volume. Unsubscribe anytime.</p>
|
||||
</div>
|
||||
<form action="mailto:info@starshipos.com?subject=Subscribe%20to%20launch%20announcements" method="post" enctype="text/plain" style="flex: 1 1 420px; display: flex; flex-wrap: wrap; gap: 12px" aria-label="Subscribe to announcements">
|
||||
<label for="sub-email" style="position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0)">Email address</label>
|
||||
<input id="sub-email" name="email" type="email" required placeholder="you@example.com" style="flex: 1 1 240px; min-height: 48px; padding: 0 16px; background: #0A1222 !important; border: 1px solid #34486A !important; border-radius: 4px; color: #EEF2F7 !important; font-family: inherit; font-size: 15px">
|
||||
<button type="submit" style="min-height: 48px; padding: 0 24px; background: #F5891F !important; color: #0A1222 !important; border: 0 !important; border-radius: 4px; font-family: inherit; font-weight: 700; font-size: 15px; cursor: pointer">Subscribe</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer style="border-top: 1px solid #22324D !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2 !important">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="/bin/view/Inquiries/" style="color: #C8D1DE !important">Inquiries</a><a href="mailto:info@starshipos.com" style="color: #C8D1DE !important">info@starshipos.com</a><a href="https://starshipos-f18.org/" style="color: #C8D1DE !important">starshipos-f18.org</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
{{/html}}
|
||||
@@ -0,0 +1,18 @@
|
||||
# site/com -- the starshipos-f18.com XWiki's pages
|
||||
|
||||
The public face of StarshipOS, made from the "StarshipOS.com" design canvas (claude.ai), whose
|
||||
artboards are copied into `canvas/` as they are: Home (`Main.WebHome`), `Inquiries.WebHome`,
|
||||
`TryIt.WebHome`. `build.py` turns each into one `{{html}}` block (a page author with script rights)
|
||||
and says what changes on the way: the wiki's links and domains, the images as attachments
|
||||
(`badge.jpg`, `captain-bob.jpg`, web-size copies of the canvas's), the real console in Try it, the
|
||||
forms by e-mail. `install.sh` puts them on the wiki and checks a guest can read them:
|
||||
|
||||
```
|
||||
site/com/build.py
|
||||
XWIKI_USER=rajames XWIKI_PASSWORD=... site/com/install.sh
|
||||
```
|
||||
|
||||
Change the design on the canvas, copy the artboard into `canvas/`, and run both again.
|
||||
|
||||
Installed 2026-11-07. Try it is on the wiki but not in the navigation (#117): its console,
|
||||
`try.starshipos-f18.com`, is not served yet (#115).
|
||||
@@ -0,0 +1,128 @@
|
||||
{{velocity}}
|
||||
#if ($isGuest)
|
||||
#[[{{html clean="false"}}<style>
|
||||
#menuview, #hierarchy_breadcrumb, .document-header, #xdocFooter, #footerglobal, #leftPanels, #rightPanels,
|
||||
#leftPanelsToggle, #rightPanelsToggle, .tour, .tour-backdrop, #bootstrap_tour_restart, .xtour-restart,
|
||||
#xwikimaincontainerinner > a.btn { display: none !important; }
|
||||
html, body, #xwikimaincontainer, #xwikimaincontainerinner, #contentcontainer, #contentcolumn, .main,
|
||||
#mainContentArea, #xwikicontent, #mainContentArea .row { background-color: #0A1222 !important; }
|
||||
#contentcontainer, #contentcolumn, .main, #mainContentArea, #xwikicontent, #mainContentArea .row {
|
||||
width: 100% !important; max-width: none !important; margin: 0 !important; padding: 0 !important; border: 0 !important; float: none !important; }
|
||||
#xwikicontent > .ssos { border: 0 !important; }
|
||||
#xwikimaincontainer { padding: 0 !important; }
|
||||
.main hr:not(.ssos hr), #xwikicontent > :not(.ssos) { display: none !important; }
|
||||
</style>{{/html}}]]#
|
||||
#end
|
||||
{{/velocity}}
|
||||
{{html clean="false"}}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
.ssos, .ssos *, .ssos *::before, .ssos *::after { background-color: transparent !important; color: inherit !important; border-color: #22324D !important; }
|
||||
.ssos a, .ssos a * { color: #F5891F !important; }
|
||||
.ssos a:hover { color: #FFB061 !important; }
|
||||
.ssos input, .ssos textarea, .ssos select { background-color: #0A1222 !important; color: #EEF2F7 !important; border-color: #34486A !important; }
|
||||
.ssos ::placeholder { color: #A3AEC2 !important; opacity: 1 !important; }
|
||||
.ssos img { background-color: transparent !important; }
|
||||
</style>
|
||||
<div class="ssos" style="background: #0A1222 !important; color: #EEF2F7 !important; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6; min-height: 0">
|
||||
|
||||
<header style="border-bottom: 1px solid #22324D !important">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="/bin/view/Main/" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7 !important; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: #F5891F !important">OS</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px">
|
||||
<a href="/bin/view/Main/" style="color: #C8D1DE !important; text-decoration: none">Home</a>
|
||||
<a href="/bin/view/TryIt/" aria-current="page" style="color: #EEF2F7 !important; text-decoration: none; border-bottom: 2px solid #F5891F !important">Try it</a>
|
||||
<a href="/bin/view/Inquiries/" style="color: #C8D1DE !important; text-decoration: none">Inquiries</a>
|
||||
<a href="https://starshipos-f18.org/" style="color: #F5891F !important; text-decoration: none">Contributors →</a>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 80px 24px 32px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0 !important">ok> try it</p>
|
||||
<h1 style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: clamp(36px, 5vw, 56px); line-height: 1.1">A StarshipOS machine of your own.</h1>
|
||||
<p style="margin: 0; max-width: 680px; font-size: 18px; color: #C8D1DE !important">Not a recording, not a simulation of StarshipOS: the console below is a real machine, started just for you and already at its prompt. You are Zuse, the superuser — of a machine that exists only for your session. There is nothing to break, and nothing you do is kept.</p>
|
||||
</section>
|
||||
|
||||
<section aria-label="The console" style="max-width: 1120px; margin: 0 auto; padding: 24px 24px 48px">
|
||||
<div style="background: #050A14 !important; border: 1px solid #34486A !important; border-radius: 8px; overflow: hidden">
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 20px; border-bottom: 1px solid #22324D !important; background: #0E182B !important; font-size: 13px; color: #A3AEC2 !important">
|
||||
<span style="display: flex; align-items: center; gap: 10px"><span aria-hidden="true" style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: #4FD1B0 !important"></span>StarshipOS · amd64 · your session</span>
|
||||
<span>try.starshipos-f18.com</span>
|
||||
</div>
|
||||
<iframe src="https://try.starshipos-f18.com/" title="StarshipOS console" style="display: block; width: 100%; height: 30em; border: 0 !important; background: #050A14 !important"></iframe>
|
||||
</div>
|
||||
<p style="margin: 12px 0 0; font-size: 13px; color: #A3AEC2 !important">If the console does not connect, every machine is in use: try again in a few minutes.</p>
|
||||
</section>
|
||||
|
||||
<section aria-label="Your machine" style="border-top: 1px solid #22324D !important; border-bottom: 1px solid #22324D !important; background: #0E182B !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 24px">
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">Zuse</div><div style="font-size: 14px; color: #A3AEC2 !important">the superuser, of this machine only</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">amd64</div><div style="font-size: 14px; color: #A3AEC2 !important">LithosAnanke v2.1.0 · StarForth v4</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">30 min</div><div style="font-size: 14px; color: #A3AEC2 !important">then it is gone; reload for a new one</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">Offline</div><div style="font-size: 14px; color: #A3AEC2 !important">no network inside the machine</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="try-h" style="max-width: 1120px; margin: 0 auto; padding: 96px 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">Things to try</p>
|
||||
<h2 id="try-h" style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: 40px; line-height: 1.15; max-width: 760px">StarshipOS speaks FORTH.</h2>
|
||||
<p style="margin: 0 0 40px; max-width: 680px; color: #C8D1DE !important">Type a line and press Enter. When the machine has done it, it answers ok.</p>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px">
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2 !important">You type</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #EEF2F7 !important">3 4 + .</p>
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2 !important">It answers</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #F5891F !important">7 ok</p>
|
||||
<p style="margin: 0; font-size: 14px; color: #C8D1DE !important">Numbers go on a stack; + adds the top two; . prints the result.</p>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2 !important">You type</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #EEF2F7 !important">: SQUARE DUP * ;</p>
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2 !important">It answers</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #F5891F !important">ok</p>
|
||||
<p style="margin: 0; font-size: 14px; color: #C8D1DE !important">You have just taught the machine a new word, SQUARE.</p>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2 !important">You type</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #EEF2F7 !important">7 SQUARE .</p>
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2 !important">It answers</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #F5891F !important">49 ok</p>
|
||||
<p style="margin: 0; font-size: 14px; color: #C8D1DE !important">…and used it, as if it had always been there.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 32px; border-top: 1px solid #22324D !important; padding-top: 48px">
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7 !important">A machine of your own</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2 !important">Resumed at its prompt from one that booted, passed its 538 power-on self-tests and logged Zuse in — so you never wait for a boot.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7 !important">The latest green build</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2 !important">Always the most recent build that booted on amd64, aarch64 and riscv64 and passed every acceptance check.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7 !important">A Zuse of its own</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2 !important">Zuse is whoever holds the identity drive. Here it is a demo Zuse minted for this page alone — not anyone's real identity.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7 !important">Gone when you go</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2 !important">Close the page, or let 30 minutes pass, and the machine is stopped and discarded. The next visitor starts clean.</p></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px 96px">
|
||||
<div style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 40px; display: flex; flex-wrap: wrap; gap: 40px; align-items: center">
|
||||
<div style="flex: 999 1 480px; min-width: 0">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">A small server</p>
|
||||
<h2 style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: 32px; line-height: 1.2">Emulated, so a little slower.</h2>
|
||||
<p style="margin: 0; color: #C8D1DE !important">The demo runs in an emulator on a modest server: slower than StarshipOS on real hardware, and only a few machines at once. The real thing boots straight from firmware, with nothing beneath it.</p>
|
||||
</div>
|
||||
<div style="flex: 1 1 220px; display: flex; flex-direction: column; gap: 12px">
|
||||
<a href="/bin/view/Main/" style="display: inline-block; padding: 14px 20px; background: #F5891F !important; color: #0A1222 !important; font-weight: 700; text-decoration: none; border-radius: 4px; text-align: center">How it works</a>
|
||||
<a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke" style="display: inline-block; padding: 14px 20px; border: 1px solid #34486A !important; color: #EEF2F7 !important; text-decoration: none; border-radius: 4px; text-align: center">Read the source</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer style="border-top: 1px solid #22324D !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2 !important">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="/bin/view/Main/" style="color: #C8D1DE !important">Home</a><a href="/bin/view/Inquiries/" style="color: #C8D1DE !important">Inquiries</a><a href="https://starshipos-f18.org/" style="color: #C8D1DE !important">starshipos-f18.org</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
{{/html}}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
Executable
+103
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""build.py -- the starshipos-f18.com XWiki pages, made from the "StarshipOS.com" design canvas.
|
||||
|
||||
site/com/build.py canvas/{Main,Inquiries,TryIt}.dc.html -> {Main,Inquiries,TryIt}.WebHome.xwiki
|
||||
|
||||
The canvas is the source: its artboards are copied into canvas/ as they are, and this turns each into
|
||||
one {{html}} block (which needs a page author with script rights). What changes on the way:
|
||||
|
||||
- the accent hole becomes its default colour, and the canvas's links become the wiki's pages
|
||||
(Main.dc.html -> /bin/view/Main/, ...) and the real domains (starshipos.org -> starshipos-f18.org);
|
||||
- the two images become attachments of Main.WebHome (badge.jpg, captain-bob.jpg -- web-size copies
|
||||
of the canvas's uploads);
|
||||
- Try it: the drawn console becomes the real one, an iframe of try.starshipos-f18.com;
|
||||
- the inquiry form posts to the .org's PublicInquiry, which files it under Inquiries there
|
||||
(admin-only, site/org/inquiries); the announcements form, which has no server, sends by e-mail;
|
||||
- a link the canvas left as a placeholder ([SSRN PAPER URL]) points at the .org until it is given.
|
||||
|
||||
install.sh puts the pages and the images on the wiki.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
||||
import colorlock # noqa: E402 the design's colours over the wiki's high-contrast theme
|
||||
|
||||
ACCENT = "#F5891F"
|
||||
FONTS = ('<link rel="preconnect" href="https://fonts.googleapis.com">\n'
|
||||
'<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700'
|
||||
'&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">')
|
||||
ORG = "https://starshipos-f18.org/"
|
||||
PAGES = ["Main", "Inquiries", "TryIt"]
|
||||
IMAGES = {"/_blob/5b564d54d98e02ad600c913a9a1888f2": "badge.jpg",
|
||||
"/_blob/5483451f292782a8b366e437181c4bcf": "captain-bob.jpg"}
|
||||
|
||||
CONSOLE = '''<div style="background: #050A14; border: 1px solid #34486A; border-radius: 8px; overflow: hidden">
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 20px; border-bottom: 1px solid #22324D; background: #0E182B; font-size: 13px; color: #A3AEC2">
|
||||
<span style="display: flex; align-items: center; gap: 10px"><span aria-hidden="true" style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: #4FD1B0"></span>StarshipOS · amd64 · your session</span>
|
||||
<span>try.starshipos-f18.com</span>
|
||||
</div>
|
||||
<iframe src="https://try.starshipos-f18.com/" title="StarshipOS console" style="display: block; width: 100%; height: 30em; border: 0; background: #050A14"></iframe>
|
||||
</div>
|
||||
<p style="margin: 12px 0 0; font-size: 13px; color: #A3AEC2">If the console does not connect, every machine is in use: try again in a few minutes.</p>'''
|
||||
|
||||
|
||||
def body(src):
|
||||
m = re.search(r"<x-dc>(.*)</x-dc>", src, re.S)
|
||||
html = re.sub(r"<helmet>.*?</helmet>", "", m.group(1), flags=re.S).strip()
|
||||
html = html.replace("{{accent}}", ACCENT)
|
||||
for p in PAGES:
|
||||
html = html.replace('href="%s.dc.html"' % p, 'href="/bin/view/%s/"' % p)
|
||||
html = html.replace('href="https://starshipos.org"', 'href="%s"' % ORG)
|
||||
html = html.replace(">starshipos.org</a>", ">starshipos-f18.org</a>")
|
||||
html = html.replace("on starshipos.org.", "on starshipos-f18.org.")
|
||||
html = html.replace('href="[SSRN PAPER URL]"', 'href="%s"' % ORG)
|
||||
for blob, name in IMAGES.items():
|
||||
html = html.replace('src="%s"' % blob, 'src="/bin/download/Main/WebHome/%s"' % name)
|
||||
html = html.replace("min-height: 100vh", "min-height: 0") # inside the wiki's page, not a screen
|
||||
return html
|
||||
|
||||
|
||||
def try_it(html):
|
||||
start = html.index('<div style="background: #050A14')
|
||||
end = html.index("</p>", html.index("[LIVE CONSOLE]")) + len("</p>")
|
||||
return html[:start] + CONSOLE + html[end:]
|
||||
|
||||
|
||||
def forms(html, page):
|
||||
if page == "Main":
|
||||
html = html.replace('<form style="flex: 1 1 420px; display: flex; flex-wrap: wrap; gap: 12px" aria-label="Subscribe to announcements">',
|
||||
'<form action="mailto:info@starshipos.com?subject=Subscribe%20to%20launch%20announcements" method="post" enctype="text/plain" style="flex: 1 1 420px; display: flex; flex-wrap: wrap; gap: 12px" aria-label="Subscribe to announcements">')
|
||||
html = html.replace('<input id="sub-email" type="email"', '<input id="sub-email" name="email" type="email" required')
|
||||
html = html.replace('<button type="button" style="min-height: 48px; padding: 0 24px',
|
||||
'<button type="submit" style="min-height: 48px; padding: 0 24px')
|
||||
if page == "Inquiries":
|
||||
html = html.replace('<form aria-label="Inquiry form"',
|
||||
'<form action="https://starshipos-f18.org/bin/view/PublicInquiry/" method="post" aria-label="Inquiry form"')
|
||||
# a field people cannot see; a robot fills it, and PublicInquiry keeps nothing it sends
|
||||
html = html.replace('<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px">',
|
||||
'<div aria-hidden="true" style="position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden">'
|
||||
'<label for="q-website">Leave this empty</label><input id="q-website" name="website" type="text" tabindex="-1" autocomplete="off"></div>\n'
|
||||
'<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px">', 1)
|
||||
for i, n in (("q-name", "name"), ("q-email", "email"), ("q-org", "organization"), ("q-topic", "topic"),
|
||||
("q-msg", "message"), ("q-list", "announcements")):
|
||||
html = html.replace('id="%s"' % i, 'id="%s" name="%s"' % (i, n), 1)
|
||||
html = html.replace('<button type="button" style="min-height: 48px; padding: 0 28px',
|
||||
'<button type="submit" style="min-height: 48px; padding: 0 28px')
|
||||
html = html.replace("Replies usually within a few days.",
|
||||
"Replies usually within a few days.")
|
||||
return html
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
for p in PAGES:
|
||||
html = forms(body(open("canvas/%s.dc.html" % p).read()), p)
|
||||
if p == "TryIt":
|
||||
html = try_it(html)
|
||||
html = colorlock.lock(html, '<div style="background: #0A1222')
|
||||
assert "{{" not in html.replace(colorlock.STYLE, "") and "[SSRN" not in html and ".dc.html" not in html and "_blob" not in html, p
|
||||
with open("%s.WebHome.xwiki" % p, "w") as f:
|
||||
f.write(colorlock.GUEST_CHROME + '{{html clean="false"}}\n%s\n%s\n{{/html}}\n' % (FONTS, html))
|
||||
print("wrote", ", ".join("%s.WebHome.xwiki" % p for p in PAGES))
|
||||
@@ -0,0 +1,118 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>StarshipOS — Inquiries</title>
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body{margin:0;background:#0A1222}
|
||||
a{color:#F5891F}a:hover{color:#FFB061}
|
||||
</style>
|
||||
</helmet>
|
||||
<div style="background: #0A1222; color: #EEF2F7; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6; min-height: 100vh">
|
||||
|
||||
<header style="border-bottom: 1px solid #22324D">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="Main.dc.html" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: {{accent}}">OS</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px">
|
||||
<a href="Main.dc.html" style="color: #C8D1DE; text-decoration: none">Home</a>
|
||||
<a href="Inquiries.dc.html" aria-current="page" style="color: #EEF2F7; text-decoration: none; border-bottom: 2px solid {{accent}}">Inquiries</a>
|
||||
<a href="https://starshipos.org" style="color: {{accent}}; text-decoration: none">Contributors →</a>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 80px 24px 32px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: {{accent}}">Inquiries</p>
|
||||
<h1 style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: clamp(36px, 5vw, 56px); line-height: 1.1">Talk to the bridge.</h1>
|
||||
<p style="margin: 0; max-width: 640px; font-size: 18px; color: #C8D1DE">Licensing, research collaboration, press or plain curiosity — every message is read by a human. Want to contribute code? Head to <a href="https://starshipos.org">starshipos.org</a>.</p>
|
||||
</section>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 32px 24px 96px; display: flex; flex-wrap: wrap; gap: 48px; align-items: flex-start">
|
||||
|
||||
<form aria-label="Inquiry form" style="flex: 999 1 520px; min-width: 0; background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 32px; display: flex; flex-direction: column; gap: 20px">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px">
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-name" style="font-size: 14px; color: #C8D1DE">Name</label>
|
||||
<input id="q-name" type="text" autocomplete="name" style="min-height: 48px; padding: 0 14px; background: #0A1222; border: 1px solid #34486A; border-radius: 4px; color: #EEF2F7; font-family: inherit; font-size: 15px">
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-email" style="font-size: 14px; color: #C8D1DE">Email</label>
|
||||
<input id="q-email" type="email" autocomplete="email" style="min-height: 48px; padding: 0 14px; background: #0A1222; border: 1px solid #34486A; border-radius: 4px; color: #EEF2F7; font-family: inherit; font-size: 15px">
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-org" style="font-size: 14px; color: #C8D1DE">Organization <span style="color: #A3AEC2">(optional)</span></label>
|
||||
<input id="q-org" type="text" autocomplete="organization" style="min-height: 48px; padding: 0 14px; background: #0A1222; border: 1px solid #34486A; border-radius: 4px; color: #EEF2F7; font-family: inherit; font-size: 15px">
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-topic" style="font-size: 14px; color: #C8D1DE">Topic</label>
|
||||
<select id="q-topic" style="min-height: 48px; padding: 0 14px; background: #0A1222; border: 1px solid #34486A; border-radius: 4px; color: #EEF2F7; font-family: inherit; font-size: 15px">
|
||||
<option>General question</option>
|
||||
<option>Licensing</option>
|
||||
<option>Research collaboration</option>
|
||||
<option>Hardware / FPGA</option>
|
||||
<option>Press & media</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<label for="q-msg" style="font-size: 14px; color: #C8D1DE">Message</label>
|
||||
<textarea id="q-msg" rows="7" style="padding: 12px 14px; background: #0A1222; border: 1px solid #34486A; border-radius: 4px; color: #EEF2F7; font-family: inherit; font-size: 15px; resize: vertical"></textarea>
|
||||
</div>
|
||||
<div style="display: flex; align-items: flex-start; gap: 12px">
|
||||
<input id="q-list" type="checkbox" style="width: 20px; height: 20px; margin: 3px 0 0; accent-color: {{accent}}">
|
||||
<label for="q-list" style="font-size: 14px; color: #C8D1DE">Also add me to launch announcements (low volume, unsubscribe anytime).</label>
|
||||
</div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; gap: 16px">
|
||||
<button type="button" style="min-height: 48px; padding: 0 28px; background: {{accent}}; color: #0A1222; border: 0; border-radius: 4px; font-family: inherit; font-weight: 700; font-size: 15px; cursor: pointer">Send inquiry</button>
|
||||
<span style="font-size: 13px; color: #A3AEC2">Replies usually within a few days.</span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<aside aria-label="Direct addresses" style="flex: 1 1 300px; display: flex; flex-direction: column; gap: 24px">
|
||||
<h2 style="margin: 0; font-family: 'Exo 2', sans-serif; font-size: 24px">Or write directly</h2>
|
||||
<div style="border-top: 1px solid #22324D; padding-top: 16px">
|
||||
<div style="font-size: 13px; color: #A3AEC2">General</div>
|
||||
<a href="mailto:info@starshipos.com" style="font-size: 16px">info@starshipos.com</a>
|
||||
</div>
|
||||
<div style="border-top: 1px solid #22324D; padding-top: 16px">
|
||||
<div style="font-size: 13px; color: #A3AEC2">Licensing & partnerships</div>
|
||||
<a href="mailto:licensing@starshipos.com" style="font-size: 16px">licensing@starshipos.com</a>
|
||||
</div>
|
||||
<div style="border-top: 1px solid #22324D; padding-top: 16px">
|
||||
<div style="font-size: 13px; color: #A3AEC2">Press & media</div>
|
||||
<a href="mailto:press@starshipos.com" style="font-size: 16px">press@starshipos.com</a>
|
||||
</div>
|
||||
<div style="border-top: 1px solid #22324D; padding-top: 16px">
|
||||
<div style="font-size: 13px; color: #A3AEC2">Security reports</div>
|
||||
<a href="mailto:security@starshipos.org" style="font-size: 16px">security@starshipos.org</a>
|
||||
</div>
|
||||
<p style="margin: 0; padding-top: 16px; border-top: 1px solid #22324D; font-size: 13px; color: #A3AEC2">StarshipOS is developed in Ashland, Ohio.</p>
|
||||
</aside>
|
||||
|
||||
</section>
|
||||
|
||||
<footer style="border-top: 1px solid #22324D">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="Main.dc.html" style="color: #C8D1DE">Home</a><a href="https://starshipos.org" style="color: #C8D1DE">starshipos.org</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props='{"accent":{"editor":"color","default":"#F5891F","options":["#F5891F","#5FD3C4","#8FB8FF"]},"$preview":{"width":1280,"height":1700}}'>
|
||||
class Component extends DCLogic {
|
||||
renderVals() {
|
||||
return { accent: this.props.accent ?? '#F5891F' };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,151 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>StarshipOS — Home</title>
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body{margin:0;background:#0A1222}
|
||||
a{color:#F5891F}a:hover{color:#FFB061}
|
||||
</style>
|
||||
</helmet>
|
||||
<div style="background: #0A1222; color: #EEF2F7; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6; min-height: 100vh">
|
||||
|
||||
<header style="border-bottom: 1px solid #22324D">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="Main.dc.html" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: {{accent}}">OS</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px">
|
||||
<a href="#system" style="color: #C8D1DE; text-decoration: none">System</a>
|
||||
<a href="#research" style="color: #C8D1DE; text-decoration: none">Research</a>
|
||||
<a href="#silicon" style="color: #C8D1DE; text-decoration: none">Silicon</a>
|
||||
<a href="Inquiries.dc.html" style="color: #C8D1DE; text-decoration: none">Inquiries</a>
|
||||
<a href="https://starshipos.org" style="color: {{accent}}; text-decoration: none">Contributors →</a>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 96px 24px 72px; display: flex; flex-wrap: wrap; align-items: center; gap: 56px">
|
||||
<div style="flex: 999 1 520px; min-width: 0">
|
||||
<p style="margin: 0 0 20px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0">ok> bare metal · FORTH · C99</p>
|
||||
<h1 style="margin: 0 0 24px; font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: clamp(40px, 6vw, 68px); line-height: 1.05; letter-spacing: -0.01em">An operating system that obeys a conservation law.</h1>
|
||||
<p style="margin: 0 0 36px; max-width: 620px; font-size: 18px; color: #C8D1DE">StarshipOS is a bare-metal operating system built from the ground up in StarForth and C99. One compudynamic engine governs every word, message, block and virtual machine — and holds K≡1.0 on every architecture it runs on.</p>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 16px">
|
||||
<a href="#system" style="display: inline-block; padding: 14px 24px; background: {{accent}}; color: #0A1222; font-weight: 700; text-decoration: none; border-radius: 4px">See how it works</a>
|
||||
<a href="Inquiries.dc.html" style="display: inline-block; padding: 14px 24px; border: 1px solid #34486A; color: #EEF2F7; text-decoration: none; border-radius: 4px">Make an inquiry</a>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex: 1 1 400px; display: flex; justify-content: center">
|
||||
<img src="/_blob/5b564d54d98e02ad600c913a9a1888f2" alt="StarshipOS badge: Santino the mascot inside a ring on a starfield" style="width: 100%; max-width: 540px; height: auto; display: block; border-radius: 8px; border: 1px solid #22324D">
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-label="At a glance" style="border-top: 1px solid #22324D; border-bottom: 1px solid #22324D; background: #0E182B">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 24px">
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: {{accent}}">38,400+</div><div style="font-size: 14px; color: #A3AEC2">experimental runs validating K≡1.0</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: {{accent}}">3 ISAs</div><div style="font-size: 14px; color: #A3AEC2">amd64 · aarch64 · riscv64</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: {{accent}}">FORTH-79</div><div style="font-size: 14px; color: #A3AEC2">compliant core, live at the ok> prompt</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: {{accent}}">Patent pending</div><div style="font-size: 14px; color: #A3AEC2">LithosAnanke kernel architecture</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="system" style="max-width: 1120px; margin: 0 auto; padding: 96px 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: {{accent}}">The system</p>
|
||||
<h2 style="margin: 0 0 48px; font-family: 'Exo 2', sans-serif; font-size: 40px; line-height: 1.15; max-width: 760px">One engine. One fabric. Everything in it obeys the same physics.</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px">
|
||||
<article style="background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 24px">StarForth</h3>
|
||||
<p style="margin: 0 0 16px; font-size: 13px; color: {{accent}}">the language and the VM</p>
|
||||
<p style="margin: 0; color: #C8D1DE">A FORTH-79 compliant adaptive virtual machine written in C99. Words execute by heat: what the system uses, it keeps close. Everything a user touches is StarForth — there is no compiler inside the box.</p>
|
||||
</article>
|
||||
<article style="background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 24px">LithosAnanke</h3>
|
||||
<p style="margin: 0 0 16px; font-size: 13px; color: {{accent}}">the microkernel</p>
|
||||
<p style="margin: 0; color: #C8D1DE">A bare-metal microkernel built around the Stadium — a single fabric where words, messages, blocks and VMs live side by side, all governed by one compudynamic engine.</p>
|
||||
</article>
|
||||
<article style="background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 24px">The fleet</h3>
|
||||
<p style="margin: 0 0 16px; font-size: 13px; color: {{accent}}">VMs that are born, not spawned</p>
|
||||
<p style="margin: 0; color: #C8D1DE">Hera births and governs the fleet. Artemis keeps the blocks. Console draws a vector framebuffer. Hermes, in the kernel, carries every message — and every message is checked against its ACL.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 32px; border-top: 1px solid #22324D; padding-top: 48px">
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7">Phenomenon first</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2">Observe the behaviour, then write the mathematics. Document before code.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7">Parity first</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2">The same machine on every ISA, proven by reproducible dictionary hashes.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7">Identity on a key</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2">Your certificate lives on a thumb drive. No key, no session.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7">Minimal by design</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2">A small core of primitives; everything else composed in FORTH.</p></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="research" style="max-width: 1120px; margin: 0 auto; padding: 72px 24px">
|
||||
<div style="background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 40px; display: flex; flex-wrap: wrap; gap: 40px; align-items: center">
|
||||
<div style="flex: 999 1 480px; min-width: 0">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: {{accent}}">Research</p>
|
||||
<h2 style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: 32px; line-height: 1.2">James Law: K≡1.0</h2>
|
||||
<p style="margin: 0; color: #C8D1DE">A conservation invariant that holds regardless of instruction set. Validated across 38,400+ runs in 128 configurations under QEMU on amd64, aarch64 and riscv64, and published on SSRN.</p>
|
||||
</div>
|
||||
<div style="flex: 1 1 220px; display: flex; flex-direction: column; gap: 12px">
|
||||
<a href="[SSRN PAPER URL]" style="display: inline-block; padding: 14px 20px; background: {{accent}}; color: #0A1222; font-weight: 700; text-decoration: none; border-radius: 4px; text-align: center">Read the paper</a>
|
||||
<a href="https://starshipos.org" style="display: inline-block; padding: 14px 20px; border: 1px solid #34486A; color: #EEF2F7; text-decoration: none; border-radius: 4px; text-align: center">Design docs on the .org</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="silicon" style="max-width: 1120px; margin: 0 auto; padding: 48px 24px 96px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: {{accent}}">Next: silicon</p>
|
||||
<h2 style="margin: 0 0 20px; font-family: 'Exo 2', sans-serif; font-size: 40px; line-height: 1.15; max-width: 760px">From virtual machine to fabric.</h2>
|
||||
<p style="margin: 0; max-width: 720px; color: #C8D1DE">StarForth V4 is being brought up as a mesh of tiny stack-machine cores on FPGA — words as instructions, messaging in hardware, and the compudynamic engine steering what runs and when. Same machine, same parity, now in logic.</p>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="bridge-h" style="max-width: 1120px; margin: 0 auto; padding: 0 24px 96px">
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 48px; align-items: center; background: #111C30; border: 1px solid #22324D; border-radius: 8px; padding: 32px">
|
||||
<img src="/_blob/5483451f292782a8b366e437181c4bcf" alt="Painted portrait of Captain Bob at a keyboard with a mug of coffee, wearing a StarshipOS jacket" style="flex: 1 1 260px; width: 100%; max-width: 340px; aspect-ratio: 2 / 3; height: auto; object-fit: cover; border-radius: 6px; display: block">
|
||||
<div style="flex: 999 1 420px; min-width: 0">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0">From the bridge</p>
|
||||
<h2 id="bridge-h" style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: 36px; line-height: 1.15">Built by one engineer, in the open.</h2>
|
||||
<p style="margin: 0 0 24px; color: #C8D1DE">StarshipOS is designed and built by Captain Bob — Robert Allan James — drawing on roughly fifty years of embedded-systems work. Development happens in Ashland, Ohio, and in public on starshipos.org.</p>
|
||||
<a href="Inquiries.dc.html" style="display: inline-block; padding: 14px 24px; border: 1px solid #34486A; color: #EEF2F7; text-decoration: none; border-radius: 4px">Get in touch</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="signup-h" style="border-top: 1px solid #22324D; background: #0E182B">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 64px 24px; display: flex; flex-wrap: wrap; gap: 32px; align-items: center; justify-content: space-between">
|
||||
<div style="flex: 1 1 360px; min-width: 0">
|
||||
<h2 id="signup-h" style="margin: 0 0 8px; font-family: 'Exo 2', sans-serif; font-size: 28px">Launch announcements</h2>
|
||||
<p style="margin: 0; color: #A3AEC2; font-size: 14px">Milestones, releases and papers. Low volume. Unsubscribe anytime.</p>
|
||||
</div>
|
||||
<form style="flex: 1 1 420px; display: flex; flex-wrap: wrap; gap: 12px" aria-label="Subscribe to announcements">
|
||||
<label for="sub-email" style="position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0)">Email address</label>
|
||||
<input id="sub-email" type="email" placeholder="you@example.com" style="flex: 1 1 240px; min-height: 48px; padding: 0 16px; background: #0A1222; border: 1px solid #34486A; border-radius: 4px; color: #EEF2F7; font-family: inherit; font-size: 15px">
|
||||
<button type="button" style="min-height: 48px; padding: 0 24px; background: {{accent}}; color: #0A1222; border: 0; border-radius: 4px; font-family: inherit; font-weight: 700; font-size: 15px; cursor: pointer">Subscribe</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer style="border-top: 1px solid #22324D">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="Inquiries.dc.html" style="color: #C8D1DE">Inquiries</a><a href="mailto:info@starshipos.com" style="color: #C8D1DE">info@starshipos.com</a><a href="https://starshipos.org" style="color: #C8D1DE">starshipos.org</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props='{"accent":{"editor":"color","default":"#F5891F","options":["#F5891F","#5FD3C4","#8FB8FF"]},"$preview":{"width":1280,"height":3700}}'>
|
||||
class Component extends DCLogic {
|
||||
renderVals() {
|
||||
return { accent: this.props.accent ?? '#F5891F' };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,136 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>StarshipOS — Try it</title>
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body{margin:0;background:#0A1222}
|
||||
a{color:#F5891F}a:hover{color:#FFB061}
|
||||
</style>
|
||||
</helmet>
|
||||
<div style="background: #0A1222; color: #EEF2F7; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6; min-height: 100vh">
|
||||
|
||||
<header style="border-bottom: 1px solid #22324D">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="Main.dc.html" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: {{accent}}">OS</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px">
|
||||
<a href="Main.dc.html" style="color: #C8D1DE; text-decoration: none">Home</a>
|
||||
<a href="TryIt.dc.html" aria-current="page" style="color: #EEF2F7; text-decoration: none; border-bottom: 2px solid {{accent}}">Try it</a>
|
||||
<a href="Inquiries.dc.html" style="color: #C8D1DE; text-decoration: none">Inquiries</a>
|
||||
<a href="https://starshipos.org" style="color: {{accent}}; text-decoration: none">Contributors →</a>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 80px 24px 32px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0">ok> try it</p>
|
||||
<h1 style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: clamp(36px, 5vw, 56px); line-height: 1.1">A StarshipOS machine of your own.</h1>
|
||||
<p style="margin: 0; max-width: 680px; font-size: 18px; color: #C8D1DE">Not a recording, not a simulation of StarshipOS: the console below is a real machine, started just for you and already at its prompt. You are Zuse, the superuser — of a machine that exists only for your session. There is nothing to break, and nothing you do is kept.</p>
|
||||
</section>
|
||||
|
||||
<section aria-label="The console" style="max-width: 1120px; margin: 0 auto; padding: 24px 24px 48px">
|
||||
<div style="background: #050A14; border: 1px solid #34486A; border-radius: 8px; overflow: hidden">
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 20px; border-bottom: 1px solid #22324D; background: #0E182B; font-size: 13px; color: #A3AEC2">
|
||||
<span style="display: flex; align-items: center; gap: 10px"><span aria-hidden="true" style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: #4FD1B0"></span>StarshipOS · amd64 · your session</span>
|
||||
<span>try.starshipos-f18.com</span>
|
||||
</div>
|
||||
<div style="padding: 24px; min-height: 360px; font-size: 15px; line-height: 1.7; color: #EEF2F7; overflow-x: auto">
|
||||
<div style="color: #A3AEC2">StarshipOS -- starting a throwaway machine, yours for up to 30 minutes. Nothing you do is kept.</div>
|
||||
<div style="color: #A3AEC2">Try: 3 4 + . : SQUARE DUP * ; 7 SQUARE .</div>
|
||||
<div style="color: #A3AEC2; margin-bottom: 12px">Ready -- type a line and press Enter.</div>
|
||||
<div><span style="color: #FFA500">[zuse@Hera]</span> <span style="color: #55FFFF">ok></span> 3 4 + .</div>
|
||||
<div><span style="color: #FFA500">[zuse@Hera]</span> 7 ok</div>
|
||||
<div><span style="color: #FFA500">[zuse@Hera]</span> <span style="color: #55FFFF">ok></span> : SQUARE DUP * ; 7 SQUARE .</div>
|
||||
<div><span style="color: #FFA500">[zuse@Hera]</span> 49 ok</div>
|
||||
<div><span style="color: #FFA500">[zuse@Hera]</span> <span style="color: #55FFFF">ok></span> <span aria-hidden="true" style="display: inline-block; width: 9px; height: 18px; vertical-align: text-bottom; background: #EEF2F7"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<p style="margin: 12px 0 0; font-size: 13px; color: #A3AEC2">[LIVE CONSOLE] On the site this panel is the machine itself — the console of try.starshipos-f18.com, embedded. If it does not connect, every machine is in use; try again in a few minutes.</p>
|
||||
</section>
|
||||
|
||||
<section aria-label="Your machine" style="border-top: 1px solid #22324D; border-bottom: 1px solid #22324D; background: #0E182B">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 24px">
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: {{accent}}">Zuse</div><div style="font-size: 14px; color: #A3AEC2">the superuser, of this machine only</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: {{accent}}">amd64</div><div style="font-size: 14px; color: #A3AEC2">LithosAnanke v2.1.0 · StarForth v4</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: {{accent}}">30 min</div><div style="font-size: 14px; color: #A3AEC2">then it is gone; reload for a new one</div></div>
|
||||
<div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: {{accent}}">Offline</div><div style="font-size: 14px; color: #A3AEC2">no network inside the machine</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="try-h" style="max-width: 1120px; margin: 0 auto; padding: 96px 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: {{accent}}">Things to try</p>
|
||||
<h2 id="try-h" style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: 40px; line-height: 1.15; max-width: 760px">StarshipOS speaks FORTH.</h2>
|
||||
<p style="margin: 0 0 40px; max-width: 680px; color: #C8D1DE">Type a line and press Enter. When the machine has done it, it answers ok.</p>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px">
|
||||
<article style="background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 28px">
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2">You type</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #EEF2F7">3 4 + .</p>
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2">It answers</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: {{accent}}">7 ok</p>
|
||||
<p style="margin: 0; font-size: 14px; color: #C8D1DE">Numbers go on a stack; + adds the top two; . prints the result.</p>
|
||||
</article>
|
||||
<article style="background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 28px">
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2">You type</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #EEF2F7">: SQUARE DUP * ;</p>
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2">It answers</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: {{accent}}">ok</p>
|
||||
<p style="margin: 0; font-size: 14px; color: #C8D1DE">You have just taught the machine a new word, SQUARE.</p>
|
||||
</article>
|
||||
<article style="background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 28px">
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2">You type</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: #EEF2F7">7 SQUARE .</p>
|
||||
<p style="margin: 0 0 4px; font-size: 13px; color: #A3AEC2">It answers</p>
|
||||
<p style="margin: 0 0 16px; font-size: 20px; color: {{accent}}">49 ok</p>
|
||||
<p style="margin: 0; font-size: 14px; color: #C8D1DE">…and used it, as if it had always been there.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 32px; border-top: 1px solid #22324D; padding-top: 48px">
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7">A machine of your own</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2">Resumed at its prompt from one that booted, passed its 538 power-on self-tests and logged Zuse in — so you never wait for a boot.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7">The latest green build</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2">Always the most recent build that booted on amd64, aarch64 and riscv64 and passed every acceptance check.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7">A Zuse of its own</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2">Zuse is whoever holds the identity drive. Here it is a demo Zuse minted for this page alone — not anyone's real identity.</p></div>
|
||||
<div><h3 style="margin: 0 0 8px; font-size: 16px; color: #EEF2F7">Gone when you go</h3><p style="margin: 0; font-size: 14px; color: #A3AEC2">Close the page, or let 30 minutes pass, and the machine is stopped and discarded. The next visitor starts clean.</p></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px 96px">
|
||||
<div style="background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 40px; display: flex; flex-wrap: wrap; gap: 40px; align-items: center">
|
||||
<div style="flex: 999 1 480px; min-width: 0">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: {{accent}}">A small server</p>
|
||||
<h2 style="margin: 0 0 16px; font-family: 'Exo 2', sans-serif; font-size: 32px; line-height: 1.2">Emulated, so a little slower.</h2>
|
||||
<p style="margin: 0; color: #C8D1DE">The demo runs in an emulator on a modest server: slower than StarshipOS on real hardware, and only a few machines at once. The real thing boots straight from firmware, with nothing beneath it.</p>
|
||||
</div>
|
||||
<div style="flex: 1 1 220px; display: flex; flex-direction: column; gap: 12px">
|
||||
<a href="Main.dc.html" style="display: inline-block; padding: 14px 20px; background: {{accent}}; color: #0A1222; font-weight: 700; text-decoration: none; border-radius: 4px; text-align: center">How it works</a>
|
||||
<a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke" style="display: inline-block; padding: 14px 20px; border: 1px solid #34486A; color: #EEF2F7; text-decoration: none; border-radius: 4px; text-align: center">Read the source</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer style="border-top: 1px solid #22324D">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="Main.dc.html" style="color: #C8D1DE">Home</a><a href="Inquiries.dc.html" style="color: #C8D1DE">Inquiries</a><a href="https://starshipos.org" style="color: #C8D1DE">starshipos.org</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props='{"accent":{"editor":"color","default":"#F5891F","options":["#F5891F","#5FD3C4","#8FB8FF"]},"$preview":{"width":1280,"height":2900}}'>
|
||||
class Component extends DCLogic {
|
||||
renderVals() {
|
||||
return { accent: this.props.accent ?? '#F5891F' };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 96 KiB |
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
# install.sh -- the starshipos-f18.com XWiki's pages, from the "StarshipOS.com" design canvas
|
||||
# (build.py makes them): Main.WebHome (Home), Inquiries.WebHome, TryIt.WebHome, and the two
|
||||
# images, attachments of Main.WebHome. All readable by everyone; the wiki's own rights decide the
|
||||
# rest. Through XWiki's REST API:
|
||||
#
|
||||
# XWIKI_USER=rajames XWIKI_PASSWORD=... site/com/install.sh [https://starshipos-f18.com]
|
||||
#
|
||||
# Run it again after build.py: pages and images are replaced. It ends by checking, without
|
||||
# logging in, that every page and image is there.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
base=${1:-https://starshipos-f18.com}
|
||||
rest="$base/rest/wikis/xwiki"
|
||||
user=${XWIKI_USER:?set XWIKI_USER}
|
||||
pass=${XWIKI_PASSWORD:?set XWIKI_PASSWORD}
|
||||
auth=(-u "$user:$pass")
|
||||
|
||||
page() { # page <space> <title> <file>: create or replace <space>.WebHome
|
||||
local body
|
||||
body=$(python3 -c '
|
||||
import sys
|
||||
from xml.sax.saxutils import escape
|
||||
print("<page xmlns=\"http://www.xwiki.org\"><title>%s</title><syntax>xwiki/2.1</syntax>"
|
||||
"<content>%s</content></page>" % (escape(sys.argv[1]), escape(open(sys.argv[2]).read())))' "$2" "$3")
|
||||
curl -fsS -o /dev/null -w " page $1.WebHome: %{http_code}\n" "${auth[@]}" -X PUT \
|
||||
-H 'Content-Type: application/xml' --data-binary "$body" "$rest/spaces/$1/pages/WebHome"
|
||||
}
|
||||
attach() { # attach <space> <file>: create or replace an attachment of <space>.WebHome
|
||||
curl -fsS -o /dev/null -w " attachment $1.WebHome/$2: %{http_code}\n" "${auth[@]}" -X PUT \
|
||||
-H 'Content-Type: image/jpeg' --data-binary "@$2" "$rest/spaces/$1/pages/WebHome/attachments/$2"
|
||||
}
|
||||
|
||||
echo "=== $base, as $user"
|
||||
page Main "StarshipOS" Main.WebHome.xwiki
|
||||
attach Main badge.jpg
|
||||
attach Main captain-bob.jpg
|
||||
page Inquiries "Inquiries" Inquiries.WebHome.xwiki
|
||||
page TryIt "Try StarshipOS" TryIt.WebHome.xwiki
|
||||
|
||||
echo "=== as a guest"
|
||||
bad=
|
||||
for u in /bin/view/Main/ /bin/view/Inquiries/ /bin/view/TryIt/ \
|
||||
/bin/download/Main/WebHome/badge.jpg /bin/download/Main/WebHome/captain-bob.jpg; do
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' "$base$u")
|
||||
if [ "$code" = 200 ]; then echo " $u: 200"; else echo " $u: $code -- NOT readable"; bad=1; fi
|
||||
done
|
||||
[ -z "$bad" ] || { echo "install: a guest cannot read everything; see above" >&2; exit 1; }
|
||||
echo "=== done: $base/bin/view/Main/"
|
||||
@@ -0,0 +1,62 @@
|
||||
{{html clean="false"}}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
.ssos, .ssos *, .ssos *::before, .ssos *::after { background-color: transparent !important; color: inherit !important; border-color: #22324D !important; }
|
||||
.ssos a, .ssos a * { color: #F5891F !important; }
|
||||
.ssos a:hover { color: #FFB061 !important; }
|
||||
.ssos input, .ssos textarea, .ssos select { background-color: #0A1222 !important; color: #EEF2F7 !important; border-color: #34486A !important; }
|
||||
.ssos ::placeholder { color: #A3AEC2 !important; opacity: 1 !important; }
|
||||
.ssos img { background-color: transparent !important; }
|
||||
</style>
|
||||
<div class="ssos" style="background: #0A1222 !important; color: #EEF2F7 !important; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6">
|
||||
<header style="border-bottom: 1px solid #22324D !important">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="/bin/view/Main/" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7 !important; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: #F5891F !important">OS</span><span style="font-size: 14px; color: #A3AEC2 !important; margin-left: 6px">.org</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px"><a href="/bin/view/Main/" style="color: #C8D1DE !important; text-decoration: none">Home</a><a href="/bin/view/Contributors/" style="color: #C8D1DE !important; text-decoration: none">Contributors</a><a href="/bin/view/Admin/" aria-current="page" style="color: #EEF2F7 !important; text-decoration: none; border-bottom: 2px solid #F5891F !important">Admin</a><a href="https://starshipos-f18.com/" style="color: #F5891F !important; text-decoration: none">starshipos-f18.com →</a></div>
|
||||
</nav>
|
||||
</header>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 80px 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0 !important">Administrator only</p>
|
||||
<h1 style="margin: 0 0 20px; font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: clamp(36px, 5vw, 56px); line-height: 1.08">Admin dashboard.</h1>
|
||||
<p style="margin: 0 0 32px; max-width: 680px; font-size: 18px; color: #C8D1DE !important">Seen by <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">XWiki.rajames</code> alone: the Admin space allows view and edit to that account and nobody else.</p>
|
||||
</section>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 0 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">CI</p>
|
||||
<h2 style="margin: 0 0 32px; font-family: 'Exo 2', sans-serif; font-size: 34px; line-height: 1.15; max-width: 760px">Every workflow, live.</h2>
|
||||
<div style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px"><div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Acceptance -- the gate on every PR into master</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/acceptance.yml/badge.svg" alt="acceptance.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=acceptance.yml" style="font-size: 13px">runs</a></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Build -- the quick check on StarForth-v4.0.0</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/build.yml/badge.svg?branch=StarForth-v4.0.0" alt="build.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=build.yml" style="font-size: 13px">runs</a></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Nightly -- acceptance, images to Nexus, proofs (03:00 UTC)</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/nightly.yml/badge.svg?branch=master" alt="nightly.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=nightly.yml" style="font-size: 13px">runs</a></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Nightly documents (04:00 UTC)</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/nightly-docs.yml/badge.svg?branch=master" alt="nightly-docs.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=nightly-docs.yml" style="font-size: 13px">runs</a></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Runner image</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/runner-image.yml/badge.svg?branch=master" alt="runner-image.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=runner-image.yml" style="font-size: 13px">runs</a></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Release -- a v<version> tag</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/release.yml/badge.svg" alt="release.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=release.yml" style="font-size: 13px">runs</a></span></div></div>
|
||||
</section>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 0 24px 96px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">Run the project</p>
|
||||
<h2 style="margin: 0 0 32px; font-family: 'Exo 2', sans-serif; font-size: 34px; line-height: 1.15; max-width: 760px">Work, artifacts, sites.</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px">
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 22px">Work</h3>
|
||||
<p style="margin: 0 0 14px; font-size: 13px; color: #F5891F !important">Gitea</p>
|
||||
<ul style="margin: 0; padding-left: 20px; color: #C8D1DE !important; font-size: 15px; display: flex; flex-direction: column; gap: 8px"><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/pulls?state=open">Open pull requests</a></li><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues?state=open">Open issues</a> — <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues?state=open&labels=23">in progress</a>, <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues?state=open&labels=20">blocked</a>, <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues?state=open&labels=21">needs acceptance</a></li><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/milestones">Milestones</a> and <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/projects">the project board</a></li><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/settings/branches">Branch protection</a> — master: no pushes, merges only after Acceptance</li><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/settings/actions/secrets">Actions secrets</a> — <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">NEXUS_CI_PASSWORD</code>, <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">PACKAGES_TOKEN</code>, <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">CAPSULE_SIGN_KEY</code></li><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/settings/actions/runners">Runners</a></li><li><a href="https://gitea.starshipos-f18.org/user/settings/applications">Access tokens</a> — revoke what a session no longer needs</li></ul>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 22px">Artifacts</h3>
|
||||
<p style="margin: 0 0 14px; font-size: 13px; color: #F5891F !important">Nexus and packages</p>
|
||||
<ul style="margin: 0; padding-left: 20px; color: #C8D1DE !important; font-size: 15px; display: flex; flex-direction: column; gap: 8px"><li><a href="https://nexus.starshipos-f18.org/#browse/browse:starshipos-snapshots:org%2Fstarship">Snapshots</a> — <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">kernelImage</code> (pc, raspi5, milkv, logs), <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">documentation</code> (book, vol1–vol3, api)</li><li><a href="https://nexus.starshipos-f18.org/#browse/browse:starshipos-releases:org%2Fstarship">Releases</a></li><li><a href="https://gitea.starshipos-f18.org/rajames/-/packages">Container images</a> — <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">lithosananke-runner</code></li></ul>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 22px">Sites</h3>
|
||||
<p style="margin: 0 0 14px; font-size: 13px; color: #F5891F !important">and the wiki itself</p>
|
||||
<ul style="margin: 0; padding-left: 20px; color: #C8D1DE !important; font-size: 15px; display: flex; flex-direction: column; gap: 8px"><li><a href="https://starshipos-f18.com/">starshipos-f18.com</a> and <a href="https://starshipos-f18.com/bin/view/TryIt/">Try it</a></li><li><a href="/bin/view/Contributors/">Contributors' dashboard</a></li><li><a href="/bin/admin/XWiki/XWikiPreferences">Wiki administration</a> — users, the group <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">XWiki.StarshipContributors</code>, rights</li></ul>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
<footer style="border-top: 1px solid #22324D !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2 !important">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke" style="color: #C8D1DE !important">Source</a><a href="https://starshipos-f18.com/" style="color: #C8D1DE !important">starshipos-f18.com</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
{{/html}}
|
||||
@@ -0,0 +1,72 @@
|
||||
{{html clean="false"}}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
.ssos, .ssos *, .ssos *::before, .ssos *::after { background-color: transparent !important; color: inherit !important; border-color: #22324D !important; }
|
||||
.ssos a, .ssos a * { color: #F5891F !important; }
|
||||
.ssos a:hover { color: #FFB061 !important; }
|
||||
.ssos input, .ssos textarea, .ssos select { background-color: #0A1222 !important; color: #EEF2F7 !important; border-color: #34486A !important; }
|
||||
.ssos ::placeholder { color: #A3AEC2 !important; opacity: 1 !important; }
|
||||
.ssos img { background-color: transparent !important; }
|
||||
</style>
|
||||
<div class="ssos" style="background: #0A1222 !important; color: #EEF2F7 !important; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6">
|
||||
<header style="border-bottom: 1px solid #22324D !important">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="/bin/view/Main/" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7 !important; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: #F5891F !important">OS</span><span style="font-size: 14px; color: #A3AEC2 !important; margin-left: 6px">.org</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px"><a href="/bin/view/Main/" style="color: #C8D1DE !important; text-decoration: none">Home</a><a href="/bin/view/Contributors/" aria-current="page" style="color: #EEF2F7 !important; text-decoration: none; border-bottom: 2px solid #F5891F !important">Contributors</a><a href="https://starshipos-f18.com/" style="color: #F5891F !important; text-decoration: none">starshipos-f18.com →</a></div>
|
||||
</nav>
|
||||
</header>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 80px 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0 !important">Contributors</p>
|
||||
<h1 style="margin: 0 0 20px; font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: clamp(36px, 5vw, 56px); line-height: 1.08">Contributors' dashboard.</h1>
|
||||
<p style="margin: 0 0 32px; max-width: 680px; font-size: 18px; color: #C8D1DE !important">For the members of <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">XWiki.StarshipContributors</code> and the administrator. Ask Captain Bob to be added.</p>
|
||||
</section>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 0 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">How we work</p>
|
||||
<h2 style="margin: 0 0 32px; font-family: 'Exo 2', sans-serif; font-size: 34px; line-height: 1.15; max-width: 760px">The Captain Bob method.</h2>
|
||||
<p style="margin: 0 0 32px; max-width: 720px; color: #C8D1DE !important">Neither agile nor waterfall: one process from the developer's desk to master.</p>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 24px">
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px"><div style="font-family: 'Exo 2', sans-serif; font-size: 28px; font-weight: 700; color: #F5891F !important">1</div><h3 style="margin: 4px 0 8px; font-family: 'Exo 2', sans-serif; font-size: 22px">Found</h3><p style="margin: 0; color: #C8D1DE !important; font-size: 14px">An issue says what is wrong or missing, with the evidence: a log, a line of code.</p></article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px"><div style="font-family: 'Exo 2', sans-serif; font-size: 28px; font-weight: 700; color: #F5891F !important">2</div><h3 style="margin: 4px 0 8px; font-family: 'Exo 2', sans-serif; font-size: 22px">Ruled</h3><p style="margin: 0; color: #C8D1DE !important; font-size: 14px">Captain Bob decides what is to be done. Nothing is built without a ruling, and no fix nobody asked for.</p></article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px"><div style="font-family: 'Exo 2', sans-serif; font-size: 28px; font-weight: 700; color: #F5891F !important">3</div><h3 style="margin: 4px 0 8px; font-family: 'Exo 2', sans-serif; font-size: 22px">Built</h3><p style="margin: 0; color: #C8D1DE !important; font-size: 14px">On the working branch, <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">StarForth-v4.0.0</code>. C99, no GNU extensions; compose in FORTH before adding a C word.</p></article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px"><div style="font-family: 'Exo 2', sans-serif; font-size: 28px; font-weight: 700; color: #F5891F !important">4</div><h3 style="margin: 4px 0 8px; font-family: 'Exo 2', sans-serif; font-size: 22px">Verified</h3><p style="margin: 0; color: #C8D1DE !important; font-size: 14px">The acceptance protocol, below; its logs are committed under <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">logs/</code>.</p></article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px"><div style="font-family: 'Exo 2', sans-serif; font-size: 28px; font-weight: 700; color: #F5891F !important">5</div><h3 style="margin: 4px 0 8px; font-family: 'Exo 2', sans-serif; font-size: 22px">Merged</h3><p style="margin: 0; color: #C8D1DE !important; font-size: 14px">A pull request into <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">master</code>, which runs acceptance by itself. master takes nothing else.</p></article>
|
||||
</div>
|
||||
</section>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">The acceptance protocol</p>
|
||||
<h2 style="margin: 0 0 32px; font-family: 'Exo 2', sans-serif; font-size: 34px; line-height: 1.15; max-width: 760px">In this order, one QEMU at a time, in the foreground.</h2>
|
||||
<pre style="margin: 0 0 24px; background: #0E182B !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 24px; overflow-x: auto; font-size: 14px; color: #EEF2F7 !important">make -f kernel/Makefile ARCH=amd64 clean qemu
|
||||
make -f kernel/Makefile ARCH=aarch64 clean qemu
|
||||
make -f kernel/Makefile ARCH=riscv64 clean qemu
|
||||
make -f kernel/Makefile ARCH=amd64 clean qemu-stick-high
|
||||
make -C v4 test-32</pre>
|
||||
<p style="margin: 0 0 24px; max-width: 760px; color: #C8D1DE !important">Each boot reaches <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">[zuse@Hera] ok></code> with <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">POST: PASSED</code> and every POST check passing, and the three architectures report the same <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">dict_hash</code>. <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">make ARCH=amd64,aarch64,riscv64 init</code> installs everything this needs.</p>
|
||||
<div style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px"><div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Acceptance -- the gate on every PR into master</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/acceptance.yml/badge.svg" alt="acceptance.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=acceptance.yml" style="font-size: 13px">runs</a></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Build -- the quick check on StarForth-v4.0.0</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/build.yml/badge.svg?branch=StarForth-v4.0.0" alt="build.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=build.yml" style="font-size: 13px">runs</a></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Nightly -- acceptance, images to Nexus, proofs (03:00 UTC)</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/nightly.yml/badge.svg?branch=master" alt="nightly.yml status" style="display: block; height: 20px"> <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions?workflow=nightly.yml" style="font-size: 13px">runs</a></span></div></div>
|
||||
</section>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 0 24px 96px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">Reference</p>
|
||||
<h2 style="margin: 0 0 32px; font-family: 'Exo 2', sans-serif; font-size: 34px; line-height: 1.15; max-width: 760px">Where things are, and what not to do.</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); gap: 24px">
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 22px">Where things are</h3>
|
||||
<p style="margin: 0 0 14px; font-size: 13px; color: #F5891F !important">start here</p>
|
||||
<ul style="margin: 0; padding-left: 20px; color: #C8D1DE !important; font-size: 15px; display: flex; flex-direction: column; gap: 8px"><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke">The repository</a> — <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">README.md</code>, <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">docs/README.md</code>; the design record is <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">docs/fabric/FABRIC-3.md</code></li><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues/new/choose">New issue</a> — the forms: bug, work, ruling, board</li><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues?state=open&labels=2">Open features</a> and <a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues?state=open&labels=1">bugs</a></li><li><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues?state=open&milestone=2">Board bring-up</a> — <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">boards/BRINGUP.md</code></li><li>Before touching a capsule: read <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">experiments/bare_metal/README.md</code> — the block ranges are shared by every capsule</li></ul>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 22px">Rules that bite</h3>
|
||||
<p style="margin: 0 0 14px; font-size: 13px; color: #F5891F !important">learned the hard way</p>
|
||||
<ul style="margin: 0; padding-left: 20px; color: #C8D1DE !important; font-size: 15px; display: flex; flex-direction: column; gap: 8px"><li>No new branch, no <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">git stash</code>, without Captain Bob's say-so.</li><li>Never modify a registered, tested FORTH word to fix it: the problem is in the caller.</li><li>ACL policy lives in <code style="color: #EEF2F7 !important; background: #0A1222 !important; padding: 1px 6px; border-radius: 3px">ACL.4th</code>, not in C.</li><li>Tags are sacred: each has the logs proving its state.</li></ul>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
<footer style="border-top: 1px solid #22324D !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2 !important">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke" style="color: #C8D1DE !important">Source</a><a href="https://starshipos-f18.com/" style="color: #C8D1DE !important">starshipos-f18.com</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
{{/html}}
|
||||
@@ -0,0 +1,93 @@
|
||||
{{velocity}}
|
||||
#if ($isGuest)
|
||||
#[[{{html clean="false"}}<style>
|
||||
#menuview, #hierarchy_breadcrumb, .document-header, #xdocFooter, #footerglobal, #leftPanels, #rightPanels,
|
||||
#leftPanelsToggle, #rightPanelsToggle, .tour, .tour-backdrop, #bootstrap_tour_restart, .xtour-restart,
|
||||
#xwikimaincontainerinner > a.btn { display: none !important; }
|
||||
html, body, #xwikimaincontainer, #xwikimaincontainerinner, #contentcontainer, #contentcolumn, .main,
|
||||
#mainContentArea, #xwikicontent, #mainContentArea .row { background-color: #0A1222 !important; }
|
||||
#contentcontainer, #contentcolumn, .main, #mainContentArea, #xwikicontent, #mainContentArea .row {
|
||||
width: 100% !important; max-width: none !important; margin: 0 !important; padding: 0 !important; border: 0 !important; float: none !important; }
|
||||
#xwikicontent > .ssos { border: 0 !important; }
|
||||
#xwikimaincontainer { padding: 0 !important; }
|
||||
.main hr:not(.ssos hr), #xwikicontent > :not(.ssos) { display: none !important; }
|
||||
</style>{{/html}}]]#
|
||||
#end
|
||||
{{/velocity}}
|
||||
{{html clean="false"}}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
.ssos, .ssos *, .ssos *::before, .ssos *::after { background-color: transparent !important; color: inherit !important; border-color: #22324D !important; }
|
||||
.ssos a, .ssos a * { color: #F5891F !important; }
|
||||
.ssos a:hover { color: #FFB061 !important; }
|
||||
.ssos input, .ssos textarea, .ssos select { background-color: #0A1222 !important; color: #EEF2F7 !important; border-color: #34486A !important; }
|
||||
.ssos ::placeholder { color: #A3AEC2 !important; opacity: 1 !important; }
|
||||
.ssos img { background-color: transparent !important; }
|
||||
</style>
|
||||
<div class="ssos" style="background: #0A1222 !important; color: #EEF2F7 !important; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 16px; line-height: 1.6">
|
||||
<header style="border-bottom: 1px solid #22324D !important">
|
||||
<nav aria-label="Main" style="max-width: 1120px; margin: 0 auto; padding: 20px 24px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px">
|
||||
<a href="/bin/view/Main/" style="font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: 22px; color: #EEF2F7 !important; text-decoration: none; letter-spacing: 0.02em">starship<span style="color: #F5891F !important">OS</span><span style="font-size: 14px; color: #A3AEC2 !important; margin-left: 6px">.org</span></a>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px"><a href="/bin/view/Main/" aria-current="page" style="color: #EEF2F7 !important; text-decoration: none; border-bottom: 2px solid #F5891F !important">Home</a><a href="/bin/view/Contributors/" style="color: #C8D1DE !important; text-decoration: none">Contributors</a><a href="https://starshipos-f18.com/" style="color: #F5891F !important; text-decoration: none">starshipos-f18.com →</a></div>
|
||||
</nav>
|
||||
</header>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 80px 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #4FD1B0 !important">ok> the working home</p>
|
||||
<h1 style="margin: 0 0 20px; font-family: 'Exo 2', sans-serif; font-weight: 700; font-size: clamp(36px, 5vw, 56px); line-height: 1.08">Where StarshipOS is built.</h1>
|
||||
<p style="margin: 0 0 32px; max-width: 680px; font-size: 18px; color: #C8D1DE !important">StarshipOS is an operating system with no other operating system underneath it. LithosAnanke, a UEFI microkernel, boots straight from the firmware and runs StarForth, a FORTH virtual machine, as its only runtime. This wiki holds its design, its record and its dashboards; the public face is <a href="https://starshipos-f18.com/">starshipos-f18.com</a>.</p>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 16px"><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke" style="display: inline-block; padding: 14px 24px; background: #F5891F !important; color: #0A1222 !important; font-weight: 700; text-decoration: none; border-radius: 4px">Browse the source</a><a href="https://starshipos-f18.com/bin/view/TryIt/" style="display: inline-block; padding: 14px 24px; border: 1px solid #34486A !important; color: #EEF2F7 !important; text-decoration: none; border-radius: 4px">Try it in a browser</a></div>
|
||||
</section>
|
||||
<section aria-label="At a glance" style="border-top: 1px solid #22324D !important; border-bottom: 1px solid #22324D !important; background: #0E182B !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 24px"><div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">v2.1.0</div><div style="font-size: 14px; color: #A3AEC2 !important">LithosAnanke, the UEFI microkernel</div></div><div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">v4</div><div style="font-size: 14px; color: #A3AEC2 !important">StarForth, the F18 engine</div></div><div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">3 ISAs</div><div style="font-size: 14px; color: #A3AEC2 !important">amd64 · aarch64 · riscv64</div></div><div><div style="font-family: 'Exo 2', sans-serif; font-size: 32px; font-weight: 700; color: #F5891F !important">538</div><div style="font-size: 14px; color: #A3AEC2 !important">POST checks on every boot</div></div></div>
|
||||
</section>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 96px 24px 48px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">The project</p>
|
||||
<h2 style="margin: 0 0 32px; font-family: 'Exo 2', sans-serif; font-size: 34px; line-height: 1.15; max-width: 760px">One repository, one process, one line to master.</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px">
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 22px">The source</h3>
|
||||
<p style="margin: 0 0 14px; font-size: 13px; color: #F5891F !important">kernel, StarForth, proofs, documents</p>
|
||||
<p style="margin: 0 0 16px; color: #C8D1DE !important">Everything in one repository: LithosAnanke, StarForth v3 and v4, the Isabelle/HOL proofs and the books.</p><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke">Browse it →</a>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 22px">Issues</h3>
|
||||
<p style="margin: 0 0 14px; font-size: 13px; color: #F5891F !important">found, ruled, built, verified</p>
|
||||
<p style="margin: 0 0 16px; color: #C8D1DE !important">Every piece of work starts as an issue with its evidence, and is ruled before it is built.</p><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/issues">Open issues →</a>
|
||||
</article>
|
||||
<article style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px">
|
||||
<h3 style="margin: 0 0 4px; font-family: 'Exo 2', sans-serif; font-size: 22px">Pull requests</h3>
|
||||
<p style="margin: 0 0 14px; font-size: 13px; color: #F5891F !important">the only way into master</p>
|
||||
<p style="margin: 0 0 16px; color: #C8D1DE !important">master takes nothing but a pull request that passed the acceptance protocol.</p><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke/pulls">Pull requests →</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">How a change is accepted</p>
|
||||
<h2 style="margin: 0 0 32px; font-family: 'Exo 2', sans-serif; font-size: 34px; line-height: 1.15; max-width: 760px">Booted on three architectures, every time.</h2>
|
||||
<p style="margin: 0 0 24px; max-width: 760px; color: #C8D1DE !important">The kernel boots in QEMU on amd64, aarch64 and riscv64 to its prompt, its power-on self-test passing every check; the PC stick boots loaded the way a PC loads it; the 32-bit build passes its tests. A developer runs it by hand, a pull request runs it by itself, and the nightly runs it again before it publishes.</p>
|
||||
<div style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px"><div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Acceptance -- the gate on every PR into master</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/acceptance.yml/badge.svg" alt="acceptance.yml status" style="display: block; height: 20px"></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Nightly -- acceptance, images to Nexus, proofs (03:00 UTC)</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/nightly.yml/badge.svg?branch=master" alt="nightly.yml status" style="display: block; height: 20px"></span></div>
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid #22324D !important"><span style="color: #C8D1DE !important; font-size: 14px">Nightly documents (04:00 UTC)</span><span style="display: flex; align-items: center; gap: 16px"><img src="https://gitea.starshipos-f18.org/rajames/LithosAnanke/actions/workflows/nightly-docs.yml/badge.svg?branch=master" alt="nightly-docs.yml status" style="display: block; height: 20px"></span></div></div>
|
||||
</section>
|
||||
<section style="max-width: 1120px; margin: 0 auto; padding: 48px 24px 96px">
|
||||
<div style="background: #111C30 !important; border: 1px solid #22324D !important; border-radius: 6px; padding: 28px; padding: 40px; display: flex; flex-wrap: wrap; gap: 32px; align-items: center">
|
||||
<div style="flex: 999 1 480px; min-width: 0">
|
||||
<p style="margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: #F5891F !important">Contributors</p>
|
||||
<h2 style="margin: 0 0 12px; font-family: 'Exo 2', sans-serif; font-size: 30px">Working on StarshipOS?</h2>
|
||||
<p style="margin: 0; color: #C8D1DE !important">Contributors have a dashboard of their own: the method, the acceptance commands, the open work. Log in to see it.</p>
|
||||
</div>
|
||||
<div style="flex: 1 1 220px; display: flex; flex-direction: column; gap: 12px">
|
||||
<a href="/bin/login/XWiki/XWikiLogin?xredirect=/bin/view/Contributors/" style="display: inline-block; padding: 14px 24px; background: #F5891F !important; color: #0A1222 !important; font-weight: 700; text-decoration: none; border-radius: 4px; text-align: center">Log in</a>
|
||||
<a href="/bin/view/Contributors/" style="display: inline-block; padding: 14px 24px; border: 1px solid #34486A !important; color: #EEF2F7 !important; text-decoration: none; border-radius: 4px; text-align: center">Contributors' dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<footer style="border-top: 1px solid #22324D !important">
|
||||
<div style="max-width: 1120px; margin: 0 auto; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; justify-content: space-between; font-size: 13px; color: #A3AEC2 !important">
|
||||
<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>
|
||||
<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="https://gitea.starshipos-f18.org/rajames/LithosAnanke" style="color: #C8D1DE !important">Source</a><a href="https://starshipos-f18.com/" style="color: #C8D1DE !important">starshipos-f18.com</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
{{/html}}
|
||||
@@ -0,0 +1,27 @@
|
||||
# site/org -- the .org XWiki's pages
|
||||
|
||||
The project's working wiki at `starshipos-f18.org` (the public face is the `.com`; `demo/` has its
|
||||
"Try it" page). Three pages, ruled by Captain Bob on 2026-11-07:
|
||||
|
||||
| Page | File | Who sees it |
|
||||
|---|---|---|
|
||||
| `Main.WebHome` -- the landing page | `Main.WebHome.xwiki` | everyone, guests included |
|
||||
| `Admin.WebHome` -- the admin dashboard | `Admin.WebHome.xwiki` | the administrator (`XWiki.rajames`) alone |
|
||||
| `Contributors.WebHome` -- the contributors' dashboard | `Contributors.WebHome.xwiki` | the group `XWiki.StarshipContributors`, and the administrator |
|
||||
|
||||
They are in the starshipos-f18.com look -- the "StarshipOS.com" design canvas (navy `#0A1222`, accent
|
||||
`#F5891F`, JetBrains Mono with Exo 2 headings), where they are also drawn as the `.org` artboards.
|
||||
`build.py` writes the three `.xwiki` files (and, with `--canvas <dir>`, the artboards) from one
|
||||
source: edit it, not the `.xwiki` files. Each page is one `{{html}}` block, which needs a page author
|
||||
with script rights (the administrator has them). CI is shown as Gitea's live workflow badges, which
|
||||
need no login.
|
||||
|
||||
`install.sh` puts them on the wiki through its REST API, makes the group and the rights, and checks
|
||||
as a guest that the landing page is readable and the dashboards are not:
|
||||
|
||||
```
|
||||
XWIKI_USER=rajames XWIKI_PASSWORD=... site/org/install.sh
|
||||
```
|
||||
|
||||
Contributors are added to `XWiki.StarshipContributors` in the wiki's administration (Users and
|
||||
Groups). The wiki-wide rights -- what guests may do anywhere else -- are the wiki's own, not this.
|
||||
Executable
+337
@@ -0,0 +1,337 @@
|
||||
#!/usr/bin/env python3
|
||||
"""build.py -- the .org XWiki's three pages in the starshipos-f18.com look (the "StarshipOS.com"
|
||||
design canvas: navy #0A1222, accent #F5891F, JetBrains Mono, Exo 2 headings), from one source.
|
||||
|
||||
site/org/build.py writes Main.WebHome.xwiki, Admin.WebHome.xwiki,
|
||||
Contributors.WebHome.xwiki (each one {{html}} block)
|
||||
site/org/build.py --canvas <dir>
|
||||
also writes <dir>/project/Org*.dc.html, the same pages as
|
||||
design-canvas artboards (status badges drawn as placeholders:
|
||||
a canvas loads nothing from Gitea)
|
||||
|
||||
The {{html}} macro needs a page author with script rights. install.sh puts the pages on the wiki.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
||||
import colorlock # noqa: E402 the design's colours over the wiki's high-contrast theme
|
||||
|
||||
GITEA = "https://gitea.starshipos-f18.org/rajames/LithosAnanke"
|
||||
COM = "https://starshipos-f18.com/"
|
||||
ISSUES = GITEA + "/issues?state=open"
|
||||
ACCENT = "#F5891F"
|
||||
TEAL = "#4FD1B0"
|
||||
|
||||
FONTS = ('<link rel="preconnect" href="https://fonts.googleapis.com">\n'
|
||||
'<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700'
|
||||
'&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">')
|
||||
|
||||
H = "font-family: 'Exo 2', sans-serif"
|
||||
CARD = "background: #111C30; border: 1px solid #22324D; border-radius: 6px; padding: 28px"
|
||||
EYEBROW = ("margin: 0 0 12px; font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; "
|
||||
"color: {accent}")
|
||||
BTN = ("display: inline-block; padding: 14px 24px; background: {accent}; color: #0A1222; "
|
||||
"font-weight: 700; text-decoration: none; border-radius: 4px")
|
||||
BTN2 = ("display: inline-block; padding: 14px 24px; border: 1px solid #34486A; color: #EEF2F7; "
|
||||
"text-decoration: none; border-radius: 4px")
|
||||
WRAP = "max-width: 1120px; margin: 0 auto"
|
||||
|
||||
WORKFLOWS = { # file -> (branch for the badge, what it is)
|
||||
"acceptance.yml": (None, "Acceptance -- the gate on every PR into master"),
|
||||
"build.yml": ("StarForth-v4.0.0", "Build -- the quick check on StarForth-v4.0.0"),
|
||||
"nightly.yml": ("master", "Nightly -- acceptance, images to Nexus, proofs (03:00 UTC)"),
|
||||
"nightly-docs.yml": ("master", "Nightly documents (04:00 UTC)"),
|
||||
"runner-image.yml": ("master", "Runner image"),
|
||||
"release.yml": (None, "Release -- a v<version> tag"),
|
||||
}
|
||||
|
||||
|
||||
def badge(wf, canvas):
|
||||
branch = WORKFLOWS[wf][0]
|
||||
if canvas:
|
||||
return ('<span style="display: inline-block; padding: 2px 10px; border: 1px dashed #34486A; '
|
||||
'border-radius: 4px; font-size: 12px; color: #A3AEC2">[LIVE STATUS]</span>')
|
||||
q = "?branch=" + branch if branch else ""
|
||||
return ('<img src="%s/actions/workflows/%s/badge.svg%s" alt="%s status" '
|
||||
'style="display: block; height: 20px">' % (GITEA, wf, q, wf))
|
||||
|
||||
|
||||
def status_rows(wfs, canvas, runs=True):
|
||||
rows = []
|
||||
for wf in wfs:
|
||||
link = (' <a href="%s/actions?workflow=%s" style="font-size: 13px">runs</a>' % (GITEA, wf)
|
||||
if runs else "")
|
||||
rows.append('<div style="display: flex; flex-wrap: wrap; align-items: center; '
|
||||
'justify-content: space-between; gap: 12px; padding: 14px 0; '
|
||||
'border-top: 1px solid #22324D">'
|
||||
'<span style="color: #C8D1DE; font-size: 14px">%s</span>'
|
||||
'<span style="display: flex; align-items: center; gap: 16px">%s%s</span></div>'
|
||||
% (WORKFLOWS[wf][1], badge(wf, canvas), link))
|
||||
return "\n".join(rows)
|
||||
|
||||
|
||||
def nav(here, links):
|
||||
items = []
|
||||
for label, href, key in links:
|
||||
cur = ' aria-current="page"' if key == here else ""
|
||||
style = ("color: #EEF2F7; text-decoration: none; border-bottom: 2px solid {accent}"
|
||||
if key == here else "color: #C8D1DE; text-decoration: none")
|
||||
items.append('<a href="%s"%s style="%s">%s</a>' % (href, cur, style, label))
|
||||
items.append('<a href="%s" style="color: {accent}; text-decoration: none">starshipos-f18.com →</a>'
|
||||
% COM)
|
||||
return ('<header style="border-bottom: 1px solid #22324D">\n'
|
||||
'<nav aria-label="Main" style="%s; padding: 20px 24px; display: flex; flex-wrap: wrap; '
|
||||
'align-items: center; justify-content: space-between; gap: 16px">\n'
|
||||
'<a href="%s" style="%s; font-weight: 700; font-size: 22px; color: #EEF2F7; '
|
||||
'text-decoration: none; letter-spacing: 0.02em">starship<span style="color: {accent}">OS</span>'
|
||||
'<span style="font-size: 14px; color: #A3AEC2; margin-left: 6px">.org</span></a>\n'
|
||||
'<div style="display: flex; flex-wrap: wrap; gap: 24px; font-size: 14px">%s</div>\n'
|
||||
'</nav>\n</header>' % (WRAP, links[0][1], H, "".join(items)))
|
||||
|
||||
|
||||
FOOTER = ('<footer style="border-top: 1px solid #22324D">\n'
|
||||
'<div style="%s; padding: 32px 24px; display: flex; flex-wrap: wrap; gap: 16px 32px; '
|
||||
'justify-content: space-between; font-size: 13px; color: #A3AEC2">\n'
|
||||
'<span>© 2026 Robert Allan James · A Starship Foundation project (in formation)</span>\n'
|
||||
'<span style="display: flex; flex-wrap: wrap; gap: 24px"><a href="%s" style="color: #C8D1DE">Source</a>'
|
||||
'<a href="%s" style="color: #C8D1DE">starshipos-f18.com</a></span>\n</div>\n</footer>' % (WRAP, GITEA, COM))
|
||||
|
||||
|
||||
def hero(eyebrow, title, text, buttons=""):
|
||||
return ('<section style="%s; padding: 80px 24px 48px">\n'
|
||||
'<p style="%s">%s</p>\n'
|
||||
'<h1 style="margin: 0 0 20px; %s; font-weight: 700; font-size: clamp(36px, 5vw, 56px); '
|
||||
'line-height: 1.08">%s</h1>\n'
|
||||
'<p style="margin: 0 0 32px; max-width: 680px; font-size: 18px; color: #C8D1DE">%s</p>\n%s'
|
||||
'</section>' % (WRAP, EYEBROW.replace("{accent}", TEAL), eyebrow, H, title, text,
|
||||
('<div style="display: flex; flex-wrap: wrap; gap: 16px">%s</div>\n' % buttons)
|
||||
if buttons else ""))
|
||||
|
||||
|
||||
def section(eyebrow, title, body, pad="48px 24px"):
|
||||
return ('<section style="%s; padding: %s">\n<p style="%s">%s</p>\n'
|
||||
'<h2 style="margin: 0 0 32px; %s; font-size: 34px; line-height: 1.15; max-width: 760px">%s</h2>\n'
|
||||
'%s\n</section>' % (WRAP, pad, EYEBROW, eyebrow, H, title, body))
|
||||
|
||||
|
||||
def card(title, sub, body):
|
||||
return ('<article style="%s">\n<h3 style="margin: 0 0 4px; %s; font-size: 22px">%s</h3>\n'
|
||||
'<p style="margin: 0 0 14px; font-size: 13px; color: {accent}">%s</p>\n%s\n</article>'
|
||||
% (CARD, H, title, sub, body))
|
||||
|
||||
|
||||
def grid(items, min_w=280):
|
||||
return ('<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(%dpx, 1fr)); '
|
||||
'gap: 24px">\n%s\n</div>' % (min_w, "\n".join(items)))
|
||||
|
||||
|
||||
def links(items):
|
||||
return ('<ul style="margin: 0; padding-left: 20px; color: #C8D1DE; font-size: 15px; '
|
||||
'display: flex; flex-direction: column; gap: 8px">%s</ul>'
|
||||
% "".join("<li>%s</li>" % i for i in items))
|
||||
|
||||
|
||||
def a(href, text):
|
||||
return '<a href="%s">%s</a>' % (href, text)
|
||||
|
||||
|
||||
def code(s):
|
||||
return '<code style="color: #EEF2F7; background: #0A1222; padding: 1px 6px; border-radius: 3px">%s</code>' % s
|
||||
|
||||
|
||||
def page_main(canvas, url):
|
||||
links_ = [("Home", url("Main"), "Main"), ("Contributors", url("Contributors"), "Contributors")]
|
||||
glance = [("v2.1.0", "LithosAnanke, the UEFI microkernel"), ("v4", "StarForth, the F18 engine"),
|
||||
("3 ISAs", "amd64 · aarch64 · riscv64"), ("538", "POST checks on every boot")]
|
||||
strip = ('<section aria-label="At a glance" style="border-top: 1px solid #22324D; border-bottom: 1px solid '
|
||||
'#22324D; background: #0E182B">\n<div style="%s; padding: 32px 24px; display: grid; '
|
||||
'grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 24px">%s</div>\n</section>'
|
||||
% (WRAP, "".join('<div><div style="%s; font-size: 32px; font-weight: 700; color: {accent}">%s</div>'
|
||||
'<div style="font-size: 14px; color: #A3AEC2">%s</div></div>' % (H, n, t)
|
||||
for n, t in glance)))
|
||||
project = section("The project", "One repository, one process, one line to master.", grid([
|
||||
card("The source", "kernel, StarForth, proofs, documents",
|
||||
'<p style="margin: 0 0 16px; color: #C8D1DE">Everything in one repository: LithosAnanke, '
|
||||
'StarForth v3 and v4, the Isabelle/HOL proofs and the books.</p>' + a(GITEA, "Browse it →")),
|
||||
card("Issues", "found, ruled, built, verified",
|
||||
'<p style="margin: 0 0 16px; color: #C8D1DE">Every piece of work starts as an issue with its '
|
||||
'evidence, and is ruled before it is built.</p>' + a(GITEA + "/issues", "Open issues →")),
|
||||
card("Pull requests", "the only way into master",
|
||||
'<p style="margin: 0 0 16px; color: #C8D1DE">master takes nothing but a pull request that '
|
||||
'passed the acceptance protocol.</p>' + a(GITEA + "/pulls", "Pull requests →")),
|
||||
]), pad="96px 24px 48px")
|
||||
accept = section("How a change is accepted", "Booted on three architectures, every time.",
|
||||
'<p style="margin: 0 0 24px; max-width: 760px; color: #C8D1DE">The kernel boots in QEMU '
|
||||
'on amd64, aarch64 and riscv64 to its prompt, its power-on self-test passing every check; '
|
||||
'the PC stick boots loaded the way a PC loads it; the 32-bit build passes its tests. A '
|
||||
'developer runs it by hand, a pull request runs it by itself, and the nightly runs it '
|
||||
'again before it publishes.</p>\n<div style="%s">%s</div>'
|
||||
% (CARD, status_rows(["acceptance.yml", "nightly.yml", "nightly-docs.yml"], canvas, False)))
|
||||
contrib = ('<section style="%s; padding: 48px 24px 96px">\n<div style="%s; padding: 40px; display: flex; '
|
||||
'flex-wrap: wrap; gap: 32px; align-items: center">\n<div style="flex: 999 1 480px; min-width: 0">\n'
|
||||
'<p style="%s">Contributors</p>\n<h2 style="margin: 0 0 12px; %s; font-size: 30px">'
|
||||
'Working on StarshipOS?</h2>\n<p style="margin: 0; color: #C8D1DE">Contributors have a dashboard '
|
||||
'of their own: the method, the acceptance commands, the open work. Log in to see it.</p>\n</div>\n'
|
||||
'<div style="flex: 1 1 220px; display: flex; flex-direction: column; gap: 12px">\n'
|
||||
'<a href="%s" style="%s; text-align: center">Log in</a>\n'
|
||||
'<a href="%s" style="%s; text-align: center">Contributors\' dashboard</a>\n</div>\n</div>\n</section>'
|
||||
% (WRAP, CARD, EYEBROW, H, url("login"), BTN, url("Contributors"), BTN2))
|
||||
return "\n".join([
|
||||
nav("Main", links_),
|
||||
hero("ok> the working home", "Where StarshipOS is built.",
|
||||
"StarshipOS is an operating system with no other operating system underneath it. LithosAnanke, a "
|
||||
"UEFI microkernel, boots straight from the firmware and runs StarForth, a FORTH virtual machine, "
|
||||
"as its only runtime. This wiki holds its design, its record and its dashboards; the public face "
|
||||
"is " + a(COM, "starshipos-f18.com") + ".",
|
||||
'<a href="%s" style="%s">Browse the source</a><a href="%s" style="%s">Try it in a browser</a>'
|
||||
% (GITEA, BTN, COM + "bin/view/TryIt/", BTN2)),
|
||||
strip, project, accept, contrib, FOOTER])
|
||||
|
||||
|
||||
def page_admin(canvas, url):
|
||||
links_ = [("Home", url("Main"), "Main"), ("Contributors", url("Contributors"), "Contributors"),
|
||||
("Admin", url("Admin"), "Admin")]
|
||||
ci = section("CI", "Every workflow, live.", '<div style="%s">%s</div>' % (CARD, status_rows(list(WORKFLOWS), canvas)),
|
||||
pad="0 24px 48px")
|
||||
work = card("Work", "Gitea", links([
|
||||
a(GITEA + "/pulls?state=open", "Open pull requests"),
|
||||
a(ISSUES, "Open issues") + " — " + a(ISSUES + "&labels=23", "in progress") + ", "
|
||||
+ a(ISSUES + "&labels=20", "blocked") + ", " + a(ISSUES + "&labels=21", "needs acceptance"),
|
||||
a(GITEA + "/milestones", "Milestones") + " and " + a(GITEA + "/projects", "the project board"),
|
||||
a(GITEA + "/settings/branches", "Branch protection") + " — master: no pushes, merges only after Acceptance",
|
||||
a(GITEA + "/settings/actions/secrets", "Actions secrets") + " — " + code("NEXUS_CI_PASSWORD") + ", "
|
||||
+ code("PACKAGES_TOKEN") + ", " + code("CAPSULE_SIGN_KEY"),
|
||||
a(GITEA + "/settings/actions/runners", "Runners"),
|
||||
a("https://gitea.starshipos-f18.org/user/settings/applications", "Access tokens")
|
||||
+ " — revoke what a session no longer needs"]))
|
||||
arts = card("Artifacts", "Nexus and packages", links([
|
||||
a("https://nexus.starshipos-f18.org/#browse/browse:starshipos-snapshots:org%2Fstarship", "Snapshots")
|
||||
+ " — " + code("kernelImage") + " (pc, raspi5, milkv, logs), " + code("documentation")
|
||||
+ " (book, vol1–vol3, api)",
|
||||
a("https://nexus.starshipos-f18.org/#browse/browse:starshipos-releases:org%2Fstarship", "Releases"),
|
||||
a("https://gitea.starshipos-f18.org/rajames/-/packages", "Container images") + " — "
|
||||
+ code("lithosananke-runner"), ]))
|
||||
sites = card("Sites", "and the wiki itself", links([
|
||||
a(COM, "starshipos-f18.com") + " and " + a(COM + "bin/view/TryIt/", "Try it"),
|
||||
a(url("Contributors"), "Contributors' dashboard"),
|
||||
a(url("admin"), "Wiki administration") + " — users, the group " + code("XWiki.StarshipContributors")
|
||||
+ ", rights"]))
|
||||
return "\n".join([
|
||||
nav("Admin", links_),
|
||||
hero("Administrator only", "Admin dashboard.",
|
||||
"Seen by " + code("XWiki.rajames") + " alone: the Admin space allows view and edit to that "
|
||||
"account and nobody else."),
|
||||
ci, section("Run the project", "Work, artifacts, sites.", grid([work, arts, sites], 300), pad="0 24px 96px"),
|
||||
FOOTER])
|
||||
|
||||
|
||||
def page_contrib(canvas, url):
|
||||
links_ = [("Home", url("Main"), "Main"), ("Contributors", url("Contributors"), "Contributors")]
|
||||
steps = [("Found", "An issue says what is wrong or missing, with the evidence: a log, a line of code."),
|
||||
("Ruled", "Captain Bob decides what is to be done. Nothing is built without a ruling, and no fix "
|
||||
"nobody asked for."),
|
||||
("Built", "On the working branch, " + code("StarForth-v4.0.0") + ". C99, no GNU extensions; compose "
|
||||
"in FORTH before adding a C word."),
|
||||
("Verified", "The acceptance protocol, below; its logs are committed under " + code("logs/") + "."),
|
||||
("Merged", "A pull request into " + code("master") + ", which runs acceptance by itself. master takes "
|
||||
"nothing else.")]
|
||||
method = section("How we work", "The Captain Bob method.",
|
||||
'<p style="margin: 0 0 32px; max-width: 720px; color: #C8D1DE">Neither agile nor waterfall: '
|
||||
'one process from the developer\'s desk to master.</p>\n' + grid(
|
||||
['<article style="%s"><div style="%s; font-size: 28px; font-weight: 700; color: {accent}">'
|
||||
'%d</div><h3 style="margin: 4px 0 8px; %s; font-size: 22px">%s</h3>'
|
||||
'<p style="margin: 0; color: #C8D1DE; font-size: 14px">%s</p></article>'
|
||||
% (CARD, H, i + 1, H, t, d) for i, (t, d) in enumerate(steps)], 190), pad="0 24px 48px")
|
||||
cmds = ("make -f kernel/Makefile ARCH=amd64 clean qemu\n"
|
||||
"make -f kernel/Makefile ARCH=aarch64 clean qemu\n"
|
||||
"make -f kernel/Makefile ARCH=riscv64 clean qemu\n"
|
||||
"make -f kernel/Makefile ARCH=amd64 clean qemu-stick-high\n"
|
||||
"make -C v4 test-32")
|
||||
accept = section("The acceptance protocol", "In this order, one QEMU at a time, in the foreground.",
|
||||
'<pre style="margin: 0 0 24px; background: #0E182B; border: 1px solid #22324D; '
|
||||
'border-radius: 6px; padding: 24px; overflow-x: auto; font-size: 14px; color: #EEF2F7">'
|
||||
'%s</pre>\n<p style="margin: 0 0 24px; max-width: 760px; color: #C8D1DE">Each boot reaches '
|
||||
'%s with %s and every POST check passing, and the three architectures report the same '
|
||||
'%s. %s installs everything this needs.</p>\n<div style="%s">%s</div>'
|
||||
% (cmds, code("[zuse@Hera] ok>"), code("POST: PASSED"), code("dict_hash"),
|
||||
code("make ARCH=amd64,aarch64,riscv64 init"), CARD,
|
||||
status_rows(["acceptance.yml", "build.yml", "nightly.yml"], canvas)))
|
||||
where = card("Where things are", "start here", links([
|
||||
a(GITEA, "The repository") + " — " + code("README.md") + ", " + code("docs/README.md")
|
||||
+ "; the design record is " + code("docs/fabric/FABRIC-3.md"),
|
||||
a(GITEA + "/issues/new/choose", "New issue") + " — the forms: bug, work, ruling, board",
|
||||
a(ISSUES + "&labels=2", "Open features") + " and " + a(ISSUES + "&labels=1", "bugs"),
|
||||
a(ISSUES + "&milestone=2", "Board bring-up") + " — " + code("boards/BRINGUP.md"),
|
||||
"Before touching a capsule: read " + code("experiments/bare_metal/README.md")
|
||||
+ " — the block ranges are shared by every capsule"]))
|
||||
rules = card("Rules that bite", "learned the hard way", links([
|
||||
"No new branch, no " + code("git stash") + ", without Captain Bob's say-so.",
|
||||
"Never modify a registered, tested FORTH word to fix it: the problem is in the caller.",
|
||||
"ACL policy lives in " + code("ACL.4th") + ", not in C.",
|
||||
"Tags are sacred: each has the logs proving its state."]))
|
||||
return "\n".join([
|
||||
nav("Contributors", links_),
|
||||
hero("Contributors", "Contributors' dashboard.",
|
||||
"For the members of " + code("XWiki.StarshipContributors") + " and the administrator. "
|
||||
"Ask Captain Bob to be added."),
|
||||
method, accept, section("Reference", "Where things are, and what not to do.",
|
||||
grid([where, rules], 360), pad="0 24px 96px"),
|
||||
FOOTER])
|
||||
|
||||
|
||||
PAGES = { # name -> (builder, title, canvas file, canvas height)
|
||||
"Main": (page_main, "StarshipOS", "OrgHome.dc.html", 2300),
|
||||
"Admin": (page_admin, "Admin Dashboard", "OrgAdmin.dc.html", 1900),
|
||||
"Contributors": (page_contrib, "Contributors' Dashboard", "OrgContributors.dc.html", 2500),
|
||||
}
|
||||
|
||||
|
||||
def wiki_url(key):
|
||||
return {"login": "/bin/login/XWiki/XWikiLogin?xredirect=/bin/view/Contributors/",
|
||||
"admin": "/bin/admin/XWiki/XWikiPreferences"}.get(key, "/bin/view/%s/" % key)
|
||||
|
||||
|
||||
def canvas_url(key):
|
||||
files = {k: v[2] for k, v in PAGES.items()}
|
||||
return files.get(key, "https://starshipos-f18.org" + wiki_url(key))
|
||||
|
||||
|
||||
def body(name, canvas):
|
||||
html = PAGES[name][0](canvas, canvas_url if canvas else wiki_url)
|
||||
return ('<div style="background: #0A1222; color: #EEF2F7; font-family: \'JetBrains Mono\', ui-monospace, '
|
||||
'monospace; font-size: 16px; line-height: 1.6">\n%s\n</div>' % html)
|
||||
|
||||
|
||||
def write_wiki(name):
|
||||
html = colorlock.lock(body(name, False).replace("{accent}", ACCENT), "<div style=\"background: #0A1222")
|
||||
with open("%s.WebHome.xwiki" % name, "w") as f:
|
||||
# the landing page is the public one: the design alone for visitors, as on the .com
|
||||
chrome = colorlock.GUEST_CHROME if name == "Main" else ""
|
||||
f.write(chrome + '{{html clean="false"}}\n%s\n%s\n{{/html}}\n' % (FONTS, html))
|
||||
|
||||
|
||||
def write_canvas(name, root):
|
||||
title, file, h = PAGES[name][1], PAGES[name][2], PAGES[name][3]
|
||||
html = body(name, True).replace("{accent}", "{{accent}}")
|
||||
doc = ('<!doctype html>\n<html lang="en">\n<head>\n<meta charset="utf-8">\n<title>StarshipOS.org — %s'
|
||||
'</title>\n<script src="./support.js"></script>\n</head>\n<body>\n<x-dc>\n<helmet>\n%s\n<style>\n'
|
||||
'body{margin:0;background:#0A1222}\na{color:#F5891F}a:hover{color:#FFB061}\n</style>\n</helmet>\n%s\n'
|
||||
'</x-dc>\n<script type="text/x-dc" data-dc-script data-props=\'{"accent":{"editor":"color","default":'
|
||||
'"#F5891F","options":["#F5891F","#5FD3C4","#8FB8FF"]},"$preview":{"width":1280,"height":%d}}\'>\n'
|
||||
'class Component extends DCLogic {\n renderVals() {\n return { accent: this.props.accent ?? '
|
||||
'\'#F5891F\' };\n }\n}\n</script>\n</body>\n</html>\n' % (title, FONTS, html, h))
|
||||
os.makedirs(os.path.join(root, "project"), exist_ok=True)
|
||||
with open(os.path.join(root, "project", file), "w") as f:
|
||||
f.write(doc)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
canvas_root = sys.argv[2] if len(sys.argv) > 2 and sys.argv[1] == "--canvas" else None
|
||||
for n in PAGES:
|
||||
write_wiki(n)
|
||||
if canvas_root:
|
||||
write_canvas(n, canvas_root)
|
||||
print("wrote", ", ".join("%s.WebHome.xwiki" % n for n in PAGES),
|
||||
"and the canvas artboards" if canvas_root else "")
|
||||
@@ -0,0 +1,26 @@
|
||||
{{velocity}}
|
||||
## Makes the inquiry class's fields, once. Run it by viewing this page as an administrator
|
||||
## (programming right); install.sh does. Viewing it again changes nothing.
|
||||
#if (!$hasProgramming)
|
||||
Needs the programming right.
|
||||
#else
|
||||
#set ($xdoc = $xwiki.getDocument('Inquiries.Code.InquiryClass').getDocument().clone())
|
||||
#set ($c = $xdoc.getXClass())
|
||||
#set ($changed = false)
|
||||
#if (!$c.get('name'))#set ($d = $c.addTextField('name', 'Name', 60))#set ($changed = true)#end
|
||||
#if (!$c.get('email'))#set ($d = $c.addTextField('email', 'Email', 60))#set ($changed = true)#end
|
||||
#if (!$c.get('organization'))#set ($d = $c.addTextField('organization', 'Organization', 60))#set ($changed = true)#end
|
||||
#if (!$c.get('topic'))#set ($d = $c.addTextField('topic', 'Topic', 60))#set ($changed = true)#end
|
||||
#if (!$c.get('message'))#set ($d = $c.addTextAreaField('message', 'Message', 80, 12))#set ($d = $c.get('message').setStringValue('contenttype', 'PureText'))#set ($changed = true)#end
|
||||
#if (!$c.get('announcements'))#set ($d = $c.addBooleanField('announcements', 'Wants announcements', 'yesno'))#set ($changed = true)#end
|
||||
#if (!$c.get('source'))#set ($d = $c.addTextField('source', 'Source', 60))#set ($changed = true)#end
|
||||
#if (!$c.get('status'))#set ($d = $c.addStaticListField('status', 'Status', 1, false, 'new|read|answered|closed'))#set ($changed = true)#end
|
||||
#if ($changed)
|
||||
#set ($d = $xdoc.setTitle('Inquiry class'))
|
||||
#set ($d = $xwiki.getXWiki().saveDocument($xdoc, 'The inquiry fields', $xcontext.getContext()))
|
||||
CLASS-SAVED
|
||||
#else
|
||||
CLASS-UNCHANGED
|
||||
#end
|
||||
#end
|
||||
{{/velocity}}
|
||||
@@ -0,0 +1,3 @@
|
||||
Every inquiry sent from the form on [[starshipos-f18.com>>https://starshipos-f18.com/bin/view/Inquiries/]], newest first. Open one for the whole message and to set its status. Only the administrator can see this space.
|
||||
|
||||
{{liveData id="inquiries" source="liveTable" sourceParameters="className=Inquiries.Code.InquiryClass&translationPrefix=" properties="doc.title,doc.creationDate,name,email,topic,status" sort="doc.creationDate:desc" limit="25"}}{{/liveData}}
|
||||
@@ -0,0 +1,26 @@
|
||||
{{velocity}}
|
||||
#set ($o = $doc.getObject('Inquiries.Code.InquiryClass'))
|
||||
#if (!$o)
|
||||
This page holds no inquiry.
|
||||
#else
|
||||
[[← All inquiries>>Inquiries.WebHome]]
|
||||
|
||||
|=Received|$escapetool.xml($xwiki.formatDate($doc.creationDate))
|
||||
|=Status|$doc.display('status', $o)
|
||||
|=Name|$doc.display('name', $o)
|
||||
|=Email|$doc.display('email', $o)
|
||||
|=Organization|$doc.display('organization', $o)
|
||||
|=Topic|$doc.display('topic', $o)
|
||||
|=Announcements|$doc.display('announcements', $o)
|
||||
|=Source|$doc.display('source', $o)
|
||||
|
||||
== Message ==
|
||||
|
||||
$doc.display('message', $o)
|
||||
|
||||
#if ($xcontext.action == 'view')
|
||||
## the e-mail is checked as plain characters when it arrives (PublicInquiry), and escaped here too
|
||||
{{html}}<p><a href="$escapetool.xml($doc.getURL('edit', 'editor=inline'))">Set its status</a>#if ("$!o.getProperty('email').value" != '') · <a href="mailto:$escapetool.xml($escapetool.url($o.getProperty('email').value).replace('%40','@'))">Reply by e-mail</a>#end</p>{{/html}}
|
||||
#end
|
||||
#end
|
||||
{{/velocity}}
|
||||
@@ -0,0 +1,41 @@
|
||||
{{velocity}}
|
||||
## Receives the inquiry form on starshipos-f18.com (POST) and files it as a page under
|
||||
## Inquiries.Entries, which only the administrator can read. It runs with this page's author's
|
||||
## rights (getDocumentAsAuthor, saveAsAuthor): a guest can reach nothing but this. Nothing a visitor
|
||||
## sends is ever written into this page's output or an entry's title: with this author's rights,
|
||||
## text that reached the wiki markup could run a macro.
|
||||
#macro (field $n $max)#set ($v = "$!request.getParameter($n)")#set ($v = $v.trim())#if ($v.length() > $max)#set ($v = $v.substring(0, $max))#end#end
|
||||
#if ($request.method != 'POST')
|
||||
This page receives the inquiry form on [[starshipos-f18.com>>https://starshipos-f18.com/bin/view/Inquiries/]].
|
||||
#else
|
||||
#field('website' 200)#set ($trap = $v)
|
||||
#field('name' 200)#set ($name = $v)
|
||||
#field('email' 200)#set ($email = $v)
|
||||
#field('organization' 200)#set ($org = $v)
|
||||
#field('topic' 100)#set ($topic = $v)
|
||||
#field('message' 10000)#set ($message = $v)
|
||||
#set ($wants = "$!request.getParameter('announcements')" != '')
|
||||
#if ($trap != '')
|
||||
## a robot filled the field people cannot see: say thanks, keep nothing
|
||||
{{html}}<p>Thank you. Your inquiry has been received.</p>{{/html}}
|
||||
#elseif ($name == '' || $message == '' || !$email.matches('^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'))
|
||||
{{html}}<p>Your inquiry was not sent: a name, a valid e-mail address and a message are needed. <a href="https://starshipos-f18.com/bin/view/Inquiries/">Back to the form</a>.</p>{{/html}}
|
||||
#else
|
||||
#set ($stamp = $datetool.format('yyyyMMdd-HHmmss', $datetool.date))
|
||||
#set ($ref = "Inquiries.Entries.I${stamp}-$mathtool.random(1000, 9999)")
|
||||
#set ($entry = $xwiki.getDocumentAsAuthor($ref))
|
||||
#set ($d = $entry.setTitle("Inquiry $stamp"))
|
||||
#set ($o = $entry.newObject('Inquiries.Code.InquiryClass'))
|
||||
#set ($d = $o.set('name', $name))
|
||||
#set ($d = $o.set('email', $email))
|
||||
#set ($d = $o.set('organization', $org))
|
||||
#set ($d = $o.set('topic', $topic))
|
||||
#set ($d = $o.set('message', $message))
|
||||
#if ($wants)#set ($d = $o.set('announcements', 1))#else#set ($d = $o.set('announcements', 0))#end
|
||||
#set ($d = $o.set('source', 'starshipos-f18.com'))
|
||||
#set ($d = $o.set('status', 'new'))
|
||||
#set ($d = $entry.saveAsAuthor('An inquiry from the .com form'))
|
||||
{{html}}<p>Thank you. Your inquiry has been received; every message is read by a human, and replies usually come within a few days.</p><p><a href="https://starshipos-f18.com/">Back to starshipos-f18.com</a></p>{{/html}}
|
||||
#end
|
||||
#end
|
||||
{{/velocity}}
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
#!/bin/bash
|
||||
# install.sh -- inquiries on the .org XWiki (Captain Bob, 2026-11-07: the .com's inquiries go to an
|
||||
# admin-only page on the .org, master/detail):
|
||||
#
|
||||
# Inquiries.WebPreferences view, edit, comment, delete: $ADMIN_USER alone -- made first
|
||||
# Inquiries.Code.InquiryClass the fields (made by Inquiries.Code.ClassSetup, viewed once as the
|
||||
# administrator: the class has no REST API), bound to the sheet
|
||||
# Inquiries.Code.InquirySheet the detail: one inquiry, its status set by editing the page
|
||||
# Inquiries.WebHome the master: every inquiry, newest first (a Live Data table)
|
||||
# Inquiries.Entries.I<time> one page per inquiry, made by PublicInquiry
|
||||
# PublicInquiry.WebHome public: the .com's form posts here; it files the inquiry with its
|
||||
# author's rights and thanks the visitor, echoing nothing they sent
|
||||
#
|
||||
# XWIKI_USER=rajames XWIKI_PASSWORD=... site/org/inquiries/install.sh [https://starshipos-f18.org]
|
||||
#
|
||||
# It ends by checking a guest's view, then sends one test inquiry as a guest, finds it as the
|
||||
# administrator, and deletes it.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
base=${1:-https://starshipos-f18.org}
|
||||
rest="$base/rest/wikis/xwiki"
|
||||
user=${XWIKI_USER:?set XWIKI_USER}
|
||||
pass=${XWIKI_PASSWORD:?set XWIKI_PASSWORD}
|
||||
admin=${ADMIN_USER:-XWiki.$user}
|
||||
auth=(-u "$user:$pass")
|
||||
|
||||
xml_page() { # xml_page <title> <file>
|
||||
python3 -c '
|
||||
import sys
|
||||
from xml.sax.saxutils import escape
|
||||
print("<page xmlns=\"http://www.xwiki.org\"><title>%s</title><syntax>xwiki/2.1</syntax>"
|
||||
"<content>%s</content></page>" % (escape(sys.argv[1]), escape(open(sys.argv[2]).read())))' "$1" "$2"
|
||||
}
|
||||
page() { # page <space path, a/b> <name> <title> <file>
|
||||
local spaces=${1//\//\/spaces\/}
|
||||
curl -fsS -o /dev/null -w " page ${1//\//.}.$2: %{http_code}\n" "${auth[@]}" -X PUT \
|
||||
-H 'Content-Type: application/xml' --data-binary "$(xml_page "$3" "$4")" "$rest/spaces/$spaces/pages/$2"
|
||||
}
|
||||
objects() { # objects <space path> <page> <class>: how many
|
||||
local spaces=${1//\//\/spaces\/}
|
||||
curl -fsS "${auth[@]}" -H 'Accept: application/json' "$rest/spaces/$spaces/pages/$2/objects/$3" |
|
||||
python3 -c 'import json,sys; print(len(json.load(sys.stdin).get("objectSummaries") or []))'
|
||||
}
|
||||
object() { # object <space path> <page> <class> <property=value>...: add one, as XML
|
||||
local spaces=${1//\//\/spaces\/} s=$1 p=$2 c=$3; shift 3
|
||||
local body
|
||||
body=$(python3 -c '
|
||||
import sys
|
||||
from xml.sax.saxutils import escape
|
||||
props = "".join("<property name=\"%s\"><value>%s</value></property>" % (escape(k), escape(v))
|
||||
for k, v in (a.split("=", 1) for a in sys.argv[2:]))
|
||||
print("<object xmlns=\"http://www.xwiki.org\"><className>%s</className>%s</object>" % (escape(sys.argv[1]), props))' "$c" "$@")
|
||||
curl -fsS -o /dev/null -w " ${s//\//.}.$p: $c added (%{http_code})\n" "${auth[@]}" -X POST \
|
||||
-H 'Content-Type: application/xml' --data-binary "$body" "$rest/spaces/$spaces/pages/$p/objects"
|
||||
}
|
||||
|
||||
echo "=== $base, as $user"
|
||||
echo "=== rights first: Inquiries is the administrator's alone"
|
||||
page Inquiries WebPreferences "Inquiries rights" /dev/null
|
||||
if [ "$(objects Inquiries WebPreferences XWiki.XWikiGlobalRights)" = 0 ]; then
|
||||
object Inquiries WebPreferences XWiki.XWikiGlobalRights \
|
||||
"levels=view,edit,comment,delete" "users=$admin" "groups=" "allow=1"
|
||||
else
|
||||
echo " rights there already, left as they are"
|
||||
fi
|
||||
|
||||
echo "=== the class, its sheet"
|
||||
page Inquiries/Code InquiryClass "Inquiry class" /dev/null
|
||||
page Inquiries/Code ClassSetup "Inquiry class setup" ClassSetup.xwiki
|
||||
out=$(curl -fsS "${auth[@]}" "$base/bin/view/Inquiries/Code/ClassSetup?basicauth=1")
|
||||
case "$out" in
|
||||
*CLASS-SAVED*) echo " the class's fields: made";;
|
||||
*CLASS-UNCHANGED*) echo " the class's fields: there already";;
|
||||
*) echo "install: the class setup did not run (programming right?)" >&2; exit 1;;
|
||||
esac
|
||||
page Inquiries/Code InquirySheet "Inquiry sheet" InquirySheet.xwiki
|
||||
if [ "$(objects Inquiries/Code InquiryClass XWiki.ClassSheetBinding)" = 0 ]; then
|
||||
object Inquiries/Code InquiryClass XWiki.ClassSheetBinding "sheet=Inquiries.Code.InquirySheet"
|
||||
else
|
||||
echo " sheet bound already"
|
||||
fi
|
||||
|
||||
echo "=== the master, and the public intake"
|
||||
page Inquiries WebHome "Inquiries" Inquiries.WebHome.xwiki
|
||||
page PublicInquiry WebHome "Inquiry" PublicInquiry.WebHome.xwiki
|
||||
|
||||
echo "=== as a guest"
|
||||
bad=
|
||||
for p in Inquiries:401 PublicInquiry:200; do
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' -H 'Accept: application/json' "$rest/spaces/${p%%:*}/pages/WebHome")
|
||||
if [ "$code" = "${p##*:}" ]; then echo " ${p%%:*}.WebHome: $code -- as it should be"
|
||||
else echo " ${p%%:*}.WebHome: $code -- NOT as it should be"; bad=1; fi
|
||||
done
|
||||
[ -z "$bad" ] || { echo "install: a guest's view is wrong; see above" >&2; exit 1; }
|
||||
|
||||
echo "=== a test inquiry, sent as a guest"
|
||||
reply=$(curl -fsS -X POST "$base/bin/view/PublicInquiry/" \
|
||||
--data-urlencode "name=install.sh test" --data-urlencode "email=test@example.org" \
|
||||
--data-urlencode "topic=General question" --data-urlencode "message=A test from site/org/inquiries/install.sh; it deletes this.")
|
||||
case "$reply" in *"has been received"*) echo " thanked";; *) echo "install: no thanks for the test" >&2; exit 1;; esac
|
||||
found=$(curl -fsS "${auth[@]}" -H 'Accept: application/json' "$rest/spaces/Inquiries/spaces/Entries/pages" |
|
||||
python3 -c '
|
||||
import json,sys
|
||||
print(" ".join(p["name"] for p in json.load(sys.stdin)["pageSummaries"]))')
|
||||
test_page=
|
||||
for n in $found; do
|
||||
if curl -fsS "${auth[@]}" -H 'Accept: application/json' \
|
||||
"$rest/spaces/Inquiries/spaces/Entries/pages/$n/objects/Inquiries.Code.InquiryClass/0/properties/name" |
|
||||
grep -q 'install.sh test'; then test_page=$n; fi
|
||||
done
|
||||
[ -n "$test_page" ] || { echo "install: the test inquiry was not filed" >&2; exit 1; }
|
||||
echo " filed as Inquiries.Entries.$test_page"
|
||||
curl -fsS -o /dev/null -w " deleted: %{http_code}\n" "${auth[@]}" -X DELETE \
|
||||
"$rest/spaces/Inquiries/spaces/Entries/pages/$test_page"
|
||||
echo "=== done: $base/bin/view/Inquiries/"
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
# install.sh -- the .org XWiki's three pages (Captain Bob, 2026-11-07): a landing page anyone can
|
||||
# read, an admin dashboard for the administrator alone, and a contributors' dashboard for the
|
||||
# group XWiki.StarshipContributors (and the administrator). Through XWiki's REST API:
|
||||
#
|
||||
# Main.WebHome Main.WebHome.xwiki rights untouched: the wiki's own (guests view)
|
||||
# Admin.WebHome Admin.WebHome.xwiki Admin.WebPreferences: view, edit, comment,
|
||||
# delete -- $ADMIN_USER alone
|
||||
# Contributors.WebHome Contributors.WebHome.xwiki Contributors.WebPreferences: view, comment --
|
||||
# XWiki.StarshipContributors and $ADMIN_USER;
|
||||
# edit, delete -- $ADMIN_USER
|
||||
# XWiki.StarshipContributors the group, created empty; members are added in the wiki's
|
||||
# administration (Users and Groups)
|
||||
#
|
||||
# An allow on a space denies that right there to everyone not named -- guests included.
|
||||
#
|
||||
# XWIKI_USER=rajames XWIKI_PASSWORD=... site/org/install.sh [https://starshipos-f18.org]
|
||||
#
|
||||
# Run it again after editing a page: pages are replaced, rights and the group are added once.
|
||||
# It ends by checking, without logging in, that the landing page is readable and the dashboards
|
||||
# are not.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
base=${1:-https://starshipos-f18.org}
|
||||
rest="$base/rest/wikis/xwiki"
|
||||
user=${XWIKI_USER:?set XWIKI_USER}
|
||||
pass=${XWIKI_PASSWORD:?set XWIKI_PASSWORD}
|
||||
admin=${ADMIN_USER:-XWiki.$user}
|
||||
group=XWiki.StarshipContributors
|
||||
auth=(-u "$user:$pass")
|
||||
|
||||
page() { # page <space> <name> <title> [file]: create or replace
|
||||
local body
|
||||
body=$(python3 -c '
|
||||
import sys
|
||||
from xml.sax.saxutils import escape
|
||||
title, path = sys.argv[1], sys.argv[2]
|
||||
content = open(path).read() if path else ""
|
||||
print("<page xmlns=\"http://www.xwiki.org\"><title>%s</title><syntax>xwiki/2.1</syntax>"
|
||||
"<content>%s</content></page>" % (escape(title), escape(content)))' "$3" "${4:-}")
|
||||
curl -fsS -o /dev/null -w " page $1.$2: %{http_code}\n" "${auth[@]}" -X PUT \
|
||||
-H 'Content-Type: application/xml' --data-binary "$body" "$rest/spaces/$1/pages/$2"
|
||||
}
|
||||
objects() { # objects <space> <page> <class>: how many the page has
|
||||
curl -fsS "${auth[@]}" -H 'Accept: application/json' "$rest/spaces/$1/pages/$2/objects/$3" |
|
||||
python3 -c 'import json,sys; print(len(json.load(sys.stdin).get("objectSummaries") or []))'
|
||||
}
|
||||
object() { # object <space> <page> <class> <property=value>...: add one
|
||||
# as XML: XWiki refuses a form-encoded POST without its form token (CSRF), not an XML one
|
||||
local s=$1 p=$2 c=$3; shift 3
|
||||
local body
|
||||
body=$(python3 -c '
|
||||
import sys
|
||||
from xml.sax.saxutils import escape
|
||||
props = "".join("<property name=\"%s\"><value>%s</value></property>" % (escape(k), escape(v))
|
||||
for k, v in (a.split("=", 1) for a in sys.argv[2:]))
|
||||
print("<object xmlns=\"http://www.xwiki.org\"><className>%s</className>%s</object>" % (escape(sys.argv[1]), props))' "$c" "$@")
|
||||
curl -fsS -o /dev/null -w " $s.$p: $c added (%{http_code})\n" "${auth[@]}" -X POST \
|
||||
-H 'Content-Type: application/xml' --data-binary "$body" "$rest/spaces/$s/pages/$p/objects"
|
||||
}
|
||||
|
||||
echo "=== $base, as $user"
|
||||
echo "=== the group $group"
|
||||
page XWiki StarshipContributors "Starship Contributors"
|
||||
if [ "$(objects XWiki StarshipContributors XWiki.XWikiGroups)" = 0 ]; then
|
||||
object XWiki StarshipContributors XWiki.XWikiGroups "member="
|
||||
else
|
||||
echo " already a group"
|
||||
fi
|
||||
|
||||
echo "=== rights"
|
||||
page Admin WebPreferences "Admin rights"
|
||||
if [ "$(objects Admin WebPreferences XWiki.XWikiGlobalRights)" = 0 ]; then
|
||||
object Admin WebPreferences XWiki.XWikiGlobalRights \
|
||||
"levels=view,edit,comment,delete" "users=$admin" "groups=" "allow=1"
|
||||
else
|
||||
echo " Admin: rights there already, left as they are"
|
||||
fi
|
||||
page Contributors WebPreferences "Contributors rights"
|
||||
if [ "$(objects Contributors WebPreferences XWiki.XWikiGlobalRights)" = 0 ]; then
|
||||
object Contributors WebPreferences XWiki.XWikiGlobalRights \
|
||||
"levels=view,comment" "users=$admin" "groups=$group" "allow=1"
|
||||
object Contributors WebPreferences XWiki.XWikiGlobalRights \
|
||||
"levels=edit,delete" "users=$admin" "groups=" "allow=1"
|
||||
else
|
||||
echo " Contributors: rights there already, left as they are"
|
||||
fi
|
||||
|
||||
echo "=== the pages -- after their spaces' rights, so a dashboard is never readable without them"
|
||||
page Main WebHome "StarshipOS" Main.WebHome.xwiki
|
||||
page Admin WebHome "Admin Dashboard" Admin.WebHome.xwiki
|
||||
page Contributors WebHome "Contributors' Dashboard" Contributors.WebHome.xwiki
|
||||
|
||||
echo "=== as a guest"
|
||||
bad=
|
||||
for p in Main Admin Contributors; do
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' -H 'Accept: application/json' "$rest/spaces/$p/pages/WebHome")
|
||||
case "$p:$code" in
|
||||
Main:200|Admin:401|Admin:403|Contributors:401|Contributors:403)
|
||||
echo " $p.WebHome: $code -- as it should be";;
|
||||
*) echo " $p.WebHome: $code -- NOT as it should be"; bad=1;;
|
||||
esac
|
||||
done
|
||||
[ -z "$bad" ] || { echo "install: a guest's view is wrong; see above" >&2; exit 1; }
|
||||
echo "=== done: $base/bin/view/Main/"
|
||||
@@ -56,6 +56,8 @@
|
||||
|
||||
#include "pkcs8_ed25519.h"
|
||||
#include "starkernel/ed25519.h"
|
||||
#include "starkernel/x509_ed25519.h"
|
||||
#include "starkernel/capsule_sig.h"
|
||||
|
||||
/*===========================================================================
|
||||
* xxHash64 (embedded for build tool — no external dependency)
|
||||
@@ -1575,6 +1577,34 @@ static int load_sign_key(const char *key_path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The signing key must be the one whose certificate the image carries
|
||||
* (CAPSULE_SIGNING_CERT_NAME): the kernel checks every signature against
|
||||
* that certificate, and refuses a signature that does not verify -- Mama's
|
||||
* own included. A key that is not the certificate's would build an image
|
||||
* that cannot boot, so refuse to build it. Returns 0 if they match. */
|
||||
static int check_sign_key_matches_cert(void) {
|
||||
uint8_t key_pub[32], cert_pub[32];
|
||||
ed25519_keygen(sign_seed, key_pub);
|
||||
for (int i = 0; i < capsule_count; i++) {
|
||||
if (strcmp(capsules[i].name, CAPSULE_SIGNING_CERT_NAME) != 0) continue;
|
||||
if (x509_extract_ed25519_pubkey(capsules[i].data, capsules[i].length, cert_pub) != 0) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: %s is not an Ed25519 certificate\n",
|
||||
CAPSULE_SIGNING_CERT_NAME);
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(key_pub, cert_pub, 32) != 0) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: the signing key is not %s's -- every "
|
||||
"capsule would fail its check at boot\n", CAPSULE_SIGNING_CERT_NAME);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "mkcapsule: signing key matches %s\n", CAPSULE_SIGNING_CERT_NAME);
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "mkcapsule: ERROR: --sign-key given, but no %s to check it against\n",
|
||||
CAPSULE_SIGNING_CERT_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/* --manifest mode: generate block ownership markdown. Optional
|
||||
* --sign-key <keyfile> prefix: mkcapsule --manifest [--sign-key
|
||||
@@ -1717,6 +1747,10 @@ int main(int argc, char **argv) {
|
||||
|
||||
fprintf(stderr, "mkcapsule: %d capsule(s) collected\n", capsule_count);
|
||||
|
||||
if (have_sign_seed && check_sign_key_matches_cert() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *out = fopen(output_path, "w");
|
||||
if (!out) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: cannot create '%s'\n", output_path);
|
||||
|
||||
+4
-2
@@ -173,10 +173,12 @@ RUN_amd64 ?=
|
||||
RUN_aarch64 ?= qemu-aarch64
|
||||
RUN_riscv64 ?= qemu-riscv64
|
||||
|
||||
SIGN_KEY ?= /home/rajames/CLionProjects/lithosananke-ca/intermediate/snakeoil-intermediate.key
|
||||
# as kernel/Makefile: CI sets SIGN_KEY; unset, the capsules are built unsigned
|
||||
SIGN_KEY ?=
|
||||
SIGN_KEY_ARGS = $(if $(wildcard $(SIGN_KEY)),--sign-key $(SIGN_KEY),)
|
||||
CRYPTO_SRCS := $(addprefix $(ROOT)/kernel/src/crypto/,ed25519.c fe25519.c scalar25519.c sha512.c)
|
||||
MKCAPSULE_SRCS := $(ROOT)/tools/mkcapsule.c $(ROOT)/tools/pkcs8_ed25519.c $(CRYPTO_SRCS)
|
||||
MKCAPSULE_SRCS := $(ROOT)/tools/mkcapsule.c $(ROOT)/tools/pkcs8_ed25519.c $(CRYPTO_SRCS) \
|
||||
$(ROOT)/kernel/src/crypto/x509_ed25519.c
|
||||
CAPSULE_FILES := $(shell find $(ROOT)/capsules -type f ! -name '.*' 2>/dev/null)
|
||||
CAPSULE_DIR_C := $(BINDIR)/capsule_generated.c
|
||||
MACHINE_64 := $(BINDIR)/rom-64.c $(BINDIR)/v4_map_64.c
|
||||
|
||||
Reference in New Issue
Block a user