Building from Source
AI Supreme Council is a single-file HTML application assembled from 80 modular source files in src/. This guide covers the full build pipeline, from TypeScript compilation to final assembly.
Prerequisites
- Node.js 20+ and npm
- Bash (Linux/macOS, or WSL on Windows)
- Python 3.10+ (for registry validation only)
Setup
Clone the repository and install development dependencies:
git clone https://github.com/nicholasgasior/bcz.git
cd bcz
npm install
This installs:
- esbuild -- TypeScript type-stripping (no bundling)
- vitest + jsdom -- Testing framework
- typescript -- Type checking (
tsc --noEmit)
These are development dependencies only. Nothing from node_modules ships to the browser. The production output is a single index.html with zero external dependencies.
Build Steps
1. TypeScript Compilation
If you have TypeScript modules in modules/*/index.ts, compile them first:
npm run build:ts
Or compile a single module:
node scripts/compile-ts.js grid
build.sh automatically runs TypeScript compilation if esbuild is installed. You only need to run npm run build:ts manually if you want to compile without assembling.
2. Assembly
Concatenate all 80 source parts into index.html:
./build.sh
Output:
Compiling TypeScript modules...
grid: modules/grid/index.ts -> src/grid.js
Compiled 1 module.
Built index.html (15432 lines, 982451 bytes) from 80 parts
3. Verification
Check that src/ matches the current index.html without overwriting:
./build.sh --check
Output on match:
OK: src/ matches index.html (80 parts)
Output on mismatch:
MISMATCH: src/ does not match index.html
TypeScript Pipeline
The TypeScript pipeline is a lightweight type-stripping system, not a bundler.
How It Works
For each module in modules/*/:
- Source:
modules/{name}/index.ts-- TypeScript source with types - Wrapper:
modules/{name}/wrapper.txt-- IIFE template with{CODE}and{Name}placeholders - Output:
src/{name}.js-- Ready-to-concatenate<script>block
The scripts/compile-ts.js script:
- Reads the TypeScript source
- Calls
esbuild.transformSync()to strip types (no bundling, no format conversion) - Removes any
import/exportstatements (the module is wrapped in an IIFE) - Indents the code and inserts it into the wrapper template
- If the code defines
__exports, appendsreturn __exports;
Wrapper Template
Each TypeScript module has a wrapper.txt that defines the <script> envelope:
<script>
// ============================================================================
// MODULE: AIS.{Name} (compiled from TypeScript)
// ============================================================================
if (!AIS.{Name}) AIS.lazy('{Name}', function() {
'use strict';
{CODE}
});
</script>
The {Name} placeholder is replaced with the capitalized module name (e.g., grid becomes Grid). The {CODE} placeholder is replaced with the type-stripped, indented source.
Writing TypeScript Modules
Use the var __exports = {...} pattern for the module's public API:
// modules/mymodule/index.ts
interface MyConfig {
name: string;
value: number;
}
function doSomething(config: MyConfig): string {
return config.name + ': ' + config.value;
}
var __exports = {
doSomething,
};
Do not use bare return statements -- they cause errors with tsc --noEmit. Use var __exports = {...} and compile-ts.js will append return __exports; automatically.
Do not set format: 'esm' in esbuild options. This causes CommonJS wrapping that breaks the IIFE pattern. The compile script omits the format option intentionally.
Type Checking
Run the TypeScript compiler in check-only mode (no output):
npm run check
This uses tsc --noEmit with the project tsconfig.json. Type definitions are in:
core-types/index.d.ts-- FullAISnamespace typescore-types/grid.d.ts-- Grid-specific types
Source File Order
The order of files in build.sh is critical. The PARTS array defines the exact concatenation sequence:
Shell (HTML/CSS/DOM):
shell-head.html # DOCTYPE, meta tags, early redirect
shell-style.html # Classless CSS styles
shell-body.html # HTML body, layout, dialogs, forms
Core Modules (single <script> block):
core-boot.js # <script> tag, AIS namespace, event bus, lazy loader
core-auth-main.js # OAuth, Google Sign-In
core-auth-local.js # Local accounts, device password
core-auth-init.js # Auth UI wiring, init, export
core-billing.js # Subscription tier, trial
core-ads.js # Static ad system
core-codec.js # Base80, VLQ, compression
core-storage.js # IndexedDB + SQLite
core-providers.js # SSE factory, registration API
core-providers-builtin.js # Built-in provider definitions
core-ui.js # DOM utils, markdown, toast
core-session.js # Bot session CRUD
core-chat.js # Messages, streaming
core-config.js # Bot config panel
core-app-botlist.js # Bot list, context menu
core-app-switch.js # switchBot, createBot, mega menu
core-app-events.js # bindEvents, council UI
core-app-search.js # Search, export, import, addons
core-app-init.js # Council helpers, init, boot
core-end.js # </script>
WASM-Replaceable (each in own <script>):
registry.js, grid.js, council.js, wizard.js,
vision.js, memory.js, imagegen.js, tools.js,
reminders.js, themes.js, templates-registry.js,
model-picker.js
Infrastructure:
kernel-bootstrap.html, moduleloader.js, plugins.js,
mcp.js, channels-*.js, sandbox.js, publish.js,
perf.js, p2p.js, profiles.js, cron.js
Platform:
settings-main.js, i18n.js, miniprograms.js,
docs.js, billing-ui.js, pwa.js
Tail:
shell-bottom.js # Welcome screen handler, closing tags
Do not rearrange the file order. Core modules share a single <script> block opened by core-boot.js and closed by core-end.js. Inserting a file between them that contains </script> will break the build.
Running Tests
The test suite uses Vitest with a jsdom environment.
# Run all tests once
npm test
# Run tests in watch mode (re-runs on file changes)
npm run test:watch
# Run only TypeScript module tests
npm run test:modules
# Run a specific test suite
npm run test:settings
Worker tests run separately from within the worker/ directory:
cd worker
npm test
Development Workflow
The standard edit-build-test cycle:
# 1. Edit source files
$EDITOR src/core-chat.js
# 2. Assemble into index.html
./build.sh
# 3. Test in browser
# Open index.html or use a local server
# 4. Run tests
npm test
# 5. Verify build integrity
./build.sh --check
For TypeScript modules:
# 1. Edit TypeScript source
$EDITOR modules/grid/index.ts
# 2. Type-check
npm run check
# 3. Compile + assemble (build.sh does both)
./build.sh
# 4. Test
npm run test:modules
Adding a New Module
To add a new lazy-loaded module:
- Create
src/mymodule.jswith the standard pattern:
<script>
if (!AIS.MyModule) AIS.lazy('MyModule', function() {
'use strict';
function doWork() { /* ... */ }
return { doWork };
});
</script>
-
Add the file to the
PARTSarray inbuild.shat the appropriate position. -
Run
./build.shto verify it assembles correctly.
To add a new TypeScript module:
- Create
modules/mymodule/index.tswith the source code. - Create
modules/mymodule/wrapper.txtwith the IIFE template (copy from an existing module likemodules/grid/wrapper.txt). - Optionally add type definitions to
core-types/index.d.ts. - Add
src/mymodule.jsto thePARTSarray inbuild.sh. - Run
./build.sh.
Registry Validation
The model and package registries have validation scripts:
# Validate model registry
python3 registry/validate.py
# Validate package registry
python3 registry/validate.py packages
# Validate a single manifest
python3 registry/validate.py manifest examples/hello-world/manifest.json
WASM Kernel (Optional)
The WASM kernel is an optional component. Building it requires Zig 0.14.0+:
cd kernel
../tools/zig/zig build # outputs zig-out/bin/kernel.wasm (~5.5 KB)
The kernel is not required for the main application to function. All kernel features have JavaScript fallbacks.