Conversation
…d "hardcore" bots
…"hardcore" TypeScript bots
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRefactors the TypeScript client library to a module-level functional API with global state and action primitives; adds full-path Dijkstra pathfinding; updates Dockerfiles and Bun build stages; migrates hardcore/softcore bots to the new API; adds game/server configs and package build scripts with local dependency path changes. Changes
Sequence Diagram(s)sequenceDiagram
participant Bot as Bot Code (onTick)
participant ClientLib as `@core/client-lib`
participant Socket as Socket
participant Server as Game Server
Bot->>ClientLib: startGame(name, onTick)
ClientLib->>Socket: connect(host, port)
Socket->>Server: connect / handshake
Server-->>Socket: welcome + initial config
Socket-->>ClientLib: data chunks (lines)
ClientLib->>ClientLib: parse lines → update game state
ClientLib->>Bot: invoke onTick()
Bot->>ClientLib: coreCreateUnit / coreActionPathfind (enqueue actions)
ClientLib->>Socket: sendActions(payload)
Socket->>Server: actions received
Server-->>Socket: tick updates
Socket-->>ClientLib: tick data → loop
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
# Conflicts: # .github/workflows/my-core-bot-ts-Dockerfile # bots/ts/client_lib/client_lib.ts # bots/ts/hardcore/.devcontainer/docker-compose.yml # bots/ts/hardcore/gridmaster/index.ts # bots/ts/hardcore/gridmaster/package.json # bots/ts/hardcore/my-core-bot/index.ts # bots/ts/hardcore/my-core-bot/package.json # bots/ts/hardcore/scripts/check_update_configs.sh # bots/ts/softcore/gridmaster/index.ts # bots/ts/softcore/gridmaster/package.json # bots/ts/softcore/my-core-bot/index.ts # bots/ts/softcore/my-core-bot/package.json
There was a problem hiding this comment.
Pull request overview
This pull request adds comprehensive TypeScript support for the Core game bot project, introducing a new TypeScript client library and bot implementations for both hardcore and softcore game modes. The PR establishes TypeScript as a first-class language option alongside the existing C implementation.
Changes:
- Introduces a TypeScript client library (
bots/ts/client_lib/) with complete game state management and action APIs - Adds TypeScript bot starter code for hardcore and softcore modes with my-core-bot and gridmaster variants
- Implements Docker containerization and CI/CD pipeline integration for TypeScript bots
- Provides development environment setup with devcontainer configurations and Makefiles
Reviewed changes
Copilot reviewed 15 out of 19 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
bots/ts/client_lib/client_lib.ts |
Core TypeScript client library implementing socket communication, game state management, and action APIs |
bots/ts/client_lib/types.ts |
TypeScript type definitions for game objects, configurations, and actions |
bots/ts/client_lib/package.json |
Client library package configuration |
bots/ts/softcore/my-core-bot/index.ts |
Softcore bot implementation starter code |
bots/ts/softcore/gridmaster/index.ts |
Softcore gridmaster bot starter code |
bots/ts/hardcore/my-core-bot/index.ts |
Hardcore bot implementation starter code |
bots/ts/hardcore/gridmaster/index.ts |
Hardcore gridmaster bot starter code |
bots/ts/softcore/package.json |
Root package configuration for softcore bots |
bots/ts/hardcore/package.json |
Root package configuration for hardcore bots |
bots/ts/softcore/my-core-bot/package.json |
Package configuration for softcore my-core-bot |
bots/ts/hardcore/my-core-bot/package.json |
Package configuration for hardcore my-core-bot |
bots/ts/softcore/gridmaster/package.json |
Package configuration for softcore gridmaster |
bots/ts/hardcore/gridmaster/package.json |
Package configuration for hardcore gridmaster |
bots/ts/softcore/my-core-bot/bun.lock |
Bun lockfile for softcore my-core-bot dependencies |
bots/ts/softcore/gridmaster/bun.lock |
Bun lockfile for softcore gridmaster dependencies |
bots/ts/hardcore/my-core-bot/bun.lock |
Bun lockfile for hardcore my-core-bot dependencies |
bots/ts/hardcore/gridmaster/bun.lock |
Bun lockfile for hardcore gridmaster dependencies |
bots/ts/softcore/configs/game.config.json |
Softcore game configuration with 4 unit types |
bots/ts/softcore/configs/server.config.json |
Softcore server configuration |
bots/ts/hardcore/configs/game.config.json |
Hardcore game configuration with 5 unit types |
bots/ts/hardcore/configs/server.config.json |
Hardcore server configuration |
bots/ts/softcore/scripts/check_update_configs.sh |
Script to check and update config files from remote |
bots/ts/softcore/scripts/check_image_updates.sh |
Script to check and update Docker images |
bots/ts/hardcore/scripts/check_update_configs.sh |
Script to check and update config files from remote |
bots/ts/hardcore/scripts/check_image_updates.sh |
Script to check and update Docker images |
bots/ts/softcore/README.md |
Documentation for softcore TypeScript bot setup |
bots/ts/hardcore/README.md |
Documentation for hardcore TypeScript bot setup |
bots/ts/softcore/Makefile |
Build automation for softcore TypeScript bots |
bots/ts/hardcore/Makefile |
Build automation for hardcore TypeScript bots |
bots/ts/softcore/.gitignore |
Git ignore rules for softcore bots |
bots/ts/hardcore/.gitignore |
Git ignore rules for hardcore bots |
bots/ts/softcore/.devcontainer/docker-compose.yml |
Docker Compose configuration for softcore development |
bots/ts/hardcore/.devcontainer/docker-compose.yml |
Docker Compose configuration for hardcore development |
bots/ts/softcore/.devcontainer/devcontainer.json |
VS Code devcontainer configuration for softcore |
bots/ts/hardcore/.devcontainer/devcontainer.json |
VS Code devcontainer configuration for hardcore |
bots/ts/softcore/.devcontainer/init_docker.bash |
Docker initialization script for 42 Macs |
bots/ts/hardcore/.devcontainer/init_docker.bash |
Docker initialization script for 42 Macs |
bots/ts/softcore/.coreignore |
Empty coreignore file |
bots/ts/hardcore/.coreignore |
Empty coreignore file |
.github/workflows/my-core-bot-ts-Dockerfile |
Dockerfile for building TypeScript bot container |
.github/workflows/my-core-bot-c-Dockerfile |
Updated C bot Dockerfile with CMD instruction |
.github/workflows/game.yml |
CI/CD workflow updated to build and publish TypeScript bot images |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 9
♻️ Duplicate comments (1)
bots/ts/softcore/configs/server.config.json (1)
1-14: Same concerns asbots/ts/hardcore/configs/server.config.json.The
/workspaces/monoreporeplay path and the identical-to-hardcore content flagged above apply equally here. No additional issues.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/softcore/configs/server.config.json` around lines 1 - 14, The replayFolderPaths array contains an unsafe/overbroad path ("/workspaces/monorepo") and mirrors the hardcore config; remove the "/workspaces/monorepo" entry from replayFolderPaths, verify remaining paths are intentionally scoped (e.g., "/workspace/replays", "./replays", and the visualizer subpath), and if this file is meant to differ from bots/ts/hardcore/configs/server.config.json adjust any values (timeoutTicks/timeoutMs/clientWaitTimeoutMs/clientConnectTimeoutMs/clientPacketsMaxSizeKb/enableTerminalVisualizer) to reflect the correct environment rather than duplicating the hardcore config.
🧹 Nitpick comments (9)
.github/workflows/my-core-bot-c-Dockerfile (1)
38-39: Keep-alive CMD can mask failures in non-debug runs.If this image is used beyond CI/debug, consider an entrypoint that runs the intended process (or add a healthcheck) so unexpected exits don’t silently turn into idle containers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/my-core-bot-c-Dockerfile around lines 38 - 39, The Dockerfile currently ends with a keep-alive command (CMD ["tail", "-f", "/dev/null"]) which can mask process failures; replace this with a real ENTRYPOINT/CMD that launches the intended service process (or add a HEALTHCHECK) so container exits surface as failures—locate the CMD ["tail", "-f", "/dev/null"] line and either change it to run your application binary/entry script via ENTRYPOINT/CMD or add a HEALTHCHECK instruction that verifies the app health and fails when the app is not running..github/workflows/my-core-bot-ts-Dockerfile (2)
7-11: Consider--no-install-recommendsto slim the image.This reduces image size and attack surface without changing behavior.
Suggested tweak
-RUN apt-get update && \ - apt-get install -y make npm && \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends make npm && \ rm -rf /var/lib/apt/lists/*🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/my-core-bot-ts-Dockerfile around lines 7 - 11, Update the Dockerfile RUN that installs system packages (the `RUN apt-get update && apt-get install -y make npm && rm -rf /var/lib/apt/lists/*` line) to include `--no-install-recommends` (e.g., `apt-get install -y --no-install-recommends make npm`) to reduce image size and attack surface; keep the same cleanup of `/var/lib/apt/lists/*` and leave the `RUN bun add -g typescript` step unchanged.
19-21: Same keep-alive consideration here.If this image is used outside CI/debug, an entrypoint that runs the real process (or a healthcheck) will prevent “silent idle” containers after failures.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/my-core-bot-ts-Dockerfile around lines 19 - 21, The Dockerfile currently copies client libs (COPY bots/ts/client_lib/ /core/client_lib/) then uses a noop keep-alive CMD (CMD ["tail", "-f", "/dev/null"]) which can leave containers silently idle; replace the tail-based CMD with a real ENTRYPOINT/CMD that starts the intended bot process (or add a HEALTHCHECK) so failures surface and the container exits/updates health appropriately—ensure the new ENTRYPOINT invokes the actual runtime (the bot startup command) and that CI/debug overrides still work (or provide a separate debug target/image that retains the tail keep-alive).bots/ts/hardcore/configs/server.config.json (1)
1-14: Hardcore and softcoreserver.config.jsonare byte-for-byte identical — consider a shared config.If the intent is genuinely the same settings for both modes, a single shared config (referenced by both) avoids future drift. If the modes are supposed to have different timeouts or packet limits, the values should diverge here now.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/hardcore/configs/server.config.json` around lines 1 - 14, Both hardcore and softcore server.config.json are identical; create a single shared JSON (e.g., server.config.shared.json) containing the common keys (timeoutTicks, timeoutMs, clientWaitTimeoutMs, clientConnectTimeoutMs, clientPacketsMaxSizeKb, replayFolderPaths, enableTerminalVisualizer) and update the mode-specific configs to reference or load that shared config at runtime (or use a symlink) and apply only mode-specific overrides when needed so values don’t drift; ensure code that reads configs (the loader that currently reads server.config.json for hardcore/softcore) is updated to merge the shared config with any override file.bots/ts/client_lib/client_lib.ts (4)
169-184: Default object is missingtypeandhpfields; suppressed withas Obj.The newly initialized object omits
typeandhp, relying onupdateObjectPropertiesto fill them from the same diff. While this works if the server always sends these fields for new objects, theas Objcast masks a genuine type incompleteness. Providing explicit defaults (e.g.,type: ObjType.UNIT, hp: 0) would make the code safer and remove the need for the cast.♻️ Add explicit defaults
obj = { id, + type: ObjType.UNIT, state: ObjState.ALIVE, pos: {x: 0, y: 0}, + hp: 0, s_core: {team_id: 0, gems: 0, spawn_cooldown: 0, balance: 0}, s_unit: {unit_type: 0, team_id: 0, gems: 0, action_cooldown: 0, balance: 0}, s_deposit_gems_pile: {gems: 0}, s_bomb: {countdown: 0} - } as Obj; + };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 169 - 184, The new object created in findOrInitializeObject is missing required Obj fields `type` and `hp` and currently uses an `as Obj` cast to suppress the type error; update the initializer to include explicit defaults for `type` (e.g., ObjType.UNIT or another appropriate ObjType) and `hp` (e.g., 0) so the literal conforms to Obj, remove the `as Obj` cast, and keep the rest of the default properties (id, state, pos, s_core, s_unit, s_deposit_gems_pile, s_bomb) unchanged.
26-53: Promise resolve nullification is fragile.The
(resolve as any) = nullcast on line 39 to prevent double-resolution is a code smell. A cleaner approach is to use aresolvedboolean flag.Also, if the socket emits
errorafterresolvehas already been called,reject(err)becomes a no-op (Promise spec), which is fine — but consider that an error before the firstgamestate would reject, while an error after would be silently swallowed. You may want to log or handle post-connect errors differently.♻️ Suggested: use a boolean flag instead of nulling resolve
async function connectInternal(): Promise<void> { return new Promise((resolve, reject) => { socket = new net.Socket(); + let resolved = false; socket.connect(port, host, () => { if (debug) console.log(`Connected to ${host}:${port}`); sendLogin(); }); socket.on('data', (data: Buffer) => { handleData(data); - if (game && resolve) { + if (game && !resolved) { + resolved = true; resolve(); - (resolve as any) = null; } }); socket.on('error', (err) => { console.error('Socket error:', err); - reject(err); + if (!resolved) reject(err); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 26 - 53, The connectInternal Promise uses a fragile "(resolve as any) = null" to avoid double-resolve; replace that with a boolean flag (e.g., "resolved") declared in connectInternal and set to true when you call resolve in socket.on('data') (check game before resolving), and guard both resolve() and reject() with that flag to avoid double-set; also in socket.on('error') if resolved is already true, log the error (via console.error or debug) instead of calling reject so post-connect errors are surfaced, and ensure socket.on('close') behavior remains unchanged in connectInternal.
195-211:updateTypeSpecificPropertiesblindly sets fields on all sub-objects regardless of type.When
diff.gemsis received, the function writes it tos_core.gems,s_core.balance,s_unit.gems,s_unit.balance, ands_deposit_gems_pile.gemssimultaneously. Similarly,diff.teamIdis written to boths_core.team_idands_unit.team_id. This means a unit'ss_corefields get polluted, and vice versa.Since
obj.typeis known at this point (set byupdateObjectProperties), consider dispatching on type to only update the relevant sub-struct. This avoids stale/misleading data in unrelated sub-objects, which could cause subtle bugs if bot code ever inspects the wrong sub-struct.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 195 - 211, The function updateTypeSpecificProperties currently writes diff fields into all sub-objects (s_core, s_unit, s_deposit_gems_pile) without considering obj.type; change it to branch on obj.type (the type set by updateObjectProperties) and only assign gems/teamId/ActionCooldown/SpawnCooldown/unit_type/countdown to the sub-structs relevant for that type (e.g., for "unit" update s_unit fields, for "core" update s_core, for "deposit_gems_pile" update s_deposit_gems_pile), leaving unrelated sub-objects untouched to avoid cross-pollution.
293-308: Module-level state is never reset between calls tostartGame.
game,actions,debugData,buffer, andsocketretain their values from any prior invocation. IfstartGameis called a second time (e.g., reconnect logic), stale state from the first run leaks in. Consider resetting all module-level state at the top ofstartGame.♻️ Reset state at the start of startGame
export async function startGame(teamName: string, onTick: () => void): Promise<void> { + // Reset module state + game = null; + socket = null; + actions = []; + debugData = []; + buffer = ''; + teamNameInternal = teamName; tickCallback = onTick;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 293 - 308, The module-level state (game, actions, debugData, buffer, socket, and any other globals like teamNameInternal/tickCallback) must be explicitly reset at the top of startGame to avoid leaking stale data between runs; modify startGame to reinitialize game = null, actions = [], debugData = {}, buffer = empty Buffer or new Uint8Array/[] as appropriate for your codebase, socket = null (and any other connection/state variables) before setting teamNameInternal/tickCallback and re-evaluating env/argv, then proceed to validateTeamId() and call connectInternal(); ensure the types you reset to match their original declarations.bots/ts/softcore/gridmaster/index.ts (1)
22-22: Add.catch()to handle connection failures.Same unhandled-rejection concern as the other bot entry points.
Proposed fix
-startGame("Gridmaster TS Core Bot", onTick) +startGame("Gridmaster TS Core Bot", onTick).catch((err) => { + console.error("Failed to start game:", err); + process.exit(1); +});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/softcore/gridmaster/index.ts` at line 22, The call to startGame("Gridmaster TS Core Bot", onTick) lacks rejection handling; update the invocation of startGame to append a .catch handler that logs the error (including the error object) and exits/cleans up as appropriate—e.g., startGame(..., onTick).catch(err => { processLogger.error("Failed to start Gridmaster TS Core Bot", err); process.exit(1); })—so connection failures from startGame and onTick are handled; ensure you reference the existing startGame function and onTick callback when adding the catch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@bots/ts/client_lib/client_lib.ts`:
- Around line 48-51: The socket close handler currently calls process.exit(0)
unconditionally in socket.on('close'), which masks abnormal disconnects; change
the handler to detect unexpected closes (e.g., accept the close callback
parameter like hadError or check socket.destroyed/lastError) and log a warning
when debug is enabled, then call process.exit with a non-zero code for
unexpected failures while retaining exit code 0 for intentional/clean shutdowns;
update the socket.on('close') callback and replace the unconditional
process.exit(0) accordingly, keeping the debug console.log behavior.
In `@bots/ts/hardcore/configs/game.config.json`:
- Line 24: The comment for the JSON key bombThrowCost is a stale copy of
wallBuildCost; update the inline comment next to "bombThrowCost" to accurately
describe that this value is the number of gems a bomb/bomb-builder must pay to
throw or plant a bomb (not to build a wall), referencing the "bombThrowCost" key
so the intent matches the value and is distinct from "wallBuildCost".
In `@bots/ts/hardcore/configs/server.config.json`:
- Line 4: The config currently lists "/workspaces/monorepo" which causes replay
files to be written to the repository root because server code (see
replayFolderPaths iteration in ReplayEncoder.cpp that writes replaySaveFolder +
"/replay_latest.json") writes directly to each configured path; update the four
server configs (both C and TS, hardcore and softcore) to remove the root path or
replace it with a dedicated subdirectory such as "/workspaces/monorepo/replays"
so that replayFolderPaths points to a safe replay subdirectory and prevents
scattering files into the repo root.
In `@bots/ts/hardcore/gridmaster/index.ts`:
- Line 22: The call to the async function startGame("Gridmaster TS Core Bot",
onTick) is not awaited or handled, causing unhandled Promise rejections; update
the invocation of startGame to handle rejections (e.g., append .catch(...) and
log the error via your logger or console.error) so connection/errors are
surfaced and the process can fail gracefully; reference the startGame call and
onTick handler when adding the .catch to ensure any thrown error from startGame
is logged.
- Around line 9-18: The code calls game?.objects.forEach without guarding
game.objects, which can throw if game is non-null but objects is undefined;
update the loop to use optional chaining on objects (i.e., change the call site
that iterates over game.objects to use game?.objects?.forEach) so the iteration
only runs when objects is defined, keeping the existing logic around
opponentCore and coreActionMove intact.
In `@bots/ts/softcore/configs/game.config.json`:
- Around line 21-24: The inline comment for the JSON key bombThrowCost is
misleading ("build a wall"); update the comment to accurately describe the value
as the number of gems required to throw/build a bomb, e.g., "amount of gems
required to throw/build a bomb" so future tuners understand the parameter
associated with bombThrowCost.
In `@bots/ts/softcore/gridmaster/index.ts`:
- Line 8: Replace the incorrect "// Hardcore bot logic" comment in
bots/ts/softcore/gridmaster/index.ts with a mode-accurate comment such as "//
Softcore bot logic" or a neutral phrase like "// Gridmaster bot logic" so the
comment matches the softcore implementation (look for the top-of-file comment in
index.ts and update it).
In `@bots/ts/softcore/my-core-bot/index.ts`:
- Line 8: Update the misleading comment in softcore/my-core-bot index.ts:
replace the copy-pasted "// Hardcore bot logic" comment with an accurate note
like "// Softcore bot logic" (or a brief description of the softcore-specific
behavior) so the comment matches the module identity; locate the comment in the
index.ts file inside the my-core-bot module and update the text accordingly.
- Line 22: The startGame call uses the wrong team name string and isn't handling
its promise; update the invocation of startGame (the call that currently passes
"Hardcore TS Core Bot" alongside onTick) to use the correct team name "Softcore
TS Core Bot" and convert the call to properly handle the returned Promise
(either await startGame(...) inside an async initializer or append .catch(...)
to log/handle connection errors) so unhandled promise rejections are prevented.
---
Duplicate comments:
In `@bots/ts/softcore/configs/server.config.json`:
- Around line 1-14: The replayFolderPaths array contains an unsafe/overbroad
path ("/workspaces/monorepo") and mirrors the hardcore config; remove the
"/workspaces/monorepo" entry from replayFolderPaths, verify remaining paths are
intentionally scoped (e.g., "/workspace/replays", "./replays", and the
visualizer subpath), and if this file is meant to differ from
bots/ts/hardcore/configs/server.config.json adjust any values
(timeoutTicks/timeoutMs/clientWaitTimeoutMs/clientConnectTimeoutMs/clientPacketsMaxSizeKb/enableTerminalVisualizer)
to reflect the correct environment rather than duplicating the hardcore config.
---
Nitpick comments:
In @.github/workflows/my-core-bot-c-Dockerfile:
- Around line 38-39: The Dockerfile currently ends with a keep-alive command
(CMD ["tail", "-f", "/dev/null"]) which can mask process failures; replace this
with a real ENTRYPOINT/CMD that launches the intended service process (or add a
HEALTHCHECK) so container exits surface as failures—locate the CMD ["tail",
"-f", "/dev/null"] line and either change it to run your application
binary/entry script via ENTRYPOINT/CMD or add a HEALTHCHECK instruction that
verifies the app health and fails when the app is not running.
In @.github/workflows/my-core-bot-ts-Dockerfile:
- Around line 7-11: Update the Dockerfile RUN that installs system packages (the
`RUN apt-get update && apt-get install -y make npm && rm -rf
/var/lib/apt/lists/*` line) to include `--no-install-recommends` (e.g., `apt-get
install -y --no-install-recommends make npm`) to reduce image size and attack
surface; keep the same cleanup of `/var/lib/apt/lists/*` and leave the `RUN bun
add -g typescript` step unchanged.
- Around line 19-21: The Dockerfile currently copies client libs (COPY
bots/ts/client_lib/ /core/client_lib/) then uses a noop keep-alive CMD (CMD
["tail", "-f", "/dev/null"]) which can leave containers silently idle; replace
the tail-based CMD with a real ENTRYPOINT/CMD that starts the intended bot
process (or add a HEALTHCHECK) so failures surface and the container
exits/updates health appropriately—ensure the new ENTRYPOINT invokes the actual
runtime (the bot startup command) and that CI/debug overrides still work (or
provide a separate debug target/image that retains the tail keep-alive).
In `@bots/ts/client_lib/client_lib.ts`:
- Around line 169-184: The new object created in findOrInitializeObject is
missing required Obj fields `type` and `hp` and currently uses an `as Obj` cast
to suppress the type error; update the initializer to include explicit defaults
for `type` (e.g., ObjType.UNIT or another appropriate ObjType) and `hp` (e.g.,
0) so the literal conforms to Obj, remove the `as Obj` cast, and keep the rest
of the default properties (id, state, pos, s_core, s_unit, s_deposit_gems_pile,
s_bomb) unchanged.
- Around line 26-53: The connectInternal Promise uses a fragile "(resolve as
any) = null" to avoid double-resolve; replace that with a boolean flag (e.g.,
"resolved") declared in connectInternal and set to true when you call resolve in
socket.on('data') (check game before resolving), and guard both resolve() and
reject() with that flag to avoid double-set; also in socket.on('error') if
resolved is already true, log the error (via console.error or debug) instead of
calling reject so post-connect errors are surfaced, and ensure
socket.on('close') behavior remains unchanged in connectInternal.
- Around line 195-211: The function updateTypeSpecificProperties currently
writes diff fields into all sub-objects (s_core, s_unit, s_deposit_gems_pile)
without considering obj.type; change it to branch on obj.type (the type set by
updateObjectProperties) and only assign
gems/teamId/ActionCooldown/SpawnCooldown/unit_type/countdown to the sub-structs
relevant for that type (e.g., for "unit" update s_unit fields, for "core" update
s_core, for "deposit_gems_pile" update s_deposit_gems_pile), leaving unrelated
sub-objects untouched to avoid cross-pollution.
- Around line 293-308: The module-level state (game, actions, debugData, buffer,
socket, and any other globals like teamNameInternal/tickCallback) must be
explicitly reset at the top of startGame to avoid leaking stale data between
runs; modify startGame to reinitialize game = null, actions = [], debugData =
{}, buffer = empty Buffer or new Uint8Array/[] as appropriate for your codebase,
socket = null (and any other connection/state variables) before setting
teamNameInternal/tickCallback and re-evaluating env/argv, then proceed to
validateTeamId() and call connectInternal(); ensure the types you reset to match
their original declarations.
In `@bots/ts/hardcore/configs/server.config.json`:
- Around line 1-14: Both hardcore and softcore server.config.json are identical;
create a single shared JSON (e.g., server.config.shared.json) containing the
common keys (timeoutTicks, timeoutMs, clientWaitTimeoutMs,
clientConnectTimeoutMs, clientPacketsMaxSizeKb, replayFolderPaths,
enableTerminalVisualizer) and update the mode-specific configs to reference or
load that shared config at runtime (or use a symlink) and apply only
mode-specific overrides when needed so values don’t drift; ensure code that
reads configs (the loader that currently reads server.config.json for
hardcore/softcore) is updated to merge the shared config with any override file.
In `@bots/ts/softcore/gridmaster/index.ts`:
- Line 22: The call to startGame("Gridmaster TS Core Bot", onTick) lacks
rejection handling; update the invocation of startGame to append a .catch
handler that logs the error (including the error object) and exits/cleans up as
appropriate—e.g., startGame(..., onTick).catch(err => {
processLogger.error("Failed to start Gridmaster TS Core Bot", err);
process.exit(1); })—so connection failures from startGame and onTick are
handled; ensure you reference the existing startGame function and onTick
callback when adding the catch.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
bots/ts/hardcore/gridmaster/bun.lockis excluded by!**/*.lockbots/ts/hardcore/my-core-bot/bun.lockis excluded by!**/*.lockbots/ts/softcore/gridmaster/bun.lockis excluded by!**/*.lockbots/ts/softcore/my-core-bot/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (15)
.github/workflows/my-core-bot-c-Dockerfile.github/workflows/my-core-bot-ts-Dockerfilebots/ts/client_lib/client_lib.tsbots/ts/hardcore/configs/game.config.jsonbots/ts/hardcore/configs/server.config.jsonbots/ts/hardcore/gridmaster/index.tsbots/ts/hardcore/gridmaster/package.jsonbots/ts/hardcore/my-core-bot/index.tsbots/ts/hardcore/my-core-bot/package.jsonbots/ts/softcore/configs/game.config.jsonbots/ts/softcore/configs/server.config.jsonbots/ts/softcore/gridmaster/index.tsbots/ts/softcore/gridmaster/package.jsonbots/ts/softcore/my-core-bot/index.tsbots/ts/softcore/my-core-bot/package.json
| # SHELL ["/bin/bash", "-c"] | ||
| # ENV SHELL=/bin/bash | ||
|
|
||
| CMD ["tail", "-f", "/dev/null"] |
There was a problem hiding this comment.
to keep the container running
There was a problem hiding this comment.
that is not necessary as the devcontainer extension handles that for you...
There was a problem hiding this comment.
this is still not necessary 😂
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
bots/ts/softcore/my-core-bot/index.ts (1)
20-20:⚠️ Potential issue | 🟠 MajorHandle
startGamepromise failures explicitly.Line 20 invokes async
startGame(...)withoutawait/.catch(). A connect/init failure can become an unhandled rejection and terminate the bot process.🐛 Proposed fix
-startGame("Softcore TS Core Bot", onTick) +void startGame("Softcore TS Core Bot", onTick).catch((err) => { + console.error("Failed to start game:", err); + process.exit(1); +});#!/bin/bash # Verify async startGame signature and fire-and-forget call sites. rg -nP --type=ts 'export\s+async\s+function\s+startGame\s*\(' -C2 rg -nP --type=ts '^\s*startGame\([^;]*\)\s*$' -g '!**/dist/**' -g '!**/build/**'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/softcore/my-core-bot/index.ts` at line 20, The call to startGame("Softcore TS Core Bot", onTick) is fire-and-forget and can produce unhandled promise rejections; update the invocation of startGame to handle promise failures explicitly (either await it from an async top-level init or attach a .catch handler) and in the catch log the error and terminate or retry as appropriate; locate the startGame call and change it so failures from startGame(...) are handled (reference symbols: startGame and onTick) and ensure the error handler uses the existing logger/process termination policy used elsewhere in the project.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@bots/ts/client_lib/package.json`:
- Line 8: Change the dependency entry for "@types/node" in package.json to a
published version (e.g. "@types/node": "25.3.2") and move it from "dependencies"
into "devDependencies" so the type package is only used at build time and won't
leak Node ambient types to consumers; update the package.json entries for the
dependency accordingly (ensure only one "@types/node" entry remains under
devDependencies and remove it from dependencies).
In `@bots/ts/hardcore/my-core-bot/index.ts`:
- Line 20: The call to startGame("Hardcore TS Core Bot", onTick) is
fire-and-forget and can reject; change it to handle the Promise by either
awaiting it inside an async wrapper or using .catch(...) to log the error and
exit gracefully. Locate the startGame invocation and replace the bare call with
e.g. an async IIFE that awaits startGame(...) and catches errors, or attach
startGame(...).catch(err => { console.error("startGame failed:", err);
process.exit(1); }), so failures from startGame (and underlying connectInternal)
are not left as unhandled rejections.
In `@bots/ts/softcore/gridmaster/index.ts`:
- Line 20: The call to startGame("Gridmaster TS Core Bot", onTick) returns a
Promise but is not handled; wrap the call to startGame (and the same calls in
my-core-bot and hardcore variants) so rejections are caught — e.g. use an async
IIFE or add .catch(err => { /* log error and exit */ }) to the Promise returned
by startGame, ensuring you log the error and call process.exit(1) (or
equivalent) on failure; locate the startGame(...) invocation and apply the
change there.
---
Duplicate comments:
In `@bots/ts/softcore/my-core-bot/index.ts`:
- Line 20: The call to startGame("Softcore TS Core Bot", onTick) is
fire-and-forget and can produce unhandled promise rejections; update the
invocation of startGame to handle promise failures explicitly (either await it
from an async top-level init or attach a .catch handler) and in the catch log
the error and terminate or retry as appropriate; locate the startGame call and
change it so failures from startGame(...) are handled (reference symbols:
startGame and onTick) and ensure the error handler uses the existing
logger/process termination policy used elsewhere in the project.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f2887b4b-2c6b-49ad-a161-43345f2ca4eb
📒 Files selected for processing (5)
bots/ts/client_lib/package.jsonbots/ts/hardcore/gridmaster/index.tsbots/ts/hardcore/my-core-bot/index.tsbots/ts/softcore/gridmaster/index.tsbots/ts/softcore/my-core-bot/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- bots/ts/hardcore/gridmaster/index.ts
…a-based pathfinding
…t object lookup, and pathfinding logic
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (4)
.github/workflows/my-core-bot-ts-Dockerfile (1)
7-11: Consider removing unusedmakeinstallation.The
makepackage is installed but TypeScript bots typically don't use Makefiles. The C bot Dockerfile installsmakefor itsRUN make restep, but there's no equivalent here. Ifmakeisn't required, removing it reduces image size and attack surface.Similarly, global
typescriptmay be redundant since Bun has built-in TypeScript support unless you specifically needtscfor type-checking.♻️ Suggested simplification if make is unused
-RUN apt-get update && \ - apt-get install -y make && \ - rm -rf /var/lib/apt/lists/* - -RUN bun add -g typescript🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/my-core-bot-ts-Dockerfile around lines 7 - 11, Remove the unnecessary packages from the Dockerfile: drop the apt-get install of make (the RUN command that includes "apt-get install -y make") if no Makefiles are used, and remove the global Bun install of TypeScript ("RUN bun add -g typescript") unless you explicitly rely on the tsc binary; rely on Bun's native TypeScript support instead. Update the Dockerfile RUN steps to only run apt-get update and clean up apt lists, and remove the bun add -g typescript line so the image is smaller and has less surface area.bots/ts/client_lib/client_lib.ts (3)
135-146: Variable shadowing: localgameshadows module-levelgame.Line 137 declares
const game = getGame()which shadows the module-levelgamevariable. While this works because mutations are applied to the returned object reference, the shadowing is confusing and could lead to bugs if someone later tries to reassigngamein this function expecting to affect module state.♻️ Rename local variable for clarity
function updateGameState(parsed: any): void { if (!parsed) return; - const game = getGame(); + const gameState = getGame(); if (parsed.tick !== undefined) { - game.elapsed_ticks = parsed.tick; + gameState.elapsed_ticks = parsed.tick; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 135 - 146, The local const named game in updateGameState shadows the module-level game variable; rename the local binding (e.g., localGame or currentState) to avoid shadowing and potential confusion, update all uses in updateGameState (where getGame() is called and properties like elapsed_ticks are set and applyDiff is passed objects) to reference the new name, and ensure no other functions are affected by the rename.
44-47: Promise resolution pattern could resolve multiple times or leak.The pattern of nullifying
resolveby casting toanyis fragile. If multipledataevents arrive before the promise settles, or if an error occurs after resolution, behavior is unpredictable. Consider using a boolean flag or resolving only once on a specific condition (e.g., whenisGameInitializedbecomes true).♻️ Suggested improvement
+ let resolved = false; socket.on('data', (data: Buffer) => { handleData(data); - if (game && resolve) { + if (game && !resolved) { + resolved = true; resolve(); - (resolve as any) = null; } });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 44 - 47, The current pattern in client_lib.ts where you call resolve() and then nullify it via (resolve as any) = null is fragile and can allow multiple resolutions or leaks if multiple data events arrive; update the logic around the resolve variable (used alongside game) to ensure the promise is settled exactly once—introduce a typed guard such as a boolean flag (e.g., isResolved) or reassign resolve to undefined via its declared type before calling, and only call resolve when game is truthy and the guard shows it hasn’t been settled (e.g., check !isResolved, set isResolved = true then invoke resolve), removing the unsafe (resolve as any) cast and preventing subsequent calls.
287-338:coreActionPathfinduses greedy heuristic—consider documenting limitations.This pathfinding implementation uses a simple greedy approach that considers only immediate neighbors. For complex maps with obstacles, it may fail to find paths or get stuck. The PR summary mentions Dijkstra-based pathfinding was added (
pathfinding.ts), but this function doesn't use it.Consider either:
- Documenting that this is a simple greedy pathfinder for straightforward scenarios
- Integrating with
pathfindFullPathDijkstrafrompathfinding.tsfor better results🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 287 - 338, coreActionPathfind currently uses a greedy one-step heuristic and should either be documented as such or replaced to use the full Dijkstra pathfinder; to fix, keep the current early guards (unit/type/cooldown/same-pos) but call pathfindFullPathDijkstra(unit.pos, pos) from pathfinding.ts to get the full path, take the next step from the returned path (or fallback to the existing greedy neighbors if no path), then inspect that nextPos with coreGetObjFromPos and use coreActionAttack or coreActionMove (and respect coreStaticIsFriendlyObj) instead of the current greedy selection; update coreActionPathfind to reference pathfindFullPathDijkstra, coreActionMove, coreActionAttack, coreGetObjFromPos, and coreStaticIsFriendlyObj or add a short comment stating the function is intentionally greedy if you choose to document limitations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/my-core-bot-ts-Dockerfile:
- Around line 15-19: The Dockerfile currently copies only /core/server,
/core/data and the client lib (/core/client_lib/) but omits the bot source and
has no container entrypoint; update the file to also COPY the bot source
directories (e.g., bots/ts/hardcore/my-core-bot/ or
bots/ts/softcore/my-core-bot/) into the image (e.g., /core/my-core-bot/) so the
package.json that references file:/core/client_lib/ is present, and add a CMD or
ENTRYPOINT that runs the bot start script (the package.json start script that
runs "bun run index.ts") so the container launches the bot on start.
In `@bots/ts/client_lib/client_lib.ts`:
- Around line 181-196: findOrInitializeObject is creating Obj instances missing
required fields type and hp, which can remain undefined if
updateObjectProperties never sets them; modify the initializer in
findOrInitializeObject to include sensible defaults for the missing properties
(e.g., type: 0 and hp: 0 or other domain-appropriate defaults) so every new
object pushed by getGame().objects has type and hp populated; update the object
literal created in findOrInitializeObject to include the type and hp keys
alongside id, state, pos, s_core, s_unit, s_deposit_gems_pile, and s_bomb so
consumers of Obj never see undefined for these fields.
In `@bots/ts/client_lib/pathfinding.ts`:
- Around line 5-23: The pathfinder repeatedly calls movementCostAt(pos) which
invokes coreGetObjFromPos() (a linear scan over game.objects), and also selects
the next node by scanning the whole grid; this makes the algorithm O(V²) with
many repeated object scans. Fix by precomputing a costGrid (e.g.,
computeCostGrid() that iterates once over all tiles and uses coreGetObjFromPos
to fill per-tile movement costs used by movementCostAt or replace movementCostAt
with a lookup into costGrid), and replace the full-grid min-node selection with
a binary-heap priority queue (min-heap) for the frontier used by your
pathfinding routine so neighbor relaxations use O(log V) push/pop instead of
scanning all nodes. Ensure you update references to movementCostAt and the
selection loop to use costGrid and the new PriorityQueue API consistently.
- Around line 104-107: The pathfinding currently forces stepCost = 1 for the
exact target (neighbor.x/y === target.x/y) which allows returning a path that
ends on an impassable tile; to guarantee returned paths are fully walkable,
after the path is reconstructed (the array built from the search result), check
the final step with movementCostAt(finalStep) and if it is impassable (cost
indicates WALL/CORE/RESOURCE) remove that final step before returning; also
update the function docstring to state explicitly that the returned path will
not include non-walkable terminal tiles. Ensure you adjust references to the
variables/methods used in the search (stepCost, movementCostAt, neighbor, and
the path reconstruction/return value) so callers get a fully walkable route.
In `@bots/ts/hardcore/my-core-bot/index.ts`:
- Around line 7-17: The code inconsistently uses optional chaining on
GameState.objects—change getGame().objects?.find(...) to
getGame().objects.find(...) so both uses of objects are non-optional; update the
expression that defines opponentCore (the call to getGame().objects.find with
ObjType.CORE and s_core.team_id) and keep the existing getGame().objects.forEach
and coreActionMove calls unchanged so null-safety matches the GameState.objects
typing.
In `@bots/ts/softcore/gridmaster/index.ts`:
- Around line 7-17: The optional chaining usage is inconsistent here—since
getGame() throws when uninitialized and GameState.objects is non-optional,
remove the unnecessary ?. occurrences so calls are consistent and non-optional;
specifically, use getGame().objects.find(...) (not getGame().objects?.find),
getGame().my_team_id (not getGame()?.my_team_id) and
getGame().objects.forEach(...) with getGame().my_team_id in the coreActionMove
loop, referencing the existing getGame(), GameState.objects, ObjType.CORE/UNIT
and coreActionMove symbols.
In `@bots/ts/softcore/my-core-bot/index.ts`:
- Around line 7-17: The code uses optional chaining on getGame().objects in the
opponentCore lookup but not in the subsequent forEach, causing inconsistent
null-safety; update the lookup to use the non-optional property (remove the ?.
so use getGame().objects.find(...)) since GameState.objects is typed as Obj[];
this makes the opponentCore assignment and the later
getGame().objects.forEach(...) consistent and avoids potential undefined
handling differences for opponentCore, getGame(), objects, ObjType, and
coreActionMove.
---
Nitpick comments:
In @.github/workflows/my-core-bot-ts-Dockerfile:
- Around line 7-11: Remove the unnecessary packages from the Dockerfile: drop
the apt-get install of make (the RUN command that includes "apt-get install -y
make") if no Makefiles are used, and remove the global Bun install of TypeScript
("RUN bun add -g typescript") unless you explicitly rely on the tsc binary; rely
on Bun's native TypeScript support instead. Update the Dockerfile RUN steps to
only run apt-get update and clean up apt lists, and remove the bun add -g
typescript line so the image is smaller and has less surface area.
In `@bots/ts/client_lib/client_lib.ts`:
- Around line 135-146: The local const named game in updateGameState shadows the
module-level game variable; rename the local binding (e.g., localGame or
currentState) to avoid shadowing and potential confusion, update all uses in
updateGameState (where getGame() is called and properties like elapsed_ticks are
set and applyDiff is passed objects) to reference the new name, and ensure no
other functions are affected by the rename.
- Around line 44-47: The current pattern in client_lib.ts where you call
resolve() and then nullify it via (resolve as any) = null is fragile and can
allow multiple resolutions or leaks if multiple data events arrive; update the
logic around the resolve variable (used alongside game) to ensure the promise is
settled exactly once—introduce a typed guard such as a boolean flag (e.g.,
isResolved) or reassign resolve to undefined via its declared type before
calling, and only call resolve when game is truthy and the guard shows it hasn’t
been settled (e.g., check !isResolved, set isResolved = true then invoke
resolve), removing the unsafe (resolve as any) cast and preventing subsequent
calls.
- Around line 287-338: coreActionPathfind currently uses a greedy one-step
heuristic and should either be documented as such or replaced to use the full
Dijkstra pathfinder; to fix, keep the current early guards
(unit/type/cooldown/same-pos) but call pathfindFullPathDijkstra(unit.pos, pos)
from pathfinding.ts to get the full path, take the next step from the returned
path (or fallback to the existing greedy neighbors if no path), then inspect
that nextPos with coreGetObjFromPos and use coreActionAttack or coreActionMove
(and respect coreStaticIsFriendlyObj) instead of the current greedy selection;
update coreActionPathfind to reference pathfindFullPathDijkstra, coreActionMove,
coreActionAttack, coreGetObjFromPos, and coreStaticIsFriendlyObj or add a short
comment stating the function is intentionally greedy if you choose to document
limitations.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 12b0c998-4d48-4349-95da-ee399303c7e0
📒 Files selected for processing (7)
.github/workflows/my-core-bot-ts-Dockerfilebots/ts/client_lib/client_lib.tsbots/ts/client_lib/pathfinding.tsbots/ts/hardcore/gridmaster/index.tsbots/ts/hardcore/my-core-bot/index.tsbots/ts/softcore/gridmaster/index.tsbots/ts/softcore/my-core-bot/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- bots/ts/hardcore/gridmaster/index.ts
| function findOrInitializeObject(id: number): Obj { | ||
| let obj = getGame().objects.find(o => o.id === id); | ||
| if (!obj) { | ||
| obj = { | ||
| id, | ||
| state: ObjState.ALIVE, | ||
| pos: {x: 0, y: 0}, | ||
| s_core: {team_id: 0, gems: 0, spawn_cooldown: 0, balance: 0}, | ||
| s_unit: {unit_type: 0, team_id: 0, gems: 0, action_cooldown: 0, balance: 0}, | ||
| s_deposit_gems_pile: {gems: 0}, | ||
| s_bomb: {countdown: 0} | ||
| } as Obj; | ||
| getGame().objects.push(obj); | ||
| } | ||
| return obj; | ||
| } |
There was a problem hiding this comment.
Missing type and hp fields when initializing new objects.
findOrInitializeObject creates objects without type or hp properties. The Obj interface requires these fields. If updateObjectProperties is never called with diff.type or diff.hp, the object will have undefined for these required fields, potentially causing runtime errors when consumers access them.
🐛 Proposed fix to include default values
if (!obj) {
obj = {
id,
state: ObjState.ALIVE,
+ type: ObjType.UNIT, // Default, will be overwritten by diff
+ hp: 0,
pos: {x: 0, y: 0},
s_core: {team_id: 0, gems: 0, spawn_cooldown: 0, balance: 0},🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@bots/ts/client_lib/client_lib.ts` around lines 181 - 196,
findOrInitializeObject is creating Obj instances missing required fields type
and hp, which can remain undefined if updateObjectProperties never sets them;
modify the initializer in findOrInitializeObject to include sensible defaults
for the missing properties (e.g., type: 0 and hp: 0 or other domain-appropriate
defaults) so every new object pushed by getGame().objects has type and hp
populated; update the object literal created in findOrInitializeObject to
include the type and hp keys alongside id, state, pos, s_core, s_unit,
s_deposit_gems_pile, and s_bomb so consumers of Obj never see undefined for
these fields.
| function movementCostAt(pos: Pos): number { | ||
| const anyObj = coreGetObjFromPos(pos); | ||
| if (!anyObj) { | ||
| return 1; // empty tile | ||
| } else { | ||
| switch (anyObj.type) { | ||
| case ObjType.WALL: | ||
| case ObjType.CORE: | ||
| case ObjType.RESOURCE: // OBJ_DEPOSIT in C | ||
| return Infinity; // impassable | ||
| case ObjType.UNIT: | ||
| case ObjType.MONEY: // OBJ_GEM_PILE in C | ||
| case ObjType.BOMB: | ||
| return 2; // passable, but costs more | ||
| default: | ||
| return 1; // unknown object, assume passable | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
This pathfinder will get expensive fast on non-trivial maps.
Each neighbor relaxation goes through movementCostAt(), which calls coreGetObjFromPos(); that helper does a game.objects.find(...) scan in bots/ts/client_lib/client_lib.ts:270-272. Combined with the full-grid min-node selection on Lines 79-84, one query is O(V²) in tiles plus repeated linear scans over game.objects. On a 100×100 grid, the selection loop alone is already ~100M comparisons per call. Please precompute per-tile costs once and use a min-heap / priority queue for the frontier.
Also applies to: 75-115
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@bots/ts/client_lib/pathfinding.ts` around lines 5 - 23, The pathfinder
repeatedly calls movementCostAt(pos) which invokes coreGetObjFromPos() (a linear
scan over game.objects), and also selects the next node by scanning the whole
grid; this makes the algorithm O(V²) with many repeated object scans. Fix by
precomputing a costGrid (e.g., computeCostGrid() that iterates once over all
tiles and uses coreGetObjFromPos to fill per-tile movement costs used by
movementCostAt or replace movementCostAt with a lookup into costGrid), and
replace the full-grid min-node selection with a binary-heap priority queue
(min-heap) for the frontier used by your pathfinding routine so neighbor
relaxations use O(log V) push/pop instead of scanning all nodes. Ensure you
update references to movementCostAt and the selection loop to use costGrid and
the new PriorityQueue API consistently.
| let stepCost = movementCostAt(neighbor); | ||
| // In C logic: if it's the target, cost is 1 (to be able to reach it even if it's impassable like a Core or Wall?) | ||
| // Wait, let's check pathfinding.c line 148: if (neighbor.x == target.x && neighbor.y == target.y) step_cost = 1; | ||
| if (neighbor.x === target.x && neighbor.y === target.y) stepCost = 1; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== C reference, if present =="
fd 'pathfinding\.c$' | while read -r f; do
echo "--- $f ---"
sed -n '140,170p' "$f"
done
echo
echo "== TypeScript call sites =="
python <<'PY'
from pathlib import Path
import re
for path in Path("bots/ts").rglob("*.ts"):
text = path.read_text()
lines = text.splitlines()
for match in re.finditer(r'pathfindFullPathDijkstra\s*\(', text):
line_no = text.count('\n', 0, match.start()) + 1
start = max(1, line_no - 4)
end = min(len(lines), line_no + 6)
print(f"--- {path}:{line_no} ---")
for i in range(start, end + 1):
print(f"{i}: {lines[i-1]}")
print()
PYRepository: 42core-team/monorepo
Length of output: 1568
🏁 Script executed:
sed -n '90,150p' bots/ts/client_lib/pathfinding.tsRepository: 42core-team/monorepo
Length of output: 2067
Clarify whether the function returns a fully walkable path or directional guidance only.
The code matches the C reference exactly: the target override at lines 104-107 allows reaching impassable tiles (WALL, CORE, RESOURCE), and the fallback at lines 118-143 only triggers if the target is entirely unreachable. This means a returned path can end at a non-walkable tile.
The docstring says "towards target" rather than "to target", but the ambiguity remains: callers may incorrectly assume they can execute the entire path. Either document the contract explicitly (e.g., "path may not reach the target if it's impassable") or trim the final step if the goal is a non-walkable tile to guarantee full walkability.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@bots/ts/client_lib/pathfinding.ts` around lines 104 - 107, The pathfinding
currently forces stepCost = 1 for the exact target (neighbor.x/y === target.x/y)
which allows returning a path that ends on an impassable tile; to guarantee
returned paths are fully walkable, after the path is reconstructed (the array
built from the search result), check the final step with
movementCostAt(finalStep) and if it is impassable (cost indicates
WALL/CORE/RESOURCE) remove that final step before returning; also update the
function docstring to state explicitly that the returned path will not include
non-walkable terminal tiles. Ensure you adjust references to the
variables/methods used in the search (stepCost, movementCostAt, neighbor, and
the path reconstruction/return value) so callers get a fully walkable route.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
.github/workflows/my-core-bot-ts-Dockerfile (1)
22-22:⚠️ Potential issue | 🟠 MajorRuntime packaging concern from earlier review still appears unresolved.
This image still only copies
bots/ts/client_lib/at Line 22. If this image is expected to runmy-core-bot, bot source/package files and a startup command are still not visible here (same issue previously flagged).#!/bin/bash set -euo pipefail echo "Where this Dockerfile is used:" rg -n "my-core-bot-ts-Dockerfile" echo echo "Check if runtime command/entrypoint is provided externally:" rg -n "my-core-bot|entrypoint:|command:" echo echo "Current Dockerfile runtime section:" nl -ba .github/workflows/my-core-bot-ts-Dockerfile | sed -n '16,80p'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/my-core-bot-ts-Dockerfile at line 22, The Dockerfile only copies the client library (COPY bots/ts/client_lib/ /core/client_lib/) but doesn't include the my-core-bot runtime sources or define a startup command; update the Dockerfile to also COPY the bot source and packaging files (e.g., bots/ts/my-core-bot/, package.json, package-lock.json/yarn.lock, tsconfig.json or the built dist/) into the image and add a CMD or ENTRYPOINT that runs the bot (referencing the my-core-bot start script or the compiled entry file), ensuring the build steps (npm/yarn install and build) are present if you copy source rather than built artifacts.
🧹 Nitpick comments (2)
bots/ts/client_lib/client_lib.ts (2)
135-146: Local variable shadows module-levelgame.The
const game = getGame()shadows the module-levelgamevariable. While functionally correct (sincegetGame()returns the same reference), this can cause confusion during maintenance. Consider renaming togameStateor similar.♻️ Suggested rename for clarity
function updateGameState(parsed: any): void { if (!parsed) return; - const game = getGame(); + const gameState = getGame(); if (parsed.tick !== undefined) { - game.elapsed_ticks = parsed.tick; + gameState.elapsed_ticks = parsed.tick; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 135 - 146, The function updateGameState declares a local const game = getGame() which shadows the module-level game variable; rename the local binding to a clearer name (e.g., gameState) inside updateGameState so it no longer conflicts, updating all local references (game.elapsed_ticks -> gameState.elapsed_ticks and any other uses) while leaving getGame() and applyDiff(diff) calls unchanged.
316-367: The pathfinding logic looks correct but could benefit from documentation.The
coreActionPathfindfunction implements a priority-based next-step pathfinding algorithm that considers:
- Out-of-bounds and axis completion
- Larger axis prioritization
- Position emptiness
- Friendly object avoidance
The magic numbers (500, 50, 100, 250) represent priority weights. Consider adding a brief comment explaining the priority system for maintainability.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bots/ts/client_lib/client_lib.ts` around lines 316 - 367, The function coreActionPathfind uses unexplained "magic" priority numbers (500, 50, 100, 250) which hurts maintainability; update the function by extracting these literals into clearly named constants (e.g., PRIORITY_OUT_OF_BOUNDS, PRIORITY_OCCUPIED, PRIORITY_FRIENDLY, PRIORITY_THRESHOLD) or at minimum add a succinct comment block above coreActionPathfind describing each weight and how priorities are combined, and then replace the numeric literals in posOptionXPriority/posOptionYPriority calculations and the final threshold checks with those named constants to make the logic explicit (references: coreActionPathfind, posOptionXPriority, posOptionYPriority, coreInternalIsPosValid, coreGetObjFromPos, coreStaticIsFriendlyObj).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/my-core-bot-ts-Dockerfile:
- Around line 7-12: The Dockerfile step that sets ARCH and downloads yq using
curl from "releases/latest" should instead pin a specific yq version and verify
its integrity: replace the curl to "releases/latest/download/yq_linux_${ARCH}"
with a download URL that includes a fixed release tag (e.g., vX.Y.Z), download
the corresponding checksum or signature file for that tag, verify the binary
with sha256sum (or gpg) before chmod +x and moving to /usr/local/bin/yq, and
fail the build if verification fails; keep the existing ARCH expansion and the
target path /usr/local/bin/yq but ensure you add checksum verification and a
pinned version variable.
---
Duplicate comments:
In @.github/workflows/my-core-bot-ts-Dockerfile:
- Line 22: The Dockerfile only copies the client library (COPY
bots/ts/client_lib/ /core/client_lib/) but doesn't include the my-core-bot
runtime sources or define a startup command; update the Dockerfile to also COPY
the bot source and packaging files (e.g., bots/ts/my-core-bot/, package.json,
package-lock.json/yarn.lock, tsconfig.json or the built dist/) into the image
and add a CMD or ENTRYPOINT that runs the bot (referencing the my-core-bot start
script or the compiled entry file), ensuring the build steps (npm/yarn install
and build) are present if you copy source rather than built artifacts.
---
Nitpick comments:
In `@bots/ts/client_lib/client_lib.ts`:
- Around line 135-146: The function updateGameState declares a local const game
= getGame() which shadows the module-level game variable; rename the local
binding to a clearer name (e.g., gameState) inside updateGameState so it no
longer conflicts, updating all local references (game.elapsed_ticks ->
gameState.elapsed_ticks and any other uses) while leaving getGame() and
applyDiff(diff) calls unchanged.
- Around line 316-367: The function coreActionPathfind uses unexplained "magic"
priority numbers (500, 50, 100, 250) which hurts maintainability; update the
function by extracting these literals into clearly named constants (e.g.,
PRIORITY_OUT_OF_BOUNDS, PRIORITY_OCCUPIED, PRIORITY_FRIENDLY,
PRIORITY_THRESHOLD) or at minimum add a succinct comment block above
coreActionPathfind describing each weight and how priorities are combined, and
then replace the numeric literals in posOptionXPriority/posOptionYPriority
calculations and the final threshold checks with those named constants to make
the logic explicit (references: coreActionPathfind, posOptionXPriority,
posOptionYPriority, coreInternalIsPosValid, coreGetObjFromPos,
coreStaticIsFriendlyObj).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 36aad4e4-3c43-4573-8545-a1634ee67d2b
📒 Files selected for processing (6)
.github/workflows/my-core-bot-ts-Dockerfilebots/ts/client_lib/client_lib.tsbots/ts/hardcore/gridmaster/index.tsbots/ts/hardcore/my-core-bot/index.tsbots/ts/softcore/gridmaster/index.tsbots/ts/softcore/my-core-bot/index.ts
| RUN apt-get update && \ | ||
| apt-get install -y make curl && \ | ||
| ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ | ||
| curl -fsSL "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq && \ | ||
| chmod +x /usr/local/bin/yq && \ | ||
| rm -rf /var/lib/apt/lists/* |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Check for non-deterministic yq installs:"
rg -n "yq/releases/latest|yq_linux_\\$\\{ARCH\\}" --glob "*Dockerfile*" --glob "*.Dockerfile"
echo
echo "Check for checksum verification in Dockerfiles:"
rg -n "sha256sum|checksums|cosign" --glob "*Dockerfile*" --glob "*.Dockerfile"Repository: 42core-team/monorepo
Length of output: 104
🏁 Script executed:
# Check if the Dockerfile exists and list similar files
find . -name "*my-core-bot-ts*" -o -name "*Dockerfile*" | head -20Repository: 42core-team/monorepo
Length of output: 243
🏁 Script executed:
# Try to locate the file with different path patterns
git ls-files | grep -i dockerfile | head -20Repository: 42core-team/monorepo
Length of output: 233
🏁 Script executed:
# If the file exists, read its content
if [ -f ".github/workflows/my-core-bot-ts-Dockerfile" ]; then
echo "File found at .github/workflows/my-core-bot-ts-Dockerfile"
cat -n ".github/workflows/my-core-bot-ts-Dockerfile"
else
echo "File not found at expected path, searching for alternatives..."
find . -type f -name "*.Dockerfile" -o -name "*Dockerfile" 2>/dev/null | head -10
fiRepository: 42core-team/monorepo
Length of output: 923
Pin and verify yq instead of downloading latest directly.
Line 10 pulls an executable from releases/latest and executes it without integrity verification. This creates non-reproducible builds and weakens supply-chain safety.
🔧 Proposed hardening diff
RUN apt-get update && \
apt-get install -y make curl && \
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \
- curl -fsSL "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq && \
+ YQ_VERSION="v4.46.1" && \
+ curl -fsSLo /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${ARCH}" && \
+ curl -fsSLo /tmp/yq_checksums "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums" && \
+ grep " yq_linux_${ARCH}$" /tmp/yq_checksums | sha256sum -c - && \
chmod +x /usr/local/bin/yq && \
+ rm -f /tmp/yq_checksums && \
rm -rf /var/lib/apt/lists/*🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/my-core-bot-ts-Dockerfile around lines 7 - 12, The
Dockerfile step that sets ARCH and downloads yq using curl from
"releases/latest" should instead pin a specific yq version and verify its
integrity: replace the curl to "releases/latest/download/yq_linux_${ARCH}" with
a download URL that includes a fixed release tag (e.g., vX.Y.Z), download the
corresponding checksum or signature file for that tag, verify the binary with
sha256sum (or gpg) before chmod +x and moving to /usr/local/bin/yq, and fail the
build if verification fails; keep the existing ARCH expansion and the target
path /usr/local/bin/yq but ensure you add checksum verification and a pinned
version variable.
| "build": "bun build index.ts --target=bun --outfile dist/index.js" | ||
| }, | ||
| "dependencies": { | ||
| "@core/client-lib": "file:../../../core/ts/client_lib" |
There was a problem hiding this comment.
I would keep the relative path so you can test the typescript bot in the monorepo and the devcontainer. This works in the go lib too
There was a problem hiding this comment.
The relative path wasn't working, and it's not that clean either. The absolute path is much easier to read
There was a problem hiding this comment.
but it is not working in the monorepo. The absolute path should absolutely work. You just need to copy the client lib into the root of the dockercontainer
…s, streamline setup
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (3)
.github/workflows/my-core-bot-ts-Dockerfile (3)
8-13:⚠️ Potential issue | 🟠 MajorPin and verify
yqinstead of downloadinglatest.Line 11 pulls
yqfromreleases/latestwith no integrity check, making builds non-reproducible and weakening supply-chain guarantees.🔧 Proposed hardening diff
+ARG YQ_VERSION="v4.46.1" RUN apt update && \ - apt install -y curl ca-certificates make unzip git && \ + apt install -y --no-install-recommends curl ca-certificates make unzip git && \ ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ - curl -fsSL "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq && \ + curl -fsSLo /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${ARCH}" && \ + curl -fsSLo /tmp/yq_checksums "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums" && \ + grep " yq_linux_${ARCH}$" /tmp/yq_checksums | sha256sum -c - && \ chmod +x /usr/local/bin/yq && \ + rm -f /tmp/yq_checksums && \ rm -rf /var/lib/apt/lists/*🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/my-core-bot-ts-Dockerfile around lines 8 - 13, The Dockerfile currently downloads yq from releases/latest with curl (using ARCH and the curl command) which makes builds non-reproducible and unverified; change the download step to pin a specific yq release (replace the releases/latest URL with a fixed tag for yq_linux_${ARCH}) and add an integrity check by verifying the downloaded binary against a known checksum (e.g., download or embed the expected SHA256 and run sha256sum -c or compare the computed digest before chmod) so the curl/ARCH download is both versioned and integrity-checked.
25-29:⚠️ Potential issue | 🟠 MajorImage assembly still appears incomplete for running
my-core-bot.Lines 25-29 only assemble server/data/client_lib; there is still no copied bot app directory and no default
CMD/ENTRYPOINTin this Dockerfile. If this image is intended to run standalone, it will not launch the bot.#!/bin/bash set -euo pipefail echo "== Where this Dockerfile is used ==" rg -n "my-core-bot-ts-Dockerfile|docker build.*my-core-bot|my-core-bot-ts" -S echo echo "== Runtime command/entrypoint wiring in repo ==" rg -n "entrypoint:|command:|bun run index.ts|my-core-bot" -S🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/my-core-bot-ts-Dockerfile around lines 25 - 29, The release stage currently only copies /core/server, /core/data and bots/ts/client_lib/ (FROM ubuntu-bun AS release and the three COPY lines) but never copies the bot application nor defines a runtime command; update this Dockerfile to COPY the built bot application directory into the image (the built my-core-bot app from your build stage, e.g., the bots/ts/<bot-app> or equivalent output from the game stage) and add a default CMD or ENTRYPOINT that launches the bot at runtime (for example the command you use locally such as bun run index.ts or the binary/start script used by my-core-bot) so the image can run standalone.
4-5:⚠️ Potential issue | 🟠 MajorUse the standardized Debian base image.
Line 4 uses
ubuntu:noble; this diverges from the repo-wide base-image standard discussed previously and increases drift across Dockerfiles.#!/bin/bash set -euo pipefail echo "== Base images across Dockerfiles ==" fd -i 'Dockerfile|dockerfile' | while read -r f; do echo "-- $f" rg -n '^\s*FROM\s+' "$f" || true done🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/my-core-bot-ts-Dockerfile around lines 4 - 5, The Dockerfile is using "FROM ubuntu:noble AS ubuntu-bun" which diverges from the repo-wide standard; replace that FROM line to use the approved Debian base image (e.g., the repo standard image tag) instead of "ubuntu:noble", keeping the build stage name "AS ubuntu-bun" intact so downstream stages still reference the same stage; update any CI/documentation if it asserts the base image list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/my-core-bot-ts-Dockerfile:
- Around line 16-21: Replace the curl-based installer and manual ENV setup with
the official Bun Docker image (e.g., use FROM oven/bun:1.1.3) and pin the global
TypeScript install to a specific version by changing the install command
(replace the RUN bun --version && bun add -g typescript line with a pinned
version such as bun add -g typescript@5.6.3); remove the RUN curl -fsSL
https://bun.sh/install | bash and the ENV BUN_INSTALL/PATH modifications since
the official image already provides Bun.
---
Duplicate comments:
In @.github/workflows/my-core-bot-ts-Dockerfile:
- Around line 8-13: The Dockerfile currently downloads yq from releases/latest
with curl (using ARCH and the curl command) which makes builds non-reproducible
and unverified; change the download step to pin a specific yq release (replace
the releases/latest URL with a fixed tag for yq_linux_${ARCH}) and add an
integrity check by verifying the downloaded binary against a known checksum
(e.g., download or embed the expected SHA256 and run sha256sum -c or compare the
computed digest before chmod) so the curl/ARCH download is both versioned and
integrity-checked.
- Around line 25-29: The release stage currently only copies /core/server,
/core/data and bots/ts/client_lib/ (FROM ubuntu-bun AS release and the three
COPY lines) but never copies the bot application nor defines a runtime command;
update this Dockerfile to COPY the built bot application directory into the
image (the built my-core-bot app from your build stage, e.g., the
bots/ts/<bot-app> or equivalent output from the game stage) and add a default
CMD or ENTRYPOINT that launches the bot at runtime (for example the command you
use locally such as bun run index.ts or the binary/start script used by
my-core-bot) so the image can run standalone.
- Around line 4-5: The Dockerfile is using "FROM ubuntu:noble AS ubuntu-bun"
which diverges from the repo-wide standard; replace that FROM line to use the
approved Debian base image (e.g., the repo standard image tag) instead of
"ubuntu:noble", keeping the build stage name "AS ubuntu-bun" intact so
downstream stages still reference the same stage; update any CI/documentation if
it asserts the base image list.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: abc46897-fae5-4ac4-b2b7-f44b1379ba90
📒 Files selected for processing (1)
.github/workflows/my-core-bot-ts-Dockerfile
| RUN curl -fsSL https://bun.sh/install | bash | ||
| ENV BUN_INSTALL=/root/.bun | ||
| ENV PATH="$BUN_INSTALL/bin:$PATH" | ||
|
|
||
| # Build connection library from monorepo sources | ||
| FROM bun-base AS connection | ||
| WORKDIR /connection | ||
| COPY bots/ts/client_lib/ ./ | ||
| # Ensure Bun is available and install TypeScript globally via Bun | ||
| RUN bun --version && bun add -g typescript |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
What is the recommended way (official docs) to install a pinned Bun version in Docker non-interactively, and how do you install a pinned global TypeScript version with Bun?
💡 Result:
The recommended way to install a pinned Bun version in Docker non-interactively, per official Bun docs, is to use a specific tagged official Docker image in your Dockerfile. Use FROM oven/bun:1.1.3 (replace 1.1.3 with your desired version tag, available at https://hub.docker.com/r/oven/bun/tags). This provides a pre-installed, pinned Bun version without interactive prompts. Example from Bun docs: FROM oven/bun:1 AS base WORKDIR /usr/src/app # ... rest of Dockerfile with bun install --frozen-lockfile etc. This is non-interactive by design in Docker builds. To install a pinned global TypeScript version with Bun, use bun add -g typescript@5.6.3 (replace 5.6.3 with your desired version). Bun's package manager supports global installs (-g) with exact version pinning via @version, as documented in bun add and bun install CLI docs. This installs TypeScript globally and makes tsc available.
Citations:
- 1: https://bun.com/docs/guides/ecosystem/docker
- 2: https://bun.com/docs/installation
- 3: https://bun.sh/guides/ecosystem/docker
- 4: https://hub.docker.com/r/oven/bun/tags
- 5: https://bun.sh/docs/cli/add
- 6: https://bun.sh/docs/cli/install
Use official Bun Docker image and pin TypeScript version for deterministic builds.
The current approach uses curl | bash to install Bun and installs TypeScript without a version specifier. Per official Bun documentation, use a pre-built Docker image (e.g., FROM oven/bun:1.1.3) instead of the install script, and pin TypeScript with bun add -g typescript@5.6.3 (or your desired version).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/my-core-bot-ts-Dockerfile around lines 16 - 21, Replace
the curl-based installer and manual ENV setup with the official Bun Docker image
(e.g., use FROM oven/bun:1.1.3) and pin the global TypeScript install to a
specific version by changing the install command (replace the RUN bun --version
&& bun add -g typescript line with a pinned version such as bun add -g
typescript@5.6.3); remove the RUN curl -fsSL https://bun.sh/install | bash and
the ENV BUN_INSTALL/PATH modifications since the official image already provides
Bun.
| "build": "bun build index.ts --target=bun --outfile dist/index.js" | ||
| }, | ||
| "dependencies": { | ||
| "@core/client-lib": "file:../../../core/ts/client_lib" |
There was a problem hiding this comment.
but it is not working in the monorepo. The absolute path should absolutely work. You just need to copy the client lib into the root of the dockercontainer
| # SHELL ["/bin/bash", "-c"] | ||
| # ENV SHELL=/bin/bash | ||
|
|
||
| CMD ["tail", "-f", "/dev/null"] |
Summary by CodeRabbit
New Features
Refactor
Chores