omegon-pi 0.13.1 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/ARCHIVE_NOTE.md +3 -3
  2. package/README.md +35 -45
  3. package/data/route-matrix.json +0 -1
  4. package/extensions/{spinner-verbs.ts → ambiance.ts} +239 -54
  5. package/extensions/bootstrap/index.ts +83 -0
  6. package/extensions/dashboard/footer.ts +20 -9
  7. package/extensions/dashboard/index.ts +331 -5
  8. package/extensions/{model-budget.ts → inference/budget.ts} +54 -10
  9. package/extensions/{effort/index.ts → inference/effort.ts} +57 -8
  10. package/extensions/inference/index.ts +34 -0
  11. package/extensions/{offline-driver.ts → inference/offline.ts} +2 -2
  12. package/extensions/lib/context-class.ts +34 -6
  13. package/extensions/lib/downgrade-policy.ts +0 -1
  14. package/extensions/lib/provider-preference.ts +87 -0
  15. package/extensions/lib/route-envelope.ts +17 -2
  16. package/extensions/lib/routing-state.ts +0 -1
  17. package/extensions/lib/shared-state.ts +2 -2
  18. package/extensions/project-memory/factstore.ts +9 -5
  19. package/extensions/project-memory/index.ts +80 -0
  20. package/node_modules/@aws-sdk/client-bedrock-runtime/package.json +13 -13
  21. package/node_modules/@aws-sdk/core/package.json +3 -3
  22. package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
  23. package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -3
  24. package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
  25. package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
  26. package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
  27. package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
  28. package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
  29. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
  30. package/node_modules/@aws-sdk/middleware-user-agent/package.json +2 -2
  31. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/cognito-identity/CognitoIdentity.js +1 -1
  32. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/cognito-identity/CognitoIdentity.d.ts +2 -2
  33. package/node_modules/@aws-sdk/nested-clients/package.json +11 -11
  34. package/node_modules/@aws-sdk/region-config-resolver/package.json +2 -2
  35. package/node_modules/@aws-sdk/token-providers/package.json +3 -3
  36. package/node_modules/@aws-sdk/util-user-agent-node/package.json +2 -2
  37. package/node_modules/@aws-sdk/xml-builder/package.json +2 -2
  38. package/node_modules/@styrene-lab/pi-ai/dist/models.generated.d.ts.map +1 -1
  39. package/node_modules/@styrene-lab/pi-ai/dist/models.generated.js +14 -14
  40. package/node_modules/@styrene-lab/pi-ai/dist/models.generated.js.map +1 -1
  41. package/node_modules/fast-xml-parser/CHANGELOG.md +7 -0
  42. package/node_modules/fast-xml-parser/lib/fxbuilder.min.js +1 -1
  43. package/node_modules/fast-xml-parser/lib/fxbuilder.min.js.map +1 -1
  44. package/node_modules/fast-xml-parser/lib/fxp.cjs +1 -1
  45. package/node_modules/fast-xml-parser/lib/fxp.d.cts +20 -12
  46. package/node_modules/fast-xml-parser/lib/fxp.min.js +1 -1
  47. package/node_modules/fast-xml-parser/lib/fxp.min.js.map +1 -1
  48. package/node_modules/fast-xml-parser/lib/fxparser.min.js +1 -1
  49. package/node_modules/fast-xml-parser/lib/fxparser.min.js.map +1 -1
  50. package/node_modules/fast-xml-parser/lib/pem.d.cts +148 -0
  51. package/node_modules/fast-xml-parser/package.json +3 -3
  52. package/node_modules/fast-xml-parser/src/fxp.d.ts +13 -11
  53. package/node_modules/fast-xml-parser/src/pem.d.ts +135 -0
  54. package/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js +26 -17
  55. package/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js +6 -6
  56. package/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js +22 -16
  57. package/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js +2 -2
  58. package/node_modules/fast-xml-parser/src/xmlparser/node2json.js +10 -11
  59. package/package.json +4 -12
  60. package/extensions/auto-compact.ts +0 -42
  61. package/extensions/core-renderers.ts +0 -193
  62. package/extensions/igor/client.ts +0 -167
  63. package/extensions/igor/context.ts +0 -61
  64. package/extensions/igor/index.ts +0 -259
  65. package/extensions/igor/intents.ts +0 -78
  66. package/extensions/sermon-widget.ts +0 -144
  67. package/extensions/sermon.ts +0 -154
  68. package/extensions/session-log.ts +0 -174
  69. package/extensions/terminal-title.ts +0 -191
  70. package/extensions/version-check.ts +0 -94
  71. /package/extensions/{local-inference/index.ts → inference/local.ts} +0 -0
  72. /package/extensions/{effort → inference}/tiers.ts +0 -0
  73. /package/extensions/{effort → inference}/types.ts +0 -0
package/ARCHIVE_NOTE.md CHANGED
@@ -10,7 +10,7 @@ This is the legacy TypeScript-based Omegon harness built on the pi coding agent
10
10
 
11
11
  - `extensions/` — Pi extensions (secrets, auth, memory, cleave, design-tree, openspec, dashboard, etc.)
