Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
2d19947
Build the core modules and their tests on Linux
claude Sep 27, 2026
2080c1a
Refuse let values nested deeper than 64 levels instead of overflowing…
claude Sep 27, 2026
762a4ed
Cap text built by +, templates, replace and join at 1 MB
claude Sep 27, 2026
5ae29e8
Remember failed ancestor matches so selectors with many * stop backtr…
claude Sep 27, 2026
95584cc
Build the provider tests on Linux
claude Sep 27, 2026
f1dfc16
Show weather hours, weekdays and sun times in the time zone of the pl…
claude Sep 27, 2026
b70fa3d
List apps without a bundle ID in apps.all like 0.1.4.2, keyed and lau…
claude Sep 27, 2026
4931713
Read control-state.json and the old settings.json only as regular fil…
claude Sep 27, 2026
c1d5a9f
Bound the remembered action warning sites and the error overlay probl…
claude Sep 27, 2026
6ba238a
Read config, state and legacy files only as regular files and at most…
claude Sep 27, 2026
a322da0
Build apollowm-probe again: give the signal handler closure an explic…
claude Sep 27, 2026
9eb6b71
Type the expected slider thumb center so the test compiles in reasona…
claude Sep 27, 2026
c2320af
Find source line breaks by scanning bytes instead of comparing every …
claude Sep 27, 2026
ca09efc
Look for an opening brace in the UTF-8 bytes instead of a Foundation …
claude Sep 27, 2026
22d2fbd
Parse each template once per load and share it between schema check a…
claude Sep 27, 2026
d67ba5e
Resolve batches of source positions per line instead of walking every…
claude Sep 27, 2026
9dcd945
Cache the stack bounds per thread on Linux instead of reading /proc o…
claude Sep 27, 2026
cc0c8d0
Compare values for identity with memcmp instead of a generic byte-by-…
claude Sep 27, 2026
15e5108
Stop allocating in the KDL parser's prefix, code point and bare word …
claude Sep 27, 2026
494daf3
Find the local names of a binding from the path roots instead of buil…
claude Sep 27, 2026
b5cd3f4
Return literal templates and expressions directly instead of running …
claude Sep 27, 2026
3c30502
Remember the path roots of a compiled value instead of walking its te…
claude Sep 27, 2026
ef4c025
Take literal var defaults as they are instead of rendering every list…
claude Sep 27, 2026
45dcc14
Join an element identity once per build and append components without…
claude Sep 27, 2026
57bd3ba
Hash each entry keys by the fields their kind uses
claude Sep 27, 2026
d0c4286
Keep the each key index between passes instead of rebuilding it from …
claude Sep 27, 2026
9c40f92
Skip sorting empty property and slot lists when building an element
claude Sep 27, 2026
67938ed
Cut values nested deeper than 256 levels to null when they enter the …
claude Sep 27, 2026
c94619a
Bound remembered binding and runtime warnings and forget the evaluato…
claude Sep 27, 2026
0329cbd
Build the shell core tests on Linux
claude Sep 27, 2026
968465d
Keep at most 256 fields from the media stream so diffs with new keys …
claude Sep 27, 2026
a848f6a
Let the date filter take a time zone as second argument
claude Sep 27, 2026
3d46e01
Publish the time zone of the weather place for the date filter
claude Sep 27, 2026
89da807
Warn when an expression reads a var the config never declares
claude Sep 27, 2026
1f472f3
Suggest the closest allowed value when an enumeration argument or pro…
claude Sep 27, 2026
9a1d0a4
Give the macOS CI job 45 minutes, the release build plus the debug te…
claude Sep 27, 2026
3b9dbd0
Warn when set, toggle-var or reset names a var the config never declares
claude Sep 27, 2026
b566f6c
Build the huge texts of the text limit test inside the test so the ru…
claude Sep 27, 2026
500f185
Add a five step guide to writing a config, with example configs the t…
claude Sep 27, 2026
cd750ea
Reject ISO times with out of range fields instead of overflowing
claude Sep 27, 2026
2466d68
Treat a zero or non finite usage half life or score from disk as the …
claude Sep 27, 2026
60d7d76
Reset a running marketplace sign-in when the provider stops so it can…
claude Sep 27, 2026
e006810
Split control socket lines in one pass and close connections whose li…
claude Sep 27, 2026
2a8648c
Keep a listen script's last unterminated line, report its exit after …
claude Sep 27, 2026
4254f7c
Read the place's UTC offset from wttr.in's local observation time ins…
claude Sep 27, 2026
26e40b1
Evaluate bindings dirtied during a flush round in the same round when…
claude Sep 27, 2026
4273fc6
Return null from percent when the scaled number is not finite
claude Sep 27, 2026
c91f91c
Find an empty needle at index 0 in index-of, matching contains
claude Sep 27, 2026
ce275b9
Ignore size reports for surfaces that are gone so they do not come ba…
claude Sep 27, 2026
7643c59
Leave elements parked for teardown out of a surface's element budget
claude Sep 27, 2026
cae3804
Stop running handler sequences of the previous config on a config swi…
claude Sep 27, 2026
6fcb761
Bind parameter defaults of a dynamic use so they follow their depende…
claude Sep 27, 2026
7b3c5b0
Blank out user folder names in every text field a crash report keeps
claude Sep 27, 2026
3b2a145
Write through a symlinked config file to its target instead of replac…
claude Sep 27, 2026
2bd177a
Serialize machine state writes so the file always ends with the lates…
claude Sep 27, 2026
f5d8824
Close a control connection when a reply cannot be written in time and…
claude Sep 27, 2026
62325cc
Treat a record whose fields change order as a change in the signal store
claude Sep 27, 2026
542025f
Wait for script runner results by suspending the test instead of spin…
claude Sep 27, 2026
01393a7
Return a path's value directly when no members follow instead of buil…
claude Sep 27, 2026
f13d2e5
Cache a compiled value's local names instead of rebuilding the sets f…
claude Sep 27, 2026
6804ffb
Hand back a bare local directly when a template is just that name
claude Sep 27, 2026
29e9040
Evaluate all bindings of a build session with one pinned evaluator an…
claude Sep 27, 2026
c1e4ef2
Stack locals on a scope as shared layers instead of copying its dicti…
claude Sep 27, 2026
c55b8c6
Flatten a container's elements without casting every part
claude Sep 27, 2026
5115449
Add an emit action that sends user.<name> events to the config's own …
claude Sep 27, 2026
367e306
Let a config declare its own filters as expressions over value, expan…
claude Sep 27, 2026
9485956
Locate expression names for diagnostic spans only when a diagnostic n…
claude Sep 27, 2026
9f8cb71
Parse binary operators by precedence climbing instead of recursing th…
claude Sep 27, 2026
55beae0
Compute a KDL source's byte order mark length once instead of on ever…
claude Sep 27, 2026
0dd69c3
Resolve KDL node positions as an ordered list and reuse the current l…
claude Sep 27, 2026
ac92d7a
Check a line for wide characters with a plain byte loop
claude Sep 27, 2026
d404b40
Read plain integers of up to 15 digits directly instead of through a …
claude Sep 27, 2026
495822d
Look up ASCII identifier characters in a table built from the KDL rule
claude Sep 27, 2026
f3164e9
Cache grapheme ends per line in an array indexed by line instead of a…
claude Sep 27, 2026
8224135
Pass literal var values through without let substitution
claude Sep 27, 2026
fb8932a
Run the timing budget tests in their own CI step without other tests …
claude Sep 27, 2026
ec9eb79
Let the slide and grow animators take the reduce motion setting so te…
claude Sep 27, 2026
3f59d85
Suggest the closest name when apollo schema does not know the one ask…
claude Sep 27, 2026
25c0d39
Carry emit depth and a per-chain event budget with the handler so wai…
claude Sep 27, 2026
c5b0d94
Bound user filter expansion, expand filters in var values, report fil…
claude Sep 27, 2026
8455217
Measure the main run loop blockage in the isolated timing step too
claude Sep 27, 2026
9c9c262
Warn about unknown vars inside filter bodies like everywhere else
claude Sep 27, 2026
65dbc95
Suggest optional for a mistyped include property
claude Sep 27, 2026
7af66e7
Document the emit chain limits in the action reference
claude Sep 27, 2026
9ae9d84
Evaluate constant list items in place and store an already sanitized …
claude Sep 27, 2026
91daddf
Fold var defaults made only of constants into one value at load time
claude Sep 27, 2026
460e4c1
Measure the long derived chain activation in the isolated timing step…
claude Sep 27, 2026
7c46814
Remove feature blocks and require feature so require only checks the …
claude Sep 28, 2026
0784977
Replace let with var: a var nothing sets is a constant and a default …
claude Sep 28, 2026
bc884c1
Name every action and node argument in kebab-case like the rest of th…
claude Sep 28, 2026
fba7a5d
Name filter arguments and check provider and event fields in kebab-ca…
claude Sep 28, 2026
f669118
Name provider action arguments in kebab-case and check them with the …
claude Sep 28, 2026
e629788
Describe every registry argument, field and entry in more than one word
claude Sep 28, 2026
13d1c47
Give every config diagnostic a stable code, shown as error[A201] and …
claude Sep 28, 2026
782c9c4
Add apollo explain to look up what a diagnostic code means
claude Sep 28, 2026
ae2a25f
Give runtime, provider and fixture diagnostics stable codes too
claude Sep 28, 2026
c70f9f9
Remove open-app, apps.launch already launches or activates an app
claude Sep 28, 2026
7828812
Rename notify to toast.show so it pairs with toast.dismiss and osd.show
claude Sep 28, 2026
3759d6b
Check the Marketplace inventory against the fixed MP-01 to MP-24 list…
claude Sep 28, 2026
848306c
Scale timing budgets by 3.5 on x86_64, where the Intel runner takes 2…
claude Sep 28, 2026
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
10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ jobs:
- name: Intel
runner: macos-26-intel
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
timeout-minutes: 45
env:
TIMING_TESTS: MainBlockObserverTests|longChainWithReaderIsFast|EachBudgetTests|HostileConfigTests|ReloadBudgetTests|loadsDefaultSizedConfigInBudget|largeListReadsWithinBudget|largeListWithOneChangedEntryWithinBudget
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1

