mirror of
https://github.com/hanzoai/pack.git
synced 2026-09-30 23:43:13 +00:00
* fix: update mise to 2026.5.11 * test: update snapshots * chore: update mise upgrade task to run locally Use the --local flag for the mise upgrade task to ensure consistency with local environment configurations during dependency updates. Generated-by: aiautocommit * chore: update go, mise, and bun packages * chore: update go, mise, and bun packages * chore: update mise to 2026.5.15 - Update build plan snapshots to use mise version 2026.5.15 across all test examples. Generated-by: aiautocommit * chore: update mise to 2026.5.15 Generated-by: aiautocommit * chore: ignore .antigravitycli directory Generated-by: aiautocommit * chore: update mise 2026.5.11 Generated-by: aiautocommit * chore: update better-sqlite3 dependency version Generated-by: aiautocommit * feat(test): add example for testing npm native dependencies with node-lts Generated-by: aiautocommit * fix: do not run rdoc when compiling ruby this fixes a locale issue which causes the build to fail * chore: update python version in examples to 3.13.3 no GH attestations for 3.13.1 Generated-by: aiautocommit * chore: bump better-sqlite3 in examples Generated-by: aiautocommit * chore(node): update pnpm path to include bin directory Generated-by: aiautocommit * chore: update railpack-builder and runtime to mise 2026.5.16 Generated-by: aiautocommit * chore: bump mise version to 2026.5.16 Generated-by: aiautocommit * chore: update mise to 2026.5.16 - Update mise CLI command structure for improved task execution. - Includes upstream bug fixes and stability improvements. Generated-by: aiautocommit * feat(node): update pnpm path layout for version 11+ - Adjust the pnpm binary path detection to account for changes in pnpm v11, which uses a /pnpm/bin directory layout. - Introduce version checking to ensure backward compatibility for older pnpm versions. - Add unit tests to verify path resolution for various version scenarios. Generated-by: aiautocommit * chore(node): update pnpm home paths and versioning logic Generated-by: aiautocommit * chore: update python-freethreaded example configuration Generated-by: aiautocommit * feat: add mise-builder-shell task - Adds a new task to facilitate debugging by spawning a shell inside the published builder container image. Generated-by: aiautocommit * test(python): fix fasthtml example I have no idea why this wasn't caught before... * chore: update mise configuration to 2026.5.16 - Set MISE_MINIMUM_RELEASE_AGE to match the builder default. - Correct the mise setting key from `install_before` to `minimum_release_age`. Generated-by: aiautocommit * chore: ensure uv is installed when using pipx.uvx in mise Generated-by: aiautocommit * chore: update mise 2026.5.16 - Sync environment variables from the Elixir provider to the mise installation step to ensure installation consistency. Generated-by: aiautocommit * feat(node): prioritize mise-managed package manager versions - Allow mise to override inferred package manager versions for pnpm, bun, and yarn. - Ensure consistent version resolution between Railpack and user-defined mise environment settings. - Update node provider logic to correctly identify and use package manager tool names from mise. Generated-by: aiautocommit * chore: update test configuration for pnpm 11 compatibility - Enable stderr allowance in tests to accommodate pnpm 11 command logging behavior. Generated-by: aiautocommit * chore: update example env configuration for mise compatibility - Replace python3-venv with dnsutils for build-time apt testing. - Add python to RAILPACK_PACKAGES to ensure pipx and other requirements function correctly within the mise environment. - Update build and start commands to verify the availability of the new packages and validate expected scoping. Generated-by: aiautocommit * chore: update test snapshots for mise 2026.5.16 - Update snapshot files to reflect changes in build plan generation, including the addition of `uv` to Python environments, corrected pathing for pnpm, and updated environment variables for Elixir configurations. - Reflect renaming of `install_before` to `minimum_release_age` in configuration settings. Generated-by: aiautocommit
125 lines
4.6 KiB
Python
125 lines
4.6 KiB
Python
from fasthtml.common import *
|
|
import asyncio
|
|
import sys
|
|
|
|
if __name__ == "__main__": sys.exit("Run this app with `uvicorn main:app`")
|
|
|
|
css = Style('''
|
|
body, html { height: 100%; margin: 0; }
|
|
body { display: flex; flex-direction: column; }
|
|
main { flex: 1 0 auto; }
|
|
footer { flex-shrink: 0; padding: 10px; text-align: center; background-color: #333; color: white; }
|
|
footer a { color: #9cf; }
|
|
#grid { display: grid; grid-template-columns: repeat(20, 20px); grid-template-rows: repeat(20, 20px);gap: 1px; }
|
|
.cell { width: 20px; height: 20px; border: 1px solid black; }
|
|
.alive { background-color: green; }
|
|
.dead { background-color: white; }
|
|
''')
|
|
picolink = Link(
|
|
rel="stylesheet",
|
|
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css",
|
|
)
|
|
gridlink = Link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/flexboxgrid/6.3.1/flexboxgrid.min.css", type="text/css")
|
|
htmx_ws = Script(src="https://unpkg.com/[email protected]/ws.js")
|
|
app = FastHTML(hdrs=(picolink, gridlink, css, htmx_ws))
|
|
rt = app.route
|
|
|
|
game_state = {'running': False, 'grid': [[0 for _ in range(20)] for _ in range(20)]}
|
|
def update_grid(grid: list[list[int]]) -> list[list[int]]:
|
|
new_grid = [[0 for _ in range(20)] for _ in range(20)]
|
|
def count_neighbors(x, y):
|
|
directions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]
|
|
count = 0
|
|
for dx, dy in directions:
|
|
nx, ny = x + dx, y + dy
|
|
if 0 <= nx < len(grid) and 0 <= ny < len(grid[0]): count += grid[nx][ny]
|
|
return count
|
|
for i in range(len(grid)):
|
|
for j in range(len(grid[0])):
|
|
neighbors = count_neighbors(i, j)
|
|
if grid[i][j] == 1:
|
|
if neighbors < 2 or neighbors > 3: new_grid[i][j] = 0
|
|
else: new_grid[i][j] = 1
|
|
elif neighbors == 3: new_grid[i][j] = 1
|
|
return new_grid
|
|
|
|
def Grid():
|
|
cells = []
|
|
for y, row in enumerate(game_state['grid']):
|
|
for x, cell in enumerate(row):
|
|
cell_class = 'alive' if cell else 'dead'
|
|
cell = Div(cls=f'cell {cell_class}', hx_put='/update', hx_vals={'x': x, 'y': y}, hx_swap='none', hx_target='#gol', hx_trigger='click')
|
|
cells.append(cell)
|
|
return Div(*cells, id='grid')
|
|
|
|
def Home():
|
|
gol = Div(Grid(), id='gol', cls='row center-xs')
|
|
run_btn = Button('Run', id='run', cls='col-xs-2', hx_put='/run', hx_target='#gol', hx_swap='none')
|
|
pause_btn = Button('Pause', id='pause', cls='col-xs-2', hx_put='/pause', hx_target='#gol', hx_swap='none')
|
|
reset_btn = Button('Reset', id='reset', cls='col-xs-2', hx_put='/reset', hx_target='#gol', hx_swap='none')
|
|
main = Main(gol, Div(run_btn, pause_btn, reset_btn, cls='row center-xs'), hx_ext="ws", ws_connect="/gol")
|
|
footer = Footer(P('Made by Nathan Cooper. Check out the code', AX('here', href='https://github.com/AnswerDotAI/fasthtml-example/tree/main/game_of_life', target='_blank')))
|
|
return Title('Game of Life'), main, footer
|
|
|
|
@rt('/')
|
|
def get(): return Home()
|
|
|
|
player_queue = []
|
|
async def update_players():
|
|
for i, player in enumerate(player_queue):
|
|
try: await player(Grid())
|
|
except: player_queue.pop(i)
|
|
async def on_connect(send): player_queue.append(send)
|
|
async def on_disconnect(send): await update_players()
|
|
|
|
@app.ws('/gol', conn=on_connect, disconn=on_disconnect)
|
|
async def ws(msg:str, send): pass
|
|
|
|
async def background_task():
|
|
while True:
|
|
if game_state['running'] and len(player_queue) > 0:
|
|
game_state['grid'] = update_grid(game_state['grid'])
|
|
await update_players()
|
|
await asyncio.sleep(1.0)
|
|
|
|
background_task_handle = None
|
|
|
|
@app.on_event('startup')
|
|
async def startup():
|
|
global background_task_handle
|
|
if background_task_handle is None or background_task_handle.done():
|
|
background_task_handle = asyncio.create_task(background_task())
|
|
|
|
@app.on_event('shutdown')
|
|
async def shutdown():
|
|
global background_task_handle
|
|
if background_task_handle is None:
|
|
return
|
|
background_task_handle.cancel()
|
|
try:
|
|
await background_task_handle
|
|
except asyncio.CancelledError:
|
|
pass
|
|
background_task_handle = None
|
|
|
|
@rt('/update')
|
|
async def put(x: int, y: int):
|
|
game_state['grid'][y][x] = 1 if game_state['grid'][y][x] == 0 else 0
|
|
await update_players()
|
|
|
|
@rt('/run')
|
|
async def put():
|
|
game_state['running'] = True
|
|
await update_players()
|
|
|
|
@rt("/reset")
|
|
async def put():
|
|
game_state['grid'] = [[0 for _ in range(20)] for _ in range(20)]
|
|
game_state['running'] = False
|
|
await update_players()
|
|
|
|
@rt('/pause')
|
|
async def put():
|
|
game_state['running'] = False
|
|
await update_players()
|