Skip to content
Open

Main #871

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
2cd9172
feat: establish authenticated Pod 4 unified sleep foundation
lucaandrea Oct 25, 2026
91f9eae
fix: align Autopilot status and fixtures with explicit owner access
lucaandrea Oct 25, 2026
d5b160e
feat: add bounded personal comfort proposals to shared arbitration
lucaandrea Oct 25, 2026
b25014f
feat: expose authenticated controller capabilities and freshness
lucaandrea Oct 25, 2026
9fe4c52
fix: preserve extensible client capability field types
lucaandrea Oct 25, 2026
6b51f04
feat: add persisted personal comfort Preview and manual pauses
lucaandrea Oct 25, 2026
70e96a0
fix: validate comfort startup and pending Autopilot status
lucaandrea Oct 25, 2026
5767b40
fix: withdraw automation policies when sensor inputs become unavailable
lucaandrea Oct 25, 2026
a016342
fix: keep personal comfort unavailable in the demo
lucaandrea Oct 25, 2026
3c3dccd
Merge pull request #1 from lucaandrea/lucas-assistant/unified-sleep
lucaandrea Oct 25, 2026
9ff9cd3
feat: stage verified Free Sleep migrations with overnight schedules
lucaandrea Oct 25, 2026
e76ea6b
fix: preserve overnight shutdown when copying schedules
lucaandrea Oct 25, 2026
50782ab
Merge pull request #2 from lucaandrea/lucas-assistant/unified-sleep
lucaandrea Oct 25, 2026
eeb8b49
feat: preserve complete overnight bedtime routines
lucaandrea Oct 25, 2026
5201916
test: pin bedtime routine schema in database contracts
lucaandrea Oct 25, 2026
7af9f07
feat: persist expiring control requests without replaying uncertain w…
lucaandrea Oct 25, 2026
151ba43
Merge pull request #3 from lucaandrea/lucas-assistant/bedtime-routines
lucaandrea Oct 25, 2026
8015c0a
Merge remote-tracking branch 'origin/main' into lucas-assistant/contr…
lucaandrea Oct 25, 2026
b00cc48
Merge pull request #4 from lucaandrea/lucas-assistant/control-receipts
lucaandrea Oct 25, 2026
8f5fccd
feat: preserve per-alarm snooze settings across overnight routines
lucaandrea Oct 25, 2026
0389b09
feat: add a schedule library while preserving imported overnight rout…
lucaandrea Oct 25, 2026
94e35ad
feat: import Apple Watch breathing and SDNN as separate references
lucaandrea Oct 25, 2026
d99902b
feat: align the web shell with SleepyPod and render the bed offline
lucaandrea Oct 25, 2026
afa4865
feat: prepare isolated offline ARM64 runtime bundles for Pod migration
lucaandrea Oct 25, 2026
399bd7b
Merge pull request #5 from lucaandrea/lucas-assistant/alarm-snooze
lucaandrea Oct 25, 2026
0051feb
fix: probe the image dependency from Next package scope
lucaandrea Oct 25, 2026
f9d73d9
feat: add the schedule library with overnight routine protection (#6)
lucaandrea Oct 25, 2026
22cbb26
feat: add distinct Apple Watch breathing and SDNN references (#7)
lucaandrea Oct 25, 2026
64143f4
feat: align the web shell with SleepyPod and render the bed offline (#8)
lucaandrea Oct 25, 2026
2b32707
fix: align biometric dependency identity with the secured runtime
lucaandrea Oct 25, 2026
43e8023
fix: regenerate demo identity after dependency fingerprint update
lucaandrea Oct 25, 2026
8f1a54f
feat: add side-owned personal stage models with explicit activation
lucaandrea Oct 25, 2026
f609c2e
fix: include verified runtime dependency identity
lucaandrea Oct 25, 2026
4191919
feat: stage verified offline ARM64 runtimes without replacing Free Sleep
lucaandrea Oct 25, 2026
e473fc4
fix: declare and probe real sensor runtime dependencies
lucaandrea Oct 25, 2026
c8f3423
fix: incorporate merged offline runtime validation
lucaandrea Oct 25, 2026
c24e70c
feat: add personal sleep models with explicit selection and rules fal…
lucaandrea Oct 25, 2026
bbf364a
Merge remote-tracking branch 'origin/main' into lucas-assistant/contr…
lucaandrea Oct 25, 2026
fa34fed
fix: install and verify the real sensor runtime dependencies
lucaandrea Oct 25, 2026
7c0338d
Merge remote-tracking branch 'origin/main' into lucas-assistant/contr…
lucaandrea Oct 25, 2026
28822bc
feat: rehearse controller handoff with automatic legacy restoration
lucaandrea Oct 25, 2026
38a501c
feat: rehearse controller handoff with automatic legacy restoration
lucaandrea Oct 25, 2026
6a6ba44
fix: provide timezone data for offline Pod migration (#13)
lucaandrea Oct 25, 2026
9d9e39a
fix: keep idle Pod sides off during controller handoff (#14)
lucaandrea Oct 25, 2026
2623663
feat: add guarded permanent controller activation (#15)
lucaandrea Oct 26, 2026
427ed33
fix: preserve firmware time in live vital estimates (#16)
lucaandrea Oct 26, 2026
01550dd
fix: align prospective biometrics with live firmware time (#17)
lucaandrea Oct 26, 2026
a08f6fd
fix: exclude mechanical interference from live biometrics (#18)
lucaandrea Oct 26, 2026
ca66e18
fix: guard MQTT commands with durable receipts and expiry (#19)
lucaandrea Oct 26, 2026
f77502b
fix: publish qualified home telemetry with explicit availability (#20)
lucaandrea Oct 26, 2026
894682b
feat: add qualified personal baseline to comfort Preview (#21)
lucaandrea Oct 26, 2026
a76d5a7
fix: keep HomeKit state fresh and prevent stale slider power-ons (#22)
lucaandrea Oct 26, 2026
ce5ed1d
fix: enforce MQTT TLS requirements before connecting (#23)
lucaandrea Oct 26, 2026
6452f3f
fix: separate service restarts from software updates (#24)
lucaandrea Oct 26, 2026
6cae1c8
fix: add restricted controller maintenance broker (#25)
lucaandrea Oct 26, 2026
ae8090b
fix: provision restricted maintenance with recoverable rollback
lucaandrea Oct 26, 2026
ad6baf7
fix: handle systemd socket state during maintenance setup
lucaandrea Oct 26, 2026
7fa390a
feat: deliver persistent automation alerts in the owner inbox
lucaandrea Oct 26, 2026
cbb0e5b
feat: integrate timestamped Home Assistant room measurements
lucaandrea Oct 26, 2026
9ca0847
fix: recover committed experiments after dataset release
lucaandrea Oct 26, 2026
8572ba1
fix: accept complete multi-metric subgroup reports
lucaandrea Oct 26, 2026
488982a
fix: keep SleepyPod controls accessible with enlarged text
lucaandrea Oct 26, 2026
e6ace9f
fix: preserve the installed repository across Pod updates
lucaandrea Oct 26, 2026
cc8d4d0
feat: preview routine timing from observed bed entry
lucaandrea Oct 26, 2026
0bf11ea
feat: add per-night Preview reports and owner review
lucaandrea Oct 26, 2026
d955dda
fix: keep overnight previews on scheduler calendar dates
lucaandrea Oct 26, 2026
88cbee4
fix: preserve alarm hold across simultaneous power-off
lucaandrea Oct 26, 2026
27736f9
Merge pull request #37 from lucaandrea/lucas-assistant/alarm-power-bo…
lucaandrea Oct 26, 2026
679f941
feat: preserve imported sleep history in source-labelled views
lucaandrea Oct 26, 2026
5297048
feat: preserve imported sleep history in source-labelled views
lucaandrea Oct 26, 2026
7e373fa
feat: restore full morning journal and atomic comfort mode (#39)
lucaandrea Oct 26, 2026
f0c40fa
feat: preserve routines when changing the next alarm (#40)
lucaandrea Oct 26, 2026
ccafceb
feat: add disabled Home Assistant house templates (#41)
lucaandrea Oct 26, 2026
5c7601d
feat: record shared-controller temperature application evidence (#42)
lucaandrea Oct 26, 2026
87ec31f
feat: add guarded personal comfort execution adapter
lucaandrea Oct 26, 2026
41d6f93
feat: qualify owner activation of personal comfort
lucaandrea Oct 26, 2026
c105621
feat: prepare quiesced imports with retained-controller recovery
lucaandrea Oct 26, 2026
f86e9b5
fix: require complete imported history before activation (#46)
lucaandrea Oct 26, 2026
82ec540
feat: add bedroom sensor context to personal comfort and web controls
lucaandrea Oct 27, 2026
e1ff08e
test: cover bedroom schema and shared transport integration
lucaandrea Oct 27, 2026
4af9480
test: follow the retained room mapping disclosure in browser checks
lucaandrea Oct 27, 2026
a0dfa35
Merge pull request #47 from lucaandrea/lucas-assistant/bedroom-sensor…
lucaandrea Oct 27, 2026
2bf775d
feat: preserve active Core data during verified release updates
lucaandrea Oct 27, 2026
d8c3cfc
fix: verify stopped maintenance sockets without a process ID
lucaandrea Oct 27, 2026
067c60f
feat: add a restricted publisher for Homebridge bedroom caches
lucaandrea Oct 27, 2026
fa465bd
test: exercise publisher installation on an isolated Windows runner
lucaandrea Oct 27, 2026
013cf96
Merge pull request #48 from lucaandrea/lucas-assistant/bedroom-publis…
lucaandrea Oct 27, 2026
21b7172
fix: assign the publisher key to SYSTEM with separate ACL operations
lucaandrea Oct 27, 2026
6222c60
Merge remote-tracking branch 'origin/main' into lucas-assistant/bedro…
lucaandrea Oct 27, 2026
b8c3478
Merge pull request #49 from lucaandrea/lucas-assistant/bedroom-publis…
lucaandrea Oct 27, 2026
55fd80f
fix: resume an interrupted bedroom publisher installation safely
lucaandrea Oct 27, 2026
1cfa62f
Merge pull request #50 from lucaandrea/lucas-assistant/bedroom-publis…
lucaandrea Oct 27, 2026
b993e51
fix: show last-reported bedroom readings separately from live context
lucaandrea Oct 27, 2026
2ddaa90
fix: sample the current clock when bedroom reports arrive
lucaandrea Oct 27, 2026
a9043d2
feat: add scoped Apple Home climate export blueprints
lucaandrea Oct 27, 2026
036b09d
Merge pull request #51 from lucaandrea/lucas-assistant/bedroom-last-r…
lucaandrea Oct 27, 2026
0f61bbe
Merge pull request #52 from lucaandrea/lucas-assistant/homepod-sensor…
lucaandrea Oct 27, 2026
4688ffe
feat: qualify live Govee bedroom sensor reads
lucaandrea Oct 27, 2026
27a06a0
feat: read live Govee appliance power states
lucaandrea Oct 27, 2026
8d0ad5c
fix: improve sleep totals, MQTT reliability and contextual comfort le…
lucaandrea Oct 29, 2026
8cd1677
Merge pull request #55 from lucaandrea/lucas-assistant/sleep-reliability
lucaandrea Oct 29, 2026
8c1ff71
Show constant bedtime routines in schedule timelines
lucaandrea Oct 29, 2026
10bde60
Merge pull request #56 from lucaandrea/lucas-assistant/constant-routi…
lucaandrea Oct 29, 2026
081296d
fix: keep sleep-stage estimates within recorded time
lucaandrea Oct 29, 2026
3224b03
Merge pull request #57 from lucaandrea/lucas-assistant/stage-coverage
lucaandrea Oct 29, 2026
5469d12
fix(docs): clarify sleep-learning validation requirements
lucaandrea Oct 29, 2026
25f8051
Merge pull request #58 from lucaandrea/lucas-assistant/reliability-ev…
lucaandrea Oct 29, 2026
3987d8c
fix(ci): authenticate OpenAPI schema exports (#59)
lucaandrea Oct 29, 2026
938070e
fix(comfort): preserve qualification across bounded baseline drift (#60)
lucaandrea Oct 29, 2026
5d06dc5
fix(ci): install locked runtimes for release hooks
lucaandrea Oct 29, 2026
b149de2
fix(qualification): rehearse bounded offline routine trials
lucaandrea Oct 29, 2026
dc5d3ea
feat: prepare private household accounts and onboarding (#63)
lucaandrea Oct 29, 2026
fa6ead0
feat(household): preserve dated ownership of sleep records (#64)
lucaandrea Oct 29, 2026
bc2f813
fix(comfort): follow the sole sleeper across both sensor zones (#65)
lucaandrea Oct 29, 2026
c53e1ec
feat: guard personal bed commands by sleeper assignment (#66)
lucaandrea Oct 29, 2026
0d395ab
docs: record household readiness and wake routing limits (#67)
lucaandrea Oct 29, 2026
86d1a2a
feat: add private personal bed controls and atomic routine storage (#68)
lucaandrea Oct 29, 2026
cccf671
feat: publish personal routines through a reviewed atomic save (#69)
lucaandrea Oct 30, 2026
ce86d15
feat: add isolated personal web controls and reviewed routine publish…
lucaandrea Oct 30, 2026
896da98
fix: stop private responses after browser account changes (#71)
lucaandrea Oct 30, 2026
4c1745d
feat: preserve personal privacy after household assignment (#72)
lucaandrea Oct 30, 2026
f0569a4
feat: add private shared-side review and independent approvals (#73)
lucaandrea Oct 30, 2026
65c81b8
fix: protect personal households during controller maintenance
lucaandrea Oct 30, 2026
db9cfb0
feat: add person-owned recording history API (#75)
lucaandrea Oct 30, 2026
cdd8bb8
feat: add private recording history to personal web workspace (#76)
lucaandrea Oct 30, 2026
f483c9c
fix: collect trustworthy thermal learning evidence during Preview (#77)
lucaandrea Oct 30, 2026
e397a3c
feat(home-assistant): add Core-native Pod dashboard (#78)
lucaandrea Oct 31, 2026
e6cc23e
feat: fit on-Pod comfort models from complete reviewed nights (#79)
lucaandrea Nov 2, 2026
c63ece8
feat: add reviewed-night water response forecasting
lucaandrea Nov 2, 2026
de23642
Merge pull request #80 from lucaandrea/lucas-assistant/thermal-respon…
lucaandrea Nov 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ docs/images/*.gif filter=lfs diff=lfs merge=lfs -text

# Web assets ship in source tarballs (sp-update, release), which never resolve LFS pointers.
public/** !filter !diff !merge binary

# Hand-authored household UI must retain readable reviews and three-way merges.
public/household/*.html text diff merge
public/household/*.js text diff merge
public/household/*.css text diff merge
6 changes: 6 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ echo "→ Drizzle schema validation..."
pnpm drizzle-kit check
pnpm drizzle-kit check --config=drizzle.biometrics.config.ts

echo "→ Offline migration tests..."
uv run --project scripts/migration --frozen python -m unittest discover -s scripts/migration -p 'test_*.py'
python3 -m unittest discover -s scripts/deployment -p 'test_*.py'
python3 -m unittest discover -s scripts/bedroom -p 'test_*.py'
node --test scripts/bedroom/homebridge-cache.test.mjs

CHANGED=$(git diff --name-only @{push}.. -- '*.ts' '*.tsx' 2>/dev/null || git diff --name-only origin/dev...HEAD -- '*.ts' '*.tsx' 2>/dev/null || true)
if [ -n "$CHANGED" ]; then
echo "→ Tests (changed files)..."
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/bedroom-windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Bedroom Windows installer

on:
pull_request:
paths: ['scripts/bedroom/**', '.github/workflows/bedroom-windows.yml']
workflow_dispatch:

permissions:
contents: read

jobs:
installer:
runs-on: windows-2025
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
- name: Validate the Windows PowerShell 5.1 installation
shell: powershell
run: ./scripts/bedroom/Test-WindowsInstaller.ps1
- name: Validate the isolated sensor-reader installation
shell: powershell
run: ./scripts/bedroom/Test-GoveeInstaller.ps1
- name: Test appliance power installation and handoff
shell: powershell
run: ./scripts/bedroom/Test-GoveeInstaller.ps1 -ReaderProfile AppliancePower
30 changes: 30 additions & 0 deletions .github/workflows/home-assistant.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Home Assistant Templates

on:
pull_request:
paths:
- 'integrations/home-assistant/**'
- 'scripts/home-assistant/**'
- '.github/workflows/home-assistant.yml'
push:
branches: [main, dev]
paths:
- 'integrations/home-assistant/**'
- 'scripts/home-assistant/**'
- '.github/workflows/home-assistant.yml'
workflow_dispatch:

permissions:
contents: read

jobs:
validate:
name: Home Assistant schemas and actions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Validate isolated Home Assistant templates
run: uv run --project scripts/home-assistant --frozen python -m unittest discover -s scripts/home-assistant -p 'test_*.py' -v
31 changes: 28 additions & 3 deletions .github/workflows/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ name: Publish OpenAPI Spec
on:
push:
branches: [main, dev]
pull_request:
paths:
- '.github/workflows/openapi.yml'
- 'app/api/openapi.json/**'
- 'src/server/openapi.ts'
- 'src/auth/**'
workflow_dispatch:

permissions:
contents: read
Expand All @@ -29,10 +36,18 @@ jobs:
- name: Build
run: pnpm build

# Exercise the same authenticated route as a real client without using
# any owner's credentials or weakening production authentication.
- name: Create temporary export credential
run: |
export_token=$(openssl rand -hex 32)
echo "::add-mask::$export_token"
printf 'SLEEPYPOD_AUTH_TOKEN=%s\n' "$export_token" >> "$GITHUB_ENV"

- name: Start server
run: |
mkdir -p /tmp/sleepypod-raw
pnpm start > /tmp/server.log 2>&1 &
pnpm start --hostname 127.0.0.1 > /tmp/server.log 2>&1 &
echo "SERVER_PID=$!" >> "$GITHUB_ENV"
env:
DATABASE_URL: file:./ci-sleepypod.db
Expand All @@ -43,7 +58,8 @@ jobs:
- name: Wait for server
run: |
for i in $(seq 1 90); do
if curl -sf http://localhost:3000/api/openapi.json > /dev/null 2>&1; then
if curl -sf --max-time 5 -H "Authorization: Bearer $SLEEPYPOD_AUTH_TOKEN" \
http://127.0.0.1:3000/api/openapi.json > /dev/null 2>&1; then
echo "Server ready after ${i}s"
exit 0
fi
Expand All @@ -55,7 +71,16 @@ jobs:
exit 1

- name: Download OpenAPI spec
run: curl -sf http://localhost:3000/api/openapi.json | jq . > openapi.json
run: |
curl -sf --max-time 30 -H "Authorization: Bearer $SLEEPYPOD_AUTH_TOKEN" \
http://127.0.0.1:3000/api/openapi.json | jq . > openapi.json
jq -e '.openapi and .paths and .security' openapi.json > /dev/null

- name: Verify anonymous access stays blocked
run: |
status=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 \
http://127.0.0.1:3000/api/openapi.json)
test "$status" = 401

- name: Stop server
if: always()
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/python-modules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ jobs:
uv pip install --python .venv/bin/python ${{ matrix.module.deps }}
fi
fi
# Probe the production environment before pytest or other test-only deps can mask missing imports.
if [ -f uv.lock ]; then
python "${{ github.workspace }}/scripts/deployment/probe_modules.py" \
--modules-root "${{ github.workspace }}/modules" --module "${{ matrix.module.name }}"
fi
# shellcheck source=/dev/null
. .venv/bin/activate
uv pip install pytest pytest-cov
Expand Down
20 changes: 19 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

# semantic-release pushes tags through the repository's pre-push checks.
# Give those checks the same locked Python runtime as the main CI jobs.
- name: Setup Python for release validation
uses: actions/setup-python@v6
with:
python-version: '3.10'

- name: Setup uv for release validation
uses: astral-sh/setup-uv@v4
with:
enable-cache: true

- name: Build
run: pnpm build

Expand Down Expand Up @@ -69,6 +81,12 @@ jobs:
.
mv /tmp/sleepypod-core.tar.gz .

# Create the host-only test environment after packaging, so Linux runner
# wheels and interpreter paths never become part of the Pod artifact.
- name: Install locked runtime integration dependencies
working-directory: modules/piezo-processor
run: uv sync --locked --no-install-project

- name: Refresh tags (force, prune)
# semantic-release runs `git fetch --tags` unconditionally and aborts
# on any "would clobber existing tag" conflict. Force-prune up front so
Expand All @@ -78,4 +96,4 @@ jobs:
- name: Semantic Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: pnpm dlx semantic-release
run: pnpm dlx semantic-release
20 changes: 19 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ jobs:
- { name: "Lint", cmd: "CHANGED=$(git diff --name-only --diff-filter=d origin/${BASE_REF#refs/heads/}...HEAD -- '*.ts' '*.tsx' | head -200); if [ -n \"$CHANGED\" ]; then echo \"$CHANGED\" | xargs -d '\\n' pnpm eslint --; else echo 'No TS/TSX files changed'; fi" }
- { name: "Typecheck", cmd: "pnpm tsc" }
- { name: "Unit Tests", cmd: "pnpm test run --coverage --passWithNoTests" }
- { name: "Browser Tests", cmd: "NODE_ENV=production CI=1 pnpm build && pnpm test:browser" }
# Build workers must not open the same on-disk SQLite file. The browser
# runner creates and migrates its own isolated databases after the build.
- { name: "Browser Tests", cmd: "NODE_ENV=production CI=1 DATABASE_URL=:memory: BIOMETRICS_DATABASE_URL=:memory: pnpm build && pnpm test:browser" }

steps:
- name: Checkout
Expand Down Expand Up @@ -89,6 +91,22 @@ jobs:
# A PR carries base.ref; a merge-group run carries refs/heads/<base>.
BASE_REF: ${{ github.event.pull_request.base.ref || github.event.merge_group.base_ref }}

- name: Verify offline Free Sleep migration
if: matrix.task.name == 'Unit Tests'
run: uv run --project scripts/migration --frozen python -m unittest discover -s scripts/migration -p 'test_*.py' -v

- name: Verify offline deployment packaging
if: matrix.task.name == 'Unit Tests'
run: |
python3 -m unittest discover -s scripts/deployment -p 'test_*.py' -v
python3 -m unittest discover -s scripts/bedroom -p 'test_*.py' -v
node --test scripts/bedroom/*.test.mjs

- name: Verify isolated IPv4 and IPv6 failure and recovery
if: matrix.task.name == 'Unit Tests'
timeout-minutes: 2
run: sudo env SLEEPYPOD_NETWORK_NAMESPACE_TEST=1 python3 -m unittest discover -s scripts/deployment -p 'test_network_trial_netns.py' -v

- name: Upload coverage reports to Codecov
if: github.repository == 'sleepypod/core' && matrix.task.name == 'Unit Tests' && !cancelled()
uses: codecov/codecov-action@v5
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ sleepypod.local.db-wal
*.db
.reviews/
__pycache__/

# Generated isolated personal browser bundle
/public/household/personal-runtime.js
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ Next.js App Router runs on the pod and controls its hardware:

- `src/hardware/`: DAC Unix-socket transport to frankenfirmware, status polling,
gestures, pump-stall protection, and snooze.
- `src/server/`: tRPC routers and REST endpoints at `/api/*`. The API uses a
LAN-only trust model without authentication; see `src/server/openapi.ts`.
- `src/server/`: tRPC routers and REST endpoints at `/api/*`. Controller APIs
require owner authentication through a Bearer connection key or an expiring
browser session; see `src/server/openapi.ts`. Use LAN or private Tailscale access.
- `src/scheduler/`: JobManager for temperature, power, alarms, and system jobs.
- `src/automation/`: Autopilot rules evaluated in the device timezone.
- `src/streaming/`: WebSocket sensor stream on port 3001, frame normalization,
Expand Down
39 changes: 39 additions & 0 deletions app/[lang]/home/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Link from 'next/link'
import { House, MoonStar, Sunrise, Wind } from 'lucide-react'
import { PageHeader } from '@/src/components/ds'
import { RoomContext } from '@/src/components/Home/RoomContext'
import { BedroomSensors } from '@/src/components/Home/BedroomSensors'

export default async function HomePage({ params }: { params: Promise<{ lang: string }> }) {
const { lang } = await params
return (
<>
<PageHeader title="Home" />
<BedroomSensors />
<section className="rounded-card border border-line bg-surface p-4">
<House className="mb-5 text-cool" size={36} aria-hidden />
<h2 className="text-base font-medium">Connect your room</h2>
<p className="mt-3 max-w-xl text-fg-2">Bring your bedroom measurements into sleep insights and reviewable Autopilot rules. Existing Home Assistant entities provide sensor input; house scenes remain separately controlled.</p>
<div className="mt-6 flex flex-wrap gap-3">
<Link href={`/${lang}/settings?section=mqtt`} className="rounded-ctl border border-line-2 px-4 py-3 text-fg">MQTT connection</Link>
<Link href={`/${lang}/settings?section=homekit`} className="rounded-ctl border border-line-2 px-4 py-3 text-fg">Apple Home bridge</Link>
</div>
</section>
<details className="rounded-card border border-line p-4">
<summary className="cursor-pointer text-sm text-fg-2">Existing single-source MQTT mappings</summary>
<div className="mt-4"><RoomContext /></div>
</details>
<div className="grid gap-4 sm:grid-cols-3">
{[{ icon: MoonStar, title: 'Wind down', text: 'Lighting and shades follow your evening.' }, { icon: Sunrise, title: 'Wake together', text: 'Coordinate your alarm with a Home scene.' }, { icon: Wind, title: 'Room comfort', text: 'Understand humidity, temperature and air quality.' }].map(item => (
<section key={item.title} className="rounded-card border border-line bg-surface p-4">
<item.icon size={22} className="mb-4 text-warm" aria-hidden />
<h2 className="font-medium">{item.title}</h2>
<p className="mt-2 text-sm text-fg-2">{item.text}</p>
<p className="mt-4 text-xs text-fg-2">Template · inactive</p>
</section>
))}
</div>
<p className="text-sm text-fg-2">Existing Apple Home scenes can be run from the native app after you authorize Home access. Missing room readings never trigger bed adjustments.</p>
</>
)
}
31 changes: 17 additions & 14 deletions app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Metadata } from 'next'
import { IBM_Plex_Mono, IBM_Plex_Sans } from 'next/font/google'
import dynamic from 'next/dynamic'
import Script from 'next/script'
import { ConnectionGate } from '@/src/components/AppShell/ConnectionGate'
import { AppShell } from '@/src/components/AppShell/AppShell'
import { allMessages, getI18nInstance } from '@/src/lib/i18n/appRouterI18n'
import { LinguiClientProvider } from '@/src/providers/LinguiClientProvider'
Expand Down Expand Up @@ -62,27 +63,29 @@ export default async function LangLayout({
return (
<html lang={lang} className={`dark ${plexSans.variable} ${plexMono.variable}`} data-theme="dark" suppressHydrationWarning>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="theme-color" content="#0b0b0c" />
<meta name="color-scheme" content="dark light" />
<link rel="icon" type="image/png" href="/icon.png" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<Script id="sp-theme-init" strategy="beforeInteractive">{THEME_INIT_SCRIPT}</Script>
</head>
<body>
<TRPCProvider>
<LinguiClientProvider initialLocale={lang} initialMessages={allMessages[lang]}>
<PrefsProvider>
<TimeFormatProvider>
<SideProvider>
<WeekNavigatorProvider>
<AppShell>{children}</AppShell>
</WeekNavigatorProvider>
</SideProvider>
</TimeFormatProvider>
</PrefsProvider>
</LinguiClientProvider>
</TRPCProvider>
<ConnectionGate>
<TRPCProvider>
<LinguiClientProvider initialLocale={lang} initialMessages={allMessages[lang]}>
<PrefsProvider>
<TimeFormatProvider>
<SideProvider>
<WeekNavigatorProvider>
<AppShell>{children}</AppShell>
</WeekNavigatorProvider>
</SideProvider>
</TimeFormatProvider>
</PrefsProvider>
</LinguiClientProvider>
</TRPCProvider>
</ConnectionGate>
<DemoAnalytics />
</body>
</html>
Expand Down
7 changes: 7 additions & 0 deletions app/[lang]/more/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { redirect } from 'next/navigation'

/** Preserve bookmarks from the former five-tab layout. */
export default async function MorePage({ params }: { params: Promise<{ lang: string }> }) {
const { lang } = await params
redirect(`/${lang}/settings`)
}
10 changes: 8 additions & 2 deletions app/[lang]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { Metadata } from 'next'
import { TempScreen } from '@/src/components/TempScreen/TempScreen'
import { BedroomSummary } from '@/src/components/Home/BedroomSummary'
import { getI18nInstance } from '@/src/lib/i18n/appRouterI18n'
import { initLingui } from '@/src/lib/i18n/initLingui'
import { setI18n } from '@lingui/react/server'

// The layout's title template only applies to child segments, not this page.
export const metadata: Metadata = { title: { absolute: 'Temp · sleepypod' } }
export const metadata: Metadata = { title: { absolute: 'Temp · Sleepypod' } }

export default async function Page({
params,
Expand All @@ -17,5 +18,10 @@ export default async function Page({
initLingui(lang)
setI18n(i18n)

return <TempScreen />
return (
<>
<BedroomSummary />
<TempScreen />
</>
)
}
Loading