Expand All @@ -38,7 +40,11 @@ jobs:
run: swift build -c release --product ApolloShell && swift build -c release --product apollo

- name: Test
run: ./test.sh
run: ./test.sh --skip "$TIMING_TESTS"

- name: Timing budgets, one test at a time
if: success() || failure()
run: ./test.sh --no-parallel --filter "$TIMING_TESTS"

- name: Assemble and verify the app bundle
run: |
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ apollo config select mine
apollo check ~/.config/apolloshell/configs/mine
```

Every node, action, provider, filter and event is in
New to configs? [docs/GUIDE.md](docs/GUIDE.md) builds one in five small,
tested steps. Every node, action, provider, filter and event is in
[docs/CONFIG.md](docs/CONFIG.md), generated by `apollo schema --markdown`.
Coming from 0.1? [docs/release-notes-0.2.0.md](docs/release-notes-0.2.0.md)
says where your settings went.
Expand Down
14 changes: 7 additions & 7 deletions Resources/configs/apolloshell-default/dashboard.kdl
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
var dashboard-tabs "{dashboard-caelestia.tabs}" type="list" persist=#true
var dashboard-cards-top "{dashboard-caelestia.top}" type="list" persist=#true
var dashboard-cards-bottom "{dashboard-caelestia.bottom}" type="list" persist=#true
var dashboard-cards-side "{dashboard-caelestia.side}" type="list" persist=#true
var dashboard-tabs "{var.dashboard-caelestia.tabs}" type="list" persist=#true
var dashboard-cards-top "{var.dashboard-caelestia.top}" type="list" persist=#true
var dashboard-cards-bottom "{var.dashboard-caelestia.bottom}" type="list" persist=#true
var dashboard-cards-side "{var.dashboard-caelestia.side}" type="list" persist=#true
var dashboard-tab "dashboard"
var calendar-offset 0
var dashboard-visible-tabs from="{var.dashboard-tabs | where 'visible' true}"
var dashboard-active-tab from="{(var.dashboard-visible-tabs | where 'id' var.dashboard-tab | count) > 0 ? var.dashboard-tab : (var.dashboard-visible-tabs | first).id}"

let dashboard-tab-looks {
var dashboard-tab-looks {
- id="dashboard" title="Dashboard" icon="bar-dashboard" symbol="square.grid.2x2" selected=".fill"
- id="media" title="Media" icon="panel-media" symbol="music.note.list" selected=""
- id="performance" title="Performance" icon="panel-performance" symbol="gauge.with.dots.needle.67percent" selected=""
Expand Down Expand Up @@ -66,8 +66,8 @@ popup "dashboard" anchor="top" motion="slide" hover-edge=#true overhang=#true ar
button class="dashboard-tab" checked="{tab.id == var.dashboard-active-tab}" {
on-click { set "dashboard-tab" "{tab.id}" }
column class="dashboard-tab-label" {
icon "{(dashboard-tab-looks | where 'id' tab.id | first).icon}" fallback="{(dashboard-tab-looks | where 'id' tab.id | first).symbol}{tab.id == var.dashboard-active-tab ? (dashboard-tab-looks | where 'id' tab.id | first).selected : ''}" class="dashboard-tab-glyph"
text "{(dashboard-tab-looks | where 'id' tab.id | first).title}" class="dashboard-tab-title"
icon "{(var.dashboard-tab-looks | where 'id' tab.id | first).icon}" fallback="{(var.dashboard-tab-looks | where 'id' tab.id | first).symbol}{tab.id == var.dashboard-active-tab ? (var.dashboard-tab-looks | where 'id' tab.id | first).selected : ''}" class="dashboard-tab-glyph"
text "{(var.dashboard-tab-looks | where 'id' tab.id | first).title}" class="dashboard-tab-title"
}
when "{tab.id == var.dashboard-active-tab}" { stack class="dashboard-tab-pill" match-id="dashboard-tab" }
}
Expand Down
4 changes: 2 additions & 2 deletions Resources/configs/apolloshell-default/onboarding.kdl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var onboarding-step 0

let onboarding-features {
var onboarding-features {
- symbol="sidebar.left" tint="blue" title="Bar" text="Spaces, Dock, clock and status on the left edge"
- symbol="magnifyingglass" tint="purple" title="Launcher" text="Search and open apps – with a keyboard shortcut"
- symbol="square.grid.2x2.fill" tint="indigo" title="Dashboard" text="Weather, calendar, media and performance"
Expand Down Expand Up @@ -72,7 +72,7 @@ window "onboarding" title="Welcome to ApolloShell" resizable=#false {
column class="onboarding-page" {
use "onboarding-header" symbol="sidebar.left" tint="indigo" title="Welcome to ApolloShell" text="A desktop shell for macOS modelled on Caelestia. It complements the Mac instead of replacing it – everything can be set up in Settings."
column class="onboarding-features" {
each feature in="{onboarding-features}" {
each feature in="{var.onboarding-features}" {
row class="onboarding-feature" {
icon "{feature.symbol}" class="onboarding-feature-glyph tint-{feature.tint}"
column class="onboarding-feature-text" {
Expand Down
28 changes: 14 additions & 14 deletions Resources/configs/apolloshell-default/presets.kdl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
let sidebar-caelestia {
var sidebar-caelestia {
- id="dashboard-button" kind="dashboard-button"
- id="spaces" kind="spaces" style="dots"
- id="dock" kind="dock" show-running=#true icon-size="medium"
Expand All @@ -8,18 +8,18 @@ let sidebar-caelestia {
- id="power" kind="power"
}

let sidebar-minimal {
var sidebar-minimal {
- id="spaces" kind="spaces" style="dots"
- id="spacer" kind="spacer"
- id="clock" kind="clock" show-icon=#false show-date=#false
- id="power" kind="power"
}

let sidebar-dock-only {
var sidebar-dock-only {
- id="dock" kind="dock" show-running=#true icon-size="medium"
}

let sidebar-everything {
var sidebar-everything {
- id="dashboard-button" kind="dashboard-button"
- id="media-button" kind="media-button"
- id="spaces" kind="spaces" style="dots"
Expand All @@ -36,14 +36,14 @@ let sidebar-everything {
- id="power" kind="power"
}

let dashboard-tabs-all {
var dashboard-tabs-all {
- id="dashboard" visible=#true
- id="media" visible=#true
- id="performance" visible=#true
- id="weather" visible=#true
}

let dashboard-caelestia {
var dashboard-caelestia {
tabs {
- id="dashboard" visible=#true
- id="media" visible=#true
Expand All @@ -64,7 +64,7 @@ let dashboard-caelestia {
}
}

let dashboard-compact {
var dashboard-compact {
tabs {
- id="dashboard" visible=#true
- id="media" visible=#true
Expand All @@ -83,7 +83,7 @@ let dashboard-compact {
side "{[]}"
}

let dashboard-calendar-weather {
var dashboard-calendar-weather {
tabs {
- id="dashboard" visible=#true
- id="weather" visible=#true
Expand All @@ -100,7 +100,7 @@ let dashboard-calendar-weather {
}
}

let utilities-standard {
var utilities-standard {
cards {
- kind="keep-awake" enabled=#true
- kind="audio" enabled=#true
Expand All @@ -120,7 +120,7 @@ let utilities-standard {
}
}

let utilities-minimal {
var utilities-minimal {
cards {
- kind="quick-toggles" enabled=#true
- kind="keep-awake" enabled=#false
Expand All @@ -135,7 +135,7 @@ let utilities-minimal {
}
}

let utilities-audio {
var utilities-audio {
cards {
- kind="audio" enabled=#true
- kind="quick-toggles" enabled=#true
Expand All @@ -150,7 +150,7 @@ let utilities-audio {
}
}

let utilities-everything {
var utilities-everything {
cards {
- kind="keep-awake" enabled=#true
- kind="audio" enabled=#true
Expand All @@ -172,13 +172,13 @@ let utilities-everything {
}
}

let hotkeys-default {
var hotkeys-default {
launcher "alt+space"
dashboard "ctrl+alt+d"
utilities "ctrl+alt+u"
settings "ctrl+alt+comma"
}
let hotkeys-hyper {
var hotkeys-hyper {
launcher "f20"
dashboard "hyper+d"
utilities "hyper+u"
Expand Down
12 changes: 6 additions & 6 deletions Resources/configs/apolloshell-default/session.kdl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
let session-actions {
var session-actions {
- id="logout" title="Log Out" icon="session-logout" symbol="rectangle.portrait.and.arrow.right" mood="think"
- id="shutdown" title="Shut Down" icon="session-shutdown" symbol="power" mood="farewell"
- id="sleep" title="Sleep" icon="session-sleep" symbol="moon.zzz" mood="sleep"
Expand All @@ -7,7 +7,7 @@ let session-actions {

var session-selection #null type="any"
var session-hover #null type="any"
var session-mood from="{var.session-hover != null ? (session-actions | where 'id' var.session-hover | first).mood : (var.session-selection != null ? (session-actions | at var.session-selection).mood : 'idle')}"
var session-mood from="{var.session-hover != null ? (var.session-actions | where 'id' var.session-hover | first).mood : (var.session-selection != null ? (var.session-actions | at var.session-selection).mood : 'idle')}"

define "session-button" {
param "action"
Expand Down Expand Up @@ -40,12 +40,12 @@ popup "session" anchor="right" scrim=0.15 overhang=#true {
}
}
column class="session" {
use "session-button" action="{session-actions | at 0}" index=0
use "session-button" action="{session-actions | at 1}" index=1
use "session-button" action="{var.session-actions | at 0}" index=0
use "session-button" action="{var.session-actions | at 1}" index=1
stack class="session-emblem" {
mark state="{var.session-mood}" greet=#true class="session-mark"
}
use "session-button" action="{session-actions | at 2}" index=2
use "session-button" action="{session-actions | at 3}" index=3
use "session-button" action="{var.session-actions | at 2}" index=2
use "session-button" action="{var.session-actions | at 3}" index=3
}
}
Loading
Loading