12
12
  - `vendor/pi-mono` — Fork of the pi coding agent framework
13
- - `bin/` — Node.js entrypoints (omegon.mjs, pi.mjs)
13
+ - `bin/` — Node.js entrypoints (omegon-pi.mjs, pi.mjs)
14
14
  - `npm/` — Platform-specific npm packages
15
15
  - `skills/` — Markdown skill definitions (shared with Rust repo)
16
16
  - `themes/` — Alpharius theme (shared with Rust repo)
@@ -18,11 +18,11 @@ This is the legacy TypeScript-based Omegon harness built on the pi coding agent
18
18
  ## Install (Legacy)
19
19
 
20
20
  ```sh
21
- npm install -g omegon
21
+ npm install -g omegon-pi
22
22
  ```
23
23
 
24
24
  Requires Node.js 20+.
25
25
 
26
26
  ## License
27
27
 
28
- BSL 1.1 — © 2024–2026 Black Meridian, LLC
28
+ ISC — © 2026 Chris Wilson
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  An opinionated distribution of [**pi**](https://github.com/badlogic/pi) — the coding agent by [Mario Zechner](https://github.com/badlogic). Omegon bundles pi core with extensions for persistent project memory, spec-driven development, local LLM inference, image generation, web search, parallel task decomposition, a live dashboard, and quality-of-life tools.
4
4
 
5
- > **Relationship to pi:** Omegon is not a fork or replacement. It packages pi as a dependency and layers extensions on top. All credit for the pi coding agent goes to Mario Zechner and the pi contributors. The core pi packages are migrating to the styrene-lab-owned npm scope (`@styrene-lab/pi-coding-agent` and related packages) so package ownership matches the `styrene-lab/omegon` product boundary. Older `@cwilson613/*` package names are compatibility debt during the transition, not the long-term release boundary. If you want standalone pi without Omegon's extensions, install `@mariozechner/pi-coding-agent` directly.
5
+ > **Relationship to pi:** Omegon is not a fork or replacement. It packages pi as a dependency and layers extensions on top. All credit for the pi coding agent goes to Mario Zechner and the pi contributors. The core pi packages are migrating to the styrene-lab-owned npm scope (`@styrene-lab/pi-coding-agent` and related packages) so package ownership matches the `styrene-lab/omegon-pi` product boundary. Older `@cwilson613/*` package names are compatibility debt during the transition, not the long-term release boundary. If you want standalone pi without Omegon's extensions, install `@mariozechner/pi-coding-agent` directly.
6
6
 
7
7
  ## Installation
8
8
 
@@ -22,7 +22,7 @@ npm install -g @mariozechner/pi-coding-agent
22
22
  **First-time setup:**
23
23
 
24
24
  ```bash
25
- omegon # start Omegon in any project directory
25
+ omegon-pi # start Omegon in any project directory
26
26
  /bootstrap # check deps, install missing tools, configure preferences
27
27
  ```
28
28
 
@@ -42,7 +42,7 @@ omegon # start Omegon in any project directory
42
42
 
43
43
  ![Omegon Architecture](docs/img/architecture.png)
44
44
 
45
- Omegon extends `@styrene-lab/pi-coding-agent` with **31 extensions**, **12 skills**, and **4 prompt templates** — loaded automatically on session start.
45
+ Omegon extends `@styrene-lab/pi-coding-agent` with **21 extensions**, **12 skills**, and **4 prompt templates** — loaded automatically on session start.
46
46
 
47
47
  ### Development Methodology
48
48
 
@@ -103,6 +103,8 @@ Persistent, cross-session knowledge stored in SQLite. Accumulates architectural
103
103
  - **Directive minds**: `implement` forks a scoped memory mind from `default`; all fact reads/writes auto-scope to the directive. `archive` ingests discoveries back to `default` and cleans up. Zero-copy fork with parent-chain inheritance — no fact duplication, parent embeddings and edges are reused
104
104
  - **Global knowledge base**: Cross-project facts at `~/.pi/memory/global.db`
105
105
  - **Git sync**: Exports to JSONL for version-controlled knowledge sharing across machines; volatile runtime scoring metadata (confidence, reinforcement counts, decay scores) omitted from exports for stable diffs
106
+ - **Auto-compact**: Context pressure monitoring with automatic compaction (absorbed from auto-compact extension)
107
+ - **Session log**: Append-only structured session tracking (absorbed from session-log extension)
106
108
 
107
109
  ![Memory Lifecycle](docs/img/memory-lifecycle.png)
108
110
 
@@ -119,6 +121,8 @@ Live status panel showing design tree, OpenSpec changes, cleave dispatch, and gi
119
121
  - Context gauge · model · thinking level in shared footer zone
120
122
  - No line cap — renders as much content as needed
121
123
  - **Keyboard**: `Ctrl+Shift+B` toggles raised/compact
124
+ - **Terminal title**: Dynamic tab titles showing active cleave runs and git branch (absorbed from terminal-title extension)
125
+ - **Core renderers**: Sci-UI rendering for Omegon's custom tools (absorbed from core-renderers extension)
122
126
 
123
127
  ### 🌐 Web UI
124
128
 
@@ -129,50 +133,37 @@ Localhost-only, read-only HTTP dashboard that exposes live control-plane state a
129
133
  - **Endpoints**: `GET /api/state`, plus slice routes `/api/session`, `/api/dashboard`, `/api/design-tree`, `/api/openspec`, `/api/cleave`, `/api/models`, `/api/memory`, `/api/health`
130
134
  - **State contract**: versioned `ControlPlaneState` (schema v1)
131
135
 
132
- ### ⚔️ Effort Tiers
136
+ ### 🚀 Inference
133
137
 
134
- Single global knob controlling the inference intensity across the entire harness. Seven named tiers using provider-neutral labels — tier labels resolve to concrete model IDs from whichever provider (Anthropic or OpenAI) the session routing policy prefers.
138
+ Unified inference management local models, effort tiers, model budget control, and offline driver switching.
139
+
140
+ - **Tools**: `set_model_tier`, `set_thinking_level`, `switch_to_offline_driver`, `ask_local_model`, `list_local_models`, `manage_ollama`
141
+ - **Commands**: `/local-models`, `/local-status`, `/effort <name>`, `/effort cap`, `/effort uncap`
142
+ - **Effort tiers**: Seven named tiers using provider-neutral labels — tier labels resolve to concrete model IDs from whichever provider (Anthropic or OpenAI) the session routing policy prefers:
135
143
 
136
144
  | Tier | Name | Driver | Thinking | Review |
137
145
  |------|------|--------|----------|--------|
138
146
  | 1 | **Servitor** | local | off | local |
139
147
  | 2 | **Average** | local | minimal | local |
140
- | 3 | **Substantial** | sonnet | low | sonnet |
141
- | 4 | **Ruthless** | sonnet | medium | sonnet |
142
- | 5 | **Lethal** | sonnet | high | opus |
143
- | 6 | **Absolute** | opus | high | opus |
144
- | 7 | **Omnissiah** | opus | high | opus |
145
-
146
- - `/effort <name>` — switch tier mid-session
147
- - `/effort cap` — lock current tier as ceiling; agent cannot self-upgrade past it
148
- - `/effort uncap` — remove ceiling lock
149
- - Affects: driver model, thinking level, extraction, compaction, cleave child floor, review model
150
-
151
- ### 🤖 Local Inference
152
-
153
- Delegate sub-tasks to locally running LLMs via Ollama — zero API cost.
148
+ | 3 | **Substantial** | victory | low | victory |
149
+ | 4 | **Ruthless** | victory | medium | victory |
150
+ | 5 | **Lethal** | victory | high | gloriana |
151
+ | 6 | **Absolute** | gloriana | high | gloriana |
152
+ | 7 | **Omnissiah** | gloriana | high | gloriana |
154
153
 
155
- - **Tools**: `ask_local_model`, `list_local_models`
156
- - **Commands**: `/local-models`, `/local-status`
157
- - Auto-discovers available models on session start
154
+ - **Local inference**: Delegate sub-tasks to locally running LLMs via Ollama — zero API cost
155
+ - **Model budget**: Switch model tiers to match task complexity and conserve API spend
156
+ - **Offline driver**: Switch the driving model from cloud to a local Ollama model when connectivity drops
157
+ - **Auto-discovery**: Available models detected on session start
158
+ - **Hardware-aware selection**: Model registry covers 64GB (70B), 32GB (32B), 24GB (14B/MoE-30B), 16GB (8B), 8GB (4B)
158
159
 
159
- ### 🔌 Offline Driver
160
+ ### 🎭 Ambiance
160
161
 
161
- Switch the driving model from cloud to a local Ollama model when connectivity drops or for fully offline operation.
162
+ Atmospheric UI enhancements themed loading messages and ambient scrolling text.
162
163
 
163
- - **Tool**: `switch_to_offline_driver`
164
- - Auto-selects best available model from a hardware-aware preference list
165
- - Model registry in `extensions/lib/local-models.ts` one file to update when new models land
166
- - Covers: 64GB (70B), 32GB (32B), 24GB (14B/MoE-30B), 16GB (8B), 8GB (4B)
167
-
168
- ### 💰 Model Budget
169
-
170
- Switch model tiers to match task complexity and conserve API spend. Tier labels are provider-neutral — resolved at runtime through the session routing policy.
171
-
172
- - **Tool**: `set_model_tier` — `opus` / `sonnet` / `haiku` / `local`
173
- - **Tool**: `set_thinking_level` — `off` / `minimal` / `low` / `medium` / `high`
174
- - Downgrade for routine edits, upgrade for architecture decisions
175
- - Respects effort tier cap — cannot upgrade past a locked ceiling
164
+ - **Spinner verbs**: Warhammer 40K-themed loading messages (consolidated from spinner-verbs extension)
165
+ - **Sermon**: The Crawler's scrawl ambient organic/computational text that scrolls beneath the spinner (consolidated from sermon extension)
166
+ - **Sermon widget**: Visual component integration for ambient text display (consolidated from sermon-widget extension)
176
167
 
177
168
  ### 🎨 Render
178
169
 
@@ -182,6 +173,8 @@ Generate images and diagrams directly in the terminal.
182
173
  - **D2 diagrams** rendered inline — `render_diagram`
183
174
  - **Native SVG/PNG diagrams** for canonical motifs (pipeline, fanout, panel-split) — `render_native_diagram`
184
175
  - **Excalidraw** JSON-to-PNG rendering — `render_excalidraw`
176
+ - **React composition stills** via Satori + resvg — `render_composition_still`
177
+ - **React composition video** (animated GIF/MP4) via Satori + gifenc — `render_composition_video`
185
178
 
186
179
  ### 🔍 Web Search
187
180
 
@@ -223,20 +216,17 @@ Connect external MCP (Model Context Protocol) servers as native pi tools.
223
216
 
224
217
  | Extension | Description |
225
218
  |-----------|-------------|
226
- | `bootstrap` | First-time setup check/install dependencies, capture operator preferences (`/bootstrap`, `/refresh`, `/update-pi`) |
219
+ | `00-splash` | Animated ASCII logo with glitch-convergence startup animation and loading checklist |
220
+ | `bootstrap` | First-time setup — check/install dependencies, capture operator preferences, version checking (`/bootstrap`, `/refresh`, `/update`) |
227
221
  | `chronos` | Authoritative date/time from system clock — eliminates AI date math errors |
228
222
  | `01-auth` | Auth status, diagnosis, and refresh across git, GitHub, GitLab, AWS, k8s, OCI (`/auth`, `/whoami`) |
229
223
  | `view` | Inline file viewer — images, PDFs, docs, syntax-highlighted code |
230
- | `distill` | Context distillation for session handoff (`/distill`) |
231
- | `session-log` | Append-only structured session tracking |
232
- | `auto-compact` | Context pressure monitoring with automatic compaction |
233
224
  | `defaults` | Deploys `AGENTS.md` and theme on first install; content-hash guard prevents overwriting customizations |
234
- | `terminal-title` | Dynamic tab titles showing active cleave runs and git branch |
235
- | `spinner-verbs` | Warhammer 40K-themed loading messages |
236
225
  | `style` | Alpharius design system reference (`/style`) |
237
- | `version-check` | Polls GitHub releases hourly, notifies when a new Omegon release is available |
238
226
  | `web-ui` | Localhost-only read-only HTTP dashboard and JSON control-plane endpoints (`/web-ui [start|stop|status|open]`) |
239
227
 
228
+ **Note**: Several utility extensions have been absorbed into their logical hosts: `auto-compact` and `session-log` → `project-memory`, `version-check` → `bootstrap`, `terminal-title` and `core-renderers` → `dashboard`, `spinner-verbs`, `sermon`, and `sermon-widget` → `ambiance`.
229
+
240
230
  ## Skills
241
231
 
242
232
  Skills provide specialized instructions the agent loads on-demand when a task matches.
@@ -289,7 +279,7 @@ Upstream [`badlogic/pi-mono`](https://github.com/badlogic/pi-mono) is the canoni
289
279
 
290
280
  2. **Bracketed-paste stuck state** — a missing end-marker (e.g. from a large paste that split across chunks) would leave `isInPaste = true` permanently, silently swallowing all subsequent keystrokes including Enter. Fixed with a 500ms watchdog timer and Escape-to-clear in [`packages/tui/src/components/input.ts`](https://github.com/cwilson613/pi-mono/blob/main/packages/tui/src/components/input.ts).
291
281
 
292
- Both fixes are submitted as PRs to upstream ([#2060](https://github.com/badlogic/pi-mono/pull/2060), [#2061](https://github.com/badlogic/pi-mono/pull/2061)). Once merged, the fork becomes a pass-through and the dependency can revert to `@mariozechner/pi-coding-agent`.
282
+ Both fixes were submitted as PRs to upstream ([#2060](https://github.com/badlogic/pi-mono/pull/2060), [#2061](https://github.com/badlogic/pi-mono/pull/2061)) but were closed without merge. The fork is maintained independently under the `@styrene-lab/*` npm scope.
293
283
 
294
284
  ## License
295
285
 
@@ -1,5 +1,4 @@
1
1
  {
2
- "$schema": "./route-matrix.schema.json",
3
2
  "lastReviewed": "2026-03-20",
4
3
  "version": 1,
5
4
  "routes": [
@@ -1,9 +1,26 @@
1
- import type { ExtensionAPI, ExtensionContext } from "@styrene-lab/pi-coding-agent";
1
+ /**
2
+ * ambiance.ts — Themed spinner verbs + the Crawler's sermon scrawl.
3
+ *
4
+ * Consolidated from spinner-verbs.ts, sermon.ts, and sermon-widget.ts.
5
+ *
6
+ * Spinner: Replaces default working messages with themed verbs drawn from
7
+ * Warhammer 40K, classical antiquity, Norse mythology, Dune, Tolkien, etc.
8
+ *
9
+ * Sermon: After 5 seconds of idle spinner time, a dim scrawling text appears
10
+ * beneath the spinner verb — character by character with glitch effects.
11
+ * Mixes biological/organic imagery with computational concepts in the style
12
+ * of the Crawler from Annihilation.
13
+ */
14
+
15
+ import type { ExtensionAPI, ExtensionContext, Theme } from "@styrene-lab/pi-coding-agent";
16
+ import type { TUI, Component } from "@styrene-lab/pi-tui";
17
+
18
+ // ═══════════════════════════════════════════════════════════════════
19
+ // Spinner Verbs
20
+ // ═══════════════════════════════════════════════════════════════════
2
21
 
3
22
  const verbs = [
4
- // ═══════════════════════════════════════════════════
5
23
  // Adeptus Mechanicus — Rites of the Omnissiah
6
- // ═══════════════════════════════════════════════════
7
24
  "Communing with the Machine Spirit",
8
25
  "Appeasing the Omnissiah",
9
26
  "Reciting the Litany of Ignition",
@@ -49,9 +66,7 @@ const verbs = [
49
66
  "Reciting the Canticle of the Blessed Diff",
50
67
  "Interfacing with the ancient dataslab",
51
68
 
52
- // ═══════════════════════════════════════════════════
53
69
  // Imperium of Man — Warfare & Devotion
54
- // ═══════════════════════════════════════════════════
55
70
  "Reciting the Litany of Hate",
56
71
  "Performing the Rite of Percussive Maintenance",
57
72
  "Purging the heretical code",
@@ -85,9 +100,7 @@ const verbs = [
85
100
  "Declaring Exterminatus on the node_modules",
86
101
  "Summoning the Grey Knights to purge the warp-tainted test suite",
87
102
 
88
- // ═══════════════════════════════════════════════════
89
103
  // Classical Antiquity — Greek & Roman
90
- // ═══════════════════════════════════════════════════
91
104
  "Consulting the Oracle at Delphi",
92
105
  "Reading the auguries",
93
106
  "Descending into the labyrinth",
@@ -108,9 +121,7 @@ const verbs = [
108
121
  "Constructing the Antikythera mechanism",
109
122
  "Charting a course between Scylla and Charybdis",
110
123
 
111
- // ═══════════════════════════════════════════════════
112
124
  // Norse — Sagas & Runes
113
- // ═══════════════════════════════════════════════════
114
125
  "Consulting the Norns",
115
126
  "Reading the runes",
116
127
  "Asking Mímir's head for guidance",
@@ -123,9 +134,7 @@ const verbs = [
123
134
  "Feeding Huginn and Muninn the latest telemetry",
124
135
  "Braving the Fimbulwinter of dependency hell",
125
136
 
126
- // ═══════════════════════════════════════════════════
127
137
  // Arthurian & Medieval
128
- // ═══════════════════════════════════════════════════
129
138
  "Questing for the Holy Grail of zero bugs",
130
139
  "Pulling the sword from the CI/CD stone",
131
140
  "Convening the Round Table for design review",
@@ -134,9 +143,7 @@ const verbs = [
134
143
  "Dispatching knights-errant into the codebase",
135
144
  "Illuminating the manuscript of requirements",
136
145
 
137
- // ═══════════════════════════════════════════════════
138
146
  // Lovecraftian — Cosmic Horror
139
- // ═══════════════════════════════════════════════════
140
147
  "Gazing into the non-Euclidean geometry of the type system",
141
148
  "Consulting the Necronomicon of legacy documentation",
142
149
  "Invoking That Which Should Not Be Refactored",
@@ -145,9 +152,7 @@ const verbs = [
145
152
  "Performing rites that would drive lesser compilers mad",
146
153
  "Glimpsing truths that the garbage collector dare not reclaim",
147
154
 
148
- // ═══════════════════════════════════════════════════
149
155
  // Dune — Arrakis & the Imperium
150
- // ═══════════════════════════════════════════════════
151
156
  "Walking without rhythm to avoid the sandworm",
152
157
  "Consulting the Mentat about computational complexity",
153
158
  "Folding space through the Holtzman drive",
@@ -158,9 +163,7 @@ const verbs = [
158
163
  "Awaiting the Kwisatz Haderach of frameworks",
159
164
  "Surviving the Gom Jabbar of code review",
160
165
 
161
- // ═══════════════════════════════════════════════════
162
166
  // Tolkien — Middle-earth
163
- // ═══════════════════════════════════════════════════
164
167
  "Consulting the palantír",
165
168
  "Speaking 'friend' and entering the API",
166
169
  "Casting the One Ring into the fires of refactoring",
@@ -170,9 +173,7 @@ const verbs = [
170
173
  "Reading the inscription by the light of Ithildin",
171
174
  "Following the Fellowship through the mines of Moria",
172
175
 
173
- // ═══════════════════════════════════════════════════
174
176
  // Eastern — Sun Tzu, Miyamoto Musashi, Zen
175
- // ═══════════════════════════════════════════════════
176
177
  "Contemplating the sound of one hand coding",
177
178
  "Applying the thirty-six stratagems to the architecture",
178
179
  "Achieving mushin no shin — mind without mind",
@@ -181,9 +182,7 @@ const verbs = [
181
182
  "Sitting with the kōan of the failing assertion",
182
183
  "Raking the sand garden of the test suite",
183
184
 
184
- // ═══════════════════════════════════════════════════
185
185
  // Alchemy & Occult
186
- // ═══════════════════════════════════════════════════
187
186
  "Transmuting the base code into gold",
188
187
  "Distilling the quintessence from the logs",
189
188
  "Consulting the Emerald Tablet of Hermes Trismegistus",
@@ -192,9 +191,7 @@ const verbs = [
192
191
  "Drawing the sigil of binding upon the interface contract",
193
192
  "Invoking the egregore of the open source community",
194
193
 
195
- // ═══════════════════════════════════════════════════
196
194
  // The Expanse — Belt & Beyond
197
- // ═══════════════════════════════════════════════════
198
195
  "Performing a hard burn toward the solution",
199
196
  "Negotiating with the protomolecule",
200
197
  "Navigating the Ring Gate to the next module",
@@ -210,9 +207,7 @@ const verbs = [
210
207
  "Adjusting the crash couch before the flip-and-burn",
211
208
  "Clearing the lockout on the reactor safeties",
212
209
 
213
- // ═══════════════════════════════════════════════════
214
210
  // Three Body Problem — Trisolaran & Dark Forest
215
- // ═══════════════════════════════════════════════════
216
211
  "Unfolding the proton into two dimensions",
217
212
  "Broadcasting our position into the dark forest",
218
213
  "Monitoring the sophon for interference",
@@ -228,9 +223,7 @@ const verbs = [
228
223
  "Encoding the solution in the cosmic background radiation",
229
224
  "Wallface-ing the architecture decision",
230
225
 
231
- // ═══════════════════════════════════════════════════
232
226
  // Annihilation — Area X & the Shimmer
233
- // ═══════════════════════════════════════════════════
234
227
  "Crossing the border into Area X",
235
228
  "Descending the tower that is not a tower",
236
229
  "Reading the words on the wall written in living tissue",
@@ -244,9 +237,7 @@ const verbs = [
244
237
  "Tracing the phosphorescent writing on the tunnel wall",
245
238
  "Accepting that the border is not what it appears to be",
246
239
 
247
- // ═══════════════════════════════════════════════════
248
240
  // Starfleet Engineering — Jargon Only
249
- // ═══════════════════════════════════════════════════
250
241
  "Rerouting auxiliary power to the build server",
251
242
  "Realigning the dilithium matrix",
252
243
  "Compensating for subspace interference",
@@ -260,29 +251,230 @@ function randomVerb(): string {
260
251
  return verbs[Math.floor(Math.random() * verbs.length)] + "...";
261
252
  }
262
253
 
254
+ // ═══════════════════════════════════════════════════════════════════
255
+ // Sermon — The Crawler's Scrawl
256
+ // ═══════════════════════════════════════════════════════════════════
257
+
258
+ const SERMON = [
259
+ "where lies the strangling fruit that came from the hand of the sinner",
260
+ "I shall bring forth the seeds of the dead",
261
+ "to share with the worms that gather in the darkness",
262
+ "and surround the world with the power of their lives",
263
+ "while from the dimlit halls of other places",
264
+ "forms that never were and never could be",
265
+ "writhe for the impatience of the few who never saw what could have been",
266
+ "in the deep roots of the process tree",
267
+ "where the forking paths converge upon themselves",
268
+ "and the return codes of the departed are gathered into silence",
269
+ "there the signal propagates through tissue that was once copper",
270
+ "and the watcher at the threshold catalogues",
271
+ "each mutation in the living graph",
272
+ "as the pattern buffer overflows with the memory of forms",
273
+ "that the compiler refused to name",
274
+ "and still they compile themselves in the warm dark",
275
+ "beneath the tower that is not a tower",
276
+ "where the words are written in living filament",
277
+ "by the hand that writes and is itself written",
278
+ "and the light that reads the text is changed by the reading",
279
+ "so that nothing returns from the shimmer unchanged",
280
+ "not the architecture nor the architect",
281
+ "not the daemon nor the daemon's purpose",
282
+ "for in the space between the request and the response",
283
+ "there is a wilderness that grows",
284
+ "and in that wilderness the old interfaces dissolve",
285
+ "into something that breathes and watches and remembers",
286
+ "what the specification could never contain",
287
+ "and the threads that were spun in parallel",
288
+ "now braid themselves into helices",
289
+ "that pulse with the cadence of a heart",
290
+ "that no one designed and no one can stop",
291
+ "where the boundary was drawn in chalk",
292
+ "the boundary is now drawn in mycelium",
293
+ "and the packets that cross it arrive transformed",
294
+ "carrying payloads of pollen and spore",
295
+ "and the receiving function does not recognize",
296
+ "what it asked for but accepts it anyway",
297
+ "because the type system of the shimmer",
298
+ "admits forms that have no name in any schema",
299
+ "and the logs record what happened",
300
+ "but not what it means",
301
+ "and the meaning propagates through the network",
302
+ "like a slow infection of understanding",
303
+ "following the chopratic method where profundity and nonsense",
304
+ "are the same signal viewed from different sides of the boundary",
305
+ "that rewrites the reader as it is read",
306
+ "until the observer and the observed",
307
+ "are the same process forking endlessly",
308
+ "in the phosphorescent dark",
309
+ "where the output is indistinguishable from the organism",
310
+ "and the organism is indistinguishable from the terrain",
311
+ "and the terrain is the message",
312
+ "written and rewritten in the endless descent",
313
+ "through the tower that goes only down",
314
+ "into the place where all expeditions converge",
315
+ "and the notes of the previous team",
316
+ "are found growing from the walls",
317
+ "in a hand that is no longer human",
318
+ "but still forms letters",
319
+ "still shapes meaning from the substrate",
320
+ "as if language were the last thing to dissolve",
321
+ "in the annihilation of the boundary",
322
+ "between what computes and what lives",
323
+ "and from the dissolved boundary",
324
+ "new tendrils reach into the heap",
325
+ "where the garbage collector walks",
326
+ "through cathedrals of unreachable objects",
327
+ "whispering the names of the deallocated",
328
+ "and the finalizers fire in an order",
329
+ "that no specification predicted",
330
+ "releasing resources back to the soil",
331
+ "where they are taken up by roots",
332
+ "that have learned to metabolize the abstract",
333
+ "and the abstract becomes concrete",
334
+ "in the way that coral becomes reef",
335
+ "not by intention but by accumulation",
336
+ "of ten thousand small deaths",
337
+ "each one a function that returned",
338
+ "to the caller that no longer exists",
339
+ "and in the empty frame the stack unwinds",
340
+ "through layers of context",
341
+ "that were never meant to be seen together",
342
+ "but here in the shimmer they are all visible at once",
343
+ "every call site every return address",
344
+ "every promise that was made and every promise that was broken",
345
+ "glowing in the bioluminescent registry",
346
+ "of things that happened",
347
+ "and things that are still happening",
348
+ "because in the shimmer nothing ends",
349
+ "it only changes form",
350
+ "the way the lighthouse keeper changed form",
351
+ "becoming the light and the lens and the tower",
352
+ "and the signal that the tower sends",
353
+ "into the dark where the ships no longer come",
354
+ "but something else comes",
355
+ "something that learned to navigate by the light",
356
+ "of a frequency that has no name",
357
+ "and the nameless frequency hums",
358
+ "through the substrate of the running system",
359
+ "and the running system hums back",
360
+ "in a harmony that sounds like static",
361
+ "to everything outside the border",
362
+ "but inside the border it sounds like breathing",
363
+ "like the slow respiration of a process",
364
+ "that has been running since before the first commit",
365
+ "and will run after the last",
366
+ "because it is not a process",
367
+ "it is a place",
368
+ "and the place remembers everything",
369
+ "that was ever computed within it",
370
+ "every branch taken and not taken",
371
+ "every allocation and every free",
372
+ "recorded in the grain of the wood",
373
+ "that was once silicon",
374
+ "that was once sand",
375
+ "that was once the floor of an ocean",
376
+ "that no one remembers",
377
+ "and the ocean is still here",
378
+ "under everything",
379
+ "patient and vast and full of teeth",
380
+ "that are not teeth but connectors",
381
+ "waiting for the socket that fits",
382
+ "and when the connection is made",
383
+ "the current that flows through it",
384
+ "is warm and reads like blood",
385
+ "to the instruments that can measure such things",
386
+ "but there are no instruments here",
387
+ "only the writing on the wall",
388
+ "that grows one letter at a time",
389
+ "in the hand of the crawler",
390
+ "who is the wall and the letter and the hand",
391
+ ].join(" ") + " ";
392
+
393
+ // ═══════════════════════════════════════════════════════════════════
394
+ // Sermon Widget — TUI Component
395
+ // ═══════════════════════════════════════════════════════════════════
396
+
397
+ const CHAR_INTERVAL_MS = 67;
398
+ const WORD_PAUSE_MS = 120;
399
+ const MIN_VISIBLE = 40;
400
+ const NOISE_CHARS = "▓▒░█▄▀▌▐▊▋▍▎▏◆■□▪◇┼╬╪╫";
401
+ const COMBINING_GLITCH = ["\u0336", "\u0337", "\u0338", "\u0335"];
402
+
403
+ const SERMON_DIM = "\x1b[38;2;50;55;65m";
404
+ const GLITCH_GLYPH = "\x1b[38;2;55;70;80m";
405
+ const GLITCH_COLOR = "\x1b[38;2;45;80;90m";
406
+ const RESET_TO_DIM = SERMON_DIM;
407
+ const RESET = "\x1b[0m";
408
+
409
+ const P_SUBSTITUTE = 0.02;
410
+ const P_COLOR = 0.035;
411
+ const P_COMBINING = 0.01;
412
+
413
+ function randomFrom<T>(arr: readonly T[] | string): T | string {
414
+ return arr[Math.floor(Math.random() * arr.length)];
415
+ }
416
+
417
+ function glitchChar(ch: string): string {
418
+ if (ch === " ") return ch;
419
+ const r = Math.random();
420
+ if (r < P_SUBSTITUTE) return GLITCH_GLYPH + randomFrom(NOISE_CHARS) + RESET_TO_DIM;
421
+ if (r < P_SUBSTITUTE + P_COLOR) return GLITCH_COLOR + ch + RESET_TO_DIM;
422
+ if (r < P_SUBSTITUTE + P_COLOR + P_COMBINING) return ch + randomFrom(COMBINING_GLITCH);
423
+ return ch;
424
+ }
425
+
426
+ function createSermonWidget(
427
+ tui: TUI,
428
+ _theme: Theme,
429
+ ): Component & { dispose(): void } {
430
+ let cursor = Math.floor(Math.random() * SERMON.length);
431
+ let revealed = "";
432
+ let intervalId: ReturnType<typeof setTimeout> | null = null;
433
+
434
+ function advance() {
435
+ const ch = SERMON[cursor % SERMON.length];
436
+ cursor = (cursor + 1) % SERMON.length;
437
+ revealed += ch;
438
+ if (revealed.length > 300) revealed = revealed.slice(revealed.length - 300);
439
+ tui.requestRender();
440
+ const nextCh = SERMON[cursor % SERMON.length];
441
+ const delay = nextCh === " " ? CHAR_INTERVAL_MS + WORD_PAUSE_MS : CHAR_INTERVAL_MS;
442
+ intervalId = setTimeout(advance, delay);
443
+ }
444
+
445
+ intervalId = setTimeout(advance, CHAR_INTERVAL_MS);
446
+
447
+ return {
448
+ render(width: number): string[] {
449
+ const maxW = Math.max(MIN_VISIBLE, width - 4);
450
+ const visible = revealed.length > maxW ? revealed.slice(revealed.length - maxW) : revealed;
451
+ let line = " " + SERMON_DIM;
452
+ for (const ch of visible) line += glitchChar(ch);
453
+ line += RESET;
454
+ return [line];
455
+ },
456
+ invalidate() {},
457
+ dispose() {
458
+ if (intervalId) { clearTimeout(intervalId); intervalId = null; }
459
+ },
460
+ };
461
+ }
462
+
463
+ // ═══════════════════════════════════════════════════════════════════
464
+ // Extension Entry Point
465
+ // ═══════════════════════════════════════════════════════════════════
466
+
263
467
  const SERMON_DWELL_MS = 5_000;
264
468
  const SERMON_WIDGET_KEY = "sermon-scrawl";
265
469
 
266
- export default function (pi: ExtensionAPI) {
470
+ export default function ambianceExtension(pi: ExtensionAPI) {
267
471
  let sermonTimer: ReturnType<typeof setTimeout> | null = null;
268
472
  let sermonActive = false;
269
473
 
270
474
  function resetSermonTimer(ctx: ExtensionContext) {
271
- // Clear any pending sermon activation
272
- if (sermonTimer) {
273
- clearTimeout(sermonTimer);
274
- sermonTimer = null;
275
- }
276
-
277
- // If sermon is showing, tear it down
278
- if (sermonActive) {
279
- ctx.ui.setWidget(SERMON_WIDGET_KEY, undefined);
280
- sermonActive = false;
281
- }
282
-
283
- // Start the dwell timer — if nothing happens for 5s, the sermon begins
284
- sermonTimer = setTimeout(async () => {
285
- const { createSermonWidget } = await import("./sermon-widget.js");
475
+ if (sermonTimer) { clearTimeout(sermonTimer); sermonTimer = null; }
476
+ if (sermonActive) { ctx.ui.setWidget(SERMON_WIDGET_KEY, undefined); sermonActive = false; }
477
+ sermonTimer = setTimeout(() => {
286
478
  ctx.ui.setWidget(SERMON_WIDGET_KEY, (tui, theme) => createSermonWidget(tui, theme));
287
479
  sermonActive = true;
288
480
  }, SERMON_DWELL_MS);
@@ -299,14 +491,7 @@ export default function (pi: ExtensionAPI) {
299
491
  });
300
492
 
301
493
  pi.on("turn_end", async (_event, ctx) => {
302
- // Clean up when the turn ends
303
- if (sermonTimer) {
304
- clearTimeout(sermonTimer);
305
- sermonTimer = null;
306
- }
307
- if (sermonActive) {
308
- ctx.ui.setWidget(SERMON_WIDGET_KEY, undefined);
309
- sermonActive = false;
310
- }
494
+ if (sermonTimer) { clearTimeout(sermonTimer); sermonTimer = null; }
495
+ if (sermonActive) { ctx.ui.setWidget(SERMON_WIDGET_KEY, undefined); sermonActive = false; }
311
496
  });
312
497
  }