Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions .fallowrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@

"packages/alistigo-*",
"cli/alistigo-*",
"packages/artifact-storage-explorer"
"packages/artifact-storage-explorer",
"websites/storybook",
"websites/alistigo/**"
],
"dynamicallyLoaded": [
"**/*.test.{ts,tsx}",
"**/tests/**/*.{ts,tsx}",
"**/*.stories.{ts,tsx}",
"cli/list-features-runner-playwright/src/support/hooks.ts",
"cli/list-features-runner-playwright/src/support/world.ts",
"cli/list-features-runner-playwright/src/pages/application.page.ts",
Expand All @@ -64,7 +67,14 @@
"gherklin",
"@cucumber/pretty-formatter",
"@lingui/format-po",
"@emotion/is-prop-valid"
"@emotion/is-prop-valid",
"astro",
"@astrojs/starlight",
"sharp",
"storybook",
"@storybook/react-vite",
"react",
"react-dom"
],
"duplicates": {
"minOccurrences": 3
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ pnpm build:typecheck # Type-check all packages
pnpm test # Run all tests
```

## Server Mode

The repo can run on a remote server for persistent AI-agent sessions (Claude in tmux, accessible from anywhere). Use the `server:*` commands to manage background dev processes via PM2:

| Command | What it does |
|---------|-------------|
| `pnpm server:start:dev` | Start playground, website, and storybook as background daemons |
| `pnpm server:kill-all` | Stop and remove all background dev processes |
| `pnpm server:status` | Show status of all managed processes |
| `pnpm server:logs` | Tail logs from all processes |
| `pnpm server:restart` | Restart all running processes (e.g. after a branch switch) |
| `pnpm server:install-service` | Install a systemd user service that auto-starts dev on login/boot |

See [ADR 0030](packages/architecture/adrs/0030-pm2-server-dev-mode.md) for the rationale.

## Quality Assurance

All static analysis and linting tools follow the `qa:*` prefix — keeping QA commands grouped and discoverable, separate from build/run/test commands.
Expand Down
19 changes: 0 additions & 19 deletions apps/alistigo-artifact-playground/.storybook/main.ts

This file was deleted.

16 changes: 0 additions & 16 deletions apps/alistigo-artifact-playground/.storybook/preview.tsx

This file was deleted.

1 change: 0 additions & 1 deletion apps/alistigo-artifact-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^4.3.4",
"storybook": "^10.3.0",
"tailwindcss": "^4.0.0",
"vite": "^7.0.0"
}
Expand Down
15 changes: 0 additions & 15 deletions apps/alistigo-artifact-playground/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,6 @@
"command": "rm -rf dist",
"cwd": "apps/alistigo-artifact-playground"
}
},
"storybook": {
"executor": "nx:run-commands",
"options": {
"command": "storybook dev -p 6007",
"cwd": "apps/alistigo-artifact-playground"
}
},
"build-storybook": {
"executor": "nx:run-commands",
"outputs": ["{projectRoot}/storybook-static"],
"options": {
"command": "storybook build",
"cwd": "apps/alistigo-artifact-playground"
}
}
}
}
18 changes: 15 additions & 3 deletions apps/alistigo-artifact-playground/src/buildIframeSrcdoc.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import claudeBridgeHtml from "@alistigo/claude-artifact-api/inject-script.html?raw";
import type { Config } from "./hooks/useHostConfig";

const _devHost = typeof __ALISTIGO_DEV_HOSTNAME__ !== "undefined" ? __ALISTIGO_DEV_HOSTNAME__ : "";
const _devHostOrigins = _devHost ? [`http://${_devHost}:*`, `ws://${_devHost}:*`] : [];

export const SRCDOC_CSP = [
"default-src 'none'",
"script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net http://localhost:* http://127.0.0.1:*",
[
"script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net",
"http://localhost:* http://127.0.0.1:*",
..._devHostOrigins.slice(0, 1),
].join(" "),
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: blob:",
"font-src 'self' data:",
"connect-src 'self' http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*",
"frame-src 'self' http://localhost:* http://127.0.0.1:*",
[
"connect-src 'self' http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*",
..._devHostOrigins,
].join(" "),
["frame-src 'self' http://localhost:* http://127.0.0.1:*", ..._devHostOrigins.slice(0, 1)].join(
" ",
),
"worker-src blob:",
"media-src 'self' blob:",
].join("; ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const meta: Meta<typeof ArtifactViewPanel> = {
title: "Playground/ArtifactViewPanel",
component: ArtifactViewPanel,
parameters: { layout: "fullscreen" },
tags: ["playground"],
decorators: [
(Story) => (
<div style={{ height: "100vh", display: "flex" }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const meta: Meta<typeof ClaudeSimulator> = {
title: "Components/ClaudeSimulator",
component: ClaudeSimulator,
parameters: { layout: "fullscreen" },
tags: ["playground"],
args: {
aiContext: "",
simulatorDelayMs: 500,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const meta: Meta<typeof ConfigFormArtifact> = {
title: "Playground/ConfigFormArtifact",
component: ConfigFormArtifact,
parameters: { layout: "centered" },
tags: ["playground"],
};

export default meta;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const meta: Meta<typeof ConfigFormListArtifact> = {
title: "Playground/ConfigFormListArtifact",
component: ConfigFormListArtifact,
parameters: { layout: "centered" },
tags: ["playground"],
};

export default meta;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const meta: Meta<typeof HostForm> = {
title: "Playground/HostForm",
component: HostForm,
parameters: { layout: "fullscreen" },
tags: ["playground"],
decorators: [
(Story) => (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const meta: Meta<typeof HostPage> = {
title: "Dev/HostPage",
component: HostPage,
parameters: { layout: "fullscreen" },
tags: ["playground"],
};

export default meta;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const meta: Meta<typeof SourceView> = {
title: "Playground/SourceView",
component: SourceView,
parameters: { layout: "fullscreen" },
tags: ["playground"],
decorators: [
(Story) => (
<div style={{ height: "100vh" }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const meta: Meta<typeof StorageExplorer> = {
title: "Playground/StorageExplorer",
component: StorageExplorer,
parameters: { layout: "fullscreen" },
tags: ["playground"],
decorators: [
(Story) => (
<div style={{ height: "400px", display: "flex", border: "1px solid #e5e7eb" }}>
Expand Down
3 changes: 3 additions & 0 deletions apps/alistigo-artifact-playground/src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ declare const __ALISTIGO_LOCALE__: string;
/** Package name -> absolute filesystem path to its src/index.ts, dev only. */
declare const __ALISTIGO_DEV_PLUGIN_SRC_PATHS__: Record<string, string>;

/** Hostname baked in at dev-server time for Tailscale/LAN CSP expansion; empty string in production. */
declare const __ALISTIGO_DEV_HOSTNAME__: string;

/**
* Per-locale Lingui catalog, resolved by Vite via an alias to the
* compiled `.po` for the active LOCALE. See `src/i18n.ts`.
Expand Down
7 changes: 5 additions & 2 deletions apps/alistigo-artifact-playground/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* 3. Add a `build:<new>` target in this app's project.json.
*/

import os from "node:os";
import path, { resolve } from "node:path";
import linguiMacro from "@lingui/babel-plugin-lingui-macro";
import { lingui } from "@lingui/vite-plugin";
Expand Down Expand Up @@ -65,7 +66,7 @@ const componentsPackageRoot = path.resolve(__dirname, "../../packages/list-compo

const activeCatalogPath = path.join(componentsPackageRoot, `src/locales/${LOCALE}/messages.po`);

export default defineConfig({
export default defineConfig(({ command }) => ({
base: "./", // relative paths — required for GitHub Pages subpath deployment
plugins: [
{
Expand Down Expand Up @@ -98,10 +99,12 @@ export default defineConfig({
define: {
__ALISTIGO_LOCALE__: JSON.stringify(LOCALE),
__ALISTIGO_DEV_PLUGIN_SRC_PATHS__: JSON.stringify(devPluginSrcPaths),
__ALISTIGO_DEV_HOSTNAME__: JSON.stringify(command === "serve" ? os.hostname() : ""),
},
server: {
port: 5173,
strictPort: false,
allowedHosts: [os.hostname(), `${os.hostname()}.local`],
},
build: {
outDir: `dist/${LOCALE}`,
Expand All @@ -118,4 +121,4 @@ export default defineConfig({
},
},
},
});
}));
2 changes: 2 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ post-checkout:
commands:
install-deps:
run: if [ "{3}" = "1" ] && git diff {1} {2} --name-only 2>/dev/null | grep -qE 'package\.json|pnpm-lock\.yaml'; then pnpm install; fi
restart-dev:
run: if [ "{3}" = "1" ] && pnpm exec pm2 list 2>/dev/null | grep -q 'online'; then echo "Branch switched — restarting dev services..." && pnpm exec pm2 restart all; fi

commit-msg:
commands:
Expand Down
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
"qa:lint": "nx run-many -t qa:lint",
"qa:arch-check": "depcruise apps packages cli --config .dependency-cruiser.cjs",
"qa:arch-calm": "nx run architecture:qa:arch-calm",
"server:start:dev": "pm2 start pm2.ecosystem.config.cjs",
"server:kill-all": "pm2 delete all 2>/dev/null; true",
"server:status": "pm2 status",
"server:logs": "pm2 logs",
"server:restart": "pm2 restart all",
"server:install-service": "bash scripts/install-dev-service.sh",
"qa:dead-code": "fallow dead-code",
"qa:audit": "fallow audit",
"qa:stories-check": "bash scripts/check-stories.sh",
Expand All @@ -36,12 +42,12 @@
"i18n:extract:clean": "lingui extract --clean",
"i18n:compile": "lingui compile",
"agent:dailylife": "bun apps/dailylife-cli/src/index.ts",
"kill": "lsof -ti :5173,:5174 | xargs kill -9 2>/dev/null; true",
"validate:file": "bun scripts/validate-file.ts",
"prepare": "if [ -d .git ]; then git config --unset-all core.hooksPath 2>/dev/null; lefthook install; fi"
},
"devDependencies": {
"@biomejs/biome": "2.4.6",
"pm2": "^5.4.0",
"@finos/calm-cli": "^1.58.0",
"@finos/calm-schema": "^1.2.0",
"@finos/calm-server": "^0.4.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# ADR 0029 — Alistigo.com Public Website via Astro Starlight

**Status:** Accepted
**Date:** 2026-09-09

## Context

Alistigo needed a public-facing website at `www.alistigo.com` to document the platform architecture, list architecture decisions, and provide an embedded playground. The site must be:
- Fast and static-first (no server required in prod)
- Developer-friendly (docs in Markdown/MDX)
- Consistent with the Holos monorepo tooling

## Decision

Use **Astro 5** with the **Starlight** documentation theme. The site lives in `websites/alistigo/` in the Holos monorepo and is registered as a pnpm workspace package.

**Key configuration:**
- Dark theme default
- 3 sidebar sections: Platform, Architecture Decisions, Playground
- GitHub social link to `https://github.com/alistigo/holos`
- Canonical URL: `https://www.alistigo.com`

**Local dev:** served via PM2 (`pnpm exec astro dev --host 0.0.0.0`) at port 4321.

## Alternatives Considered

- **Docusaurus** — rejected; heavier JS bundle, less Astro-native
- **VitePress** — rejected; Vue-centric, not aligned with React stack
- **Plain Astro (no Starlight)** — rejected; Starlight provides out-of-the-box search, TOC, sidebar, dark mode

## Consequences

- `pnpm-workspace.yaml` must include `websites/*` for pnpm to recognize the site as a workspace package
- The Starlight site is a separate pnpm workspace package (`@alistigo/alistigo-website`)
- PM2 starts the site alongside the artifact playground in dev mode
51 changes: 51 additions & 0 deletions packages/architecture/adrs/0030-pm2-server-dev-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# ADR 0030 — PM2 Server Dev Mode

**Status:** Accepted
**Date:** 2026-09-14

## Context

The repository runs on a remote Linux server (accessed via VS Code Remote / Codespace) to support long-lived Claude AI sessions in tmux. Dev servers — playground (Vite), website (Astro), and Storybook — need to:

- Outlive SSH disconnects without being killed
- Survive branch switches (restart automatically when the branch changes)
- Auto-restart on crash without manual intervention
- Be accessible over LAN/Tailscale from other devices

The existing `pnpm dev` command runs foreground processes tied to the terminal session — suitable for local development, not for persistent server use.

## Decision

Use **PM2** as the background process manager for server-mode dev. Introduce a `server:*` script namespace in the root `package.json` to make server-mode commands clearly distinct from the `dev` foreground command. Provide `server:install-service` to install a systemd user service for boot-time persistence.

The PM2 ecosystem config lives at `pm2.ecosystem.config.cjs` (CJS required — PM2 does not support ESM config files).

All managed processes use `interpreter: "none"` because `pnpm` is a bash script, not a Node.js file — PM2 would otherwise try to run it through Node.js and fail with a syntax error.

All processes bind to `--host 0.0.0.0` for LAN/Tailscale accessibility.

## Rationale

- **Named processes** — `pm2 status` gives a clear live view of all running services
- **Crash restart** — `autorestart: true` handles unexpected failures
- **Unified logs** — `pm2 logs` streams all processes; individual logs at `~/.pm2/logs/`
- **No Docker overhead** — Docker adds networking complexity for a single-developer server setup
- **`server:` prefix** — keeps these scripts clearly separated from the local-dev `pnpm dev` workflow; discoverability via `pnpm run | grep server`

The systemd user service (`scripts/install-dev-service.sh`) enables boot-time persistence without `sudo`. It uses `Type=oneshot` + `RemainAfterExit=yes` because PM2 daemonizes itself and the start command exits immediately — `Type=forking` is incorrect here. The service installer injects the mise shims directory into `Environment=PATH=` because systemd does not source shell profiles.

## Consequences

- New root devDependency: `pm2 ^5.4.0`
- `.cjs` config file at repo root (cannot be ESM)
- `loginctl enable-linger <user>` needed for true boot-without-login persistence (service installer calls it automatically, with a fallback message if unavailable)
- `websites/alistigo` and `websites/storybook` must exist for those PM2 processes to start; `playground` works independently

## Alternatives Rejected

| Option | Why rejected |
|--------|-------------|
| `nohup <cmd> &` | No crash restart, no log management, no status dashboard |
| tmux session | Lost on server reboot; manual reconnect required |
| Docker Compose | Networking overhead; port mapping complexity; overkill for a solo dev server |
| systemd unit per process | More boilerplate; PM2 already provides the daemon layer cleanly |
2 changes: 2 additions & 0 deletions packages/architecture/adrs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ This directory contains architectural decisions for the Holos monorepo — both
| [0026](0026-alistigo-document-format-jsonld-schemaorg.md) | Alistigo Document Format: JSON-LD + schema.org Foundation and Package Standard | Accepted | 2026-08-29 |
| [0027](0027-architecture-as-code-calm.md) | Architecture as Code: Adopting CALM (Common Architecture Language Model) | Accepted | 2026-09-04 |
| [0028](0028-package-first-repository-structure.md) | Package-First Repository Structure | Accepted | 2026-09-08 |
| [0029](0029-alistigo-website-astro-starlight.md) | Alistigo.com Public Website via Astro Starlight | Accepted | 2026-09-09 |
| [0030](0030-pm2-server-dev-mode.md) | PM2 Server Dev Mode | Accepted | 2026-09-14 |
Loading
Loading