Skip to content

switch hydra-cli to npm build and release flow#7

Merged
baanish merged 3 commits into
mainfrom
prep-npm
Mar 30, 2026
Merged

switch hydra-cli to npm build and release flow#7
baanish merged 3 commits into
mainfrom
prep-npm

Conversation

@baanish
Copy link
Copy Markdown
Owner

@baanish baanish commented Mar 30, 2026

Summary

  • switched the project from bun-based packaging to an npm-based build, test, and release flow.
  • added package-lock.json, npm scripts, and a node 24+ baseline for local dev and CI.
  • updated the CLI package layout so the published tarball ships dist/ output and omits source-only artifacts.
  • refreshed the readme with npm install, run, and publish instructions plus updated storage paths.
  • expanded and adjusted tests across config, db, engine, security, cli smoke coverage, and web/server behavior to match the new runtime assumptions.

Testing

  • npm ci
  • npm run lint
  • npm run typecheck
  • npm test
  • npm run build
  • npm pack smoke check for package/dist/index.js and package/dist/web/app.html
  • not run: manual publish to npm

Summary by CodeRabbit

Release Notes

  • New Features

    • Added automated CI/CD pipeline for quality assurance across multiple platforms
  • Documentation

    • Updated installation instructions with multiple deployment options (global, local, npx)
    • Documented config and data storage location (~/.config/hydra-cli)
    • Added development guide with build, test, and publish commands
  • Chores

    • Rebranded package name to @baanish/hydra-cli

- replace bun lockfile with package-lock.json
- add npm build, test, and pack smoke checks
- update docs and ci for node 24/npm
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 30, 2026

Warning

Rate limit exceeded

@baanish has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 2 minutes and 3 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 2 minutes and 3 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7004dc00-baa4-4f33-9109-9890df77ee1a

📥 Commits

Reviewing files that changed from the base of the PR and between 3428710 and e272be7.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • README.md
  • src/cli.smoke.test.ts
  • src/config.ts
  • src/db/queries.ts
  • src/engine/pipeline.ts
  • src/opentui-core.d.ts
  • src/web/server.ts
📝 Walkthrough

Walkthrough

The pull request migrates the Hydra project from Bun to Node.js 24 as the runtime, switching the build toolchain to npm/tsx/vitest, replacing Bun's built-in SQLite with better-sqlite3, updating all ES module imports to use explicit .js extensions, refactoring the web server from Bun.serve to Node http.createServer, and standardizing formatting across the codebase.

Changes

Cohort / File(s) Summary
Build & Tooling Configuration
.github/workflows/ci.yml, tsconfig.json, tsconfig.build.json, vitest.config.ts, package.json
Added GitHub Actions CI workflow with multi-OS matrix testing, updated TypeScript compilation targets from Bun to NodeNext/Node, created separate build config excluding tests, introduced Vitest configuration, and updated package.json to reference Node 24+ with new npm scripts replacing Bun commands (npm ci, npm run lint/typecheck/test/build).
Runtime & Platform Migration
src/index.ts, src/web/server.ts, src/db/client.ts
Changed shebang from #!/usr/bin/env bun to #!/usr/bin/env node, migrated web server from Bun.serve to Node http.createServer with IncomingMessage→Request/Response adapters, replaced Bun sqlite import with better-sqlite3 package and introduced SqliteDatabase type alias for compatibility.
Asset Handling & Build Scripts
scripts/copy-assets.mjs
Added new asset copy script to sync web UI static files (app.html) from src/web to dist/web during build process.
Documentation & Package Metadata
README.md
Rebranded project from hydra-cli to hydra, replaced Bun install/link instructions with npm alternatives (npx, npm install, npm install -g), added storage section documenting config paths, included development section with standard npm commands, and removed Bun-specific guidance.
Database Layer
src/db/queries.ts, src/db/queries.test.ts
Migrated test runner from bun:test to vitest with vi.doMock instead of mock.module, updated imports to use .js extensions, added explicit error handling in createRun to verify inserted rows exist, kept query logic unchanged.
Test Infrastructure
src/config.test.ts, src/engine/concurrency.test.ts, src/engine/model.test.ts, src/engine/personas*.test.ts, src/engine/pipeline.test.ts, src/security.test.ts, src/ui/animations.test.ts, src/index.test.ts, src/cli.smoke.test.ts
Replaced bun:test imports with vitest across all test files, switched mocking from mock.module to vi.doMock, updated module import paths to include .js extensions, added new CLI smoke test for build verification and runtime help output validation, adjusted test fixtures (bun/src → node/dist).
Type Definitions & Core Types
src/types.ts, src/opentui-core.d.ts
Reformatted spacing/indentation in types.ts exports without semantic changes; added new TypeScript declaration file for @opentui/core module with CliRenderer, BoxRenderable, TextRenderable, and text styling utilities.
Engine & Search Core
src/engine/eta.ts, src/engine/concurrency.ts, src/engine/model.ts, src/engine/search.ts, src/engine/prompts.ts, src/engine/pipeline.ts, src/engine/personas.ts, src/engine/personas.error.test.ts, src/ui/agent-mode.ts
Standardized module imports to use .js extensions across all engine files, adjusted indentation/formatting to tabs, reformatted function signatures in prompts.ts, preserved all runtime logic for concurrency/ETA/model/search/pipeline/personas features.
Config & Security
src/config.ts, src/security.ts, src/ui/tui.ts, src/web/index.ts
Updated ESM imports to include .js extensions, reformatted indentation/style without changing logic, adjusted web server re-export path from ./server to ./server.js.

Sequence Diagram(s)

sequenceDiagram
    participant Client as HTTP Client
    participant Server as Node HTTP Server
    participant Handler as Request Handler
    participant Pipeline as HydraPipeline
    participant DB as better-sqlite3

    Client->>Server: POST /api/run (with query)
    Server->>Server: Convert IncomingMessage → Request
    Server->>Handler: handleWebRequest(req, sessionToken)
    
    Handler->>Handler: Check authorization
    Handler->>Handler: Parse route & method
    
    alt POST /api/run
        Handler->>Pipeline: Create HydraPipeline
        Handler->>Pipeline: pipeline.run(query)
        Pipeline->>DB: Query initialization
        DB-->>Pipeline: Run record created
        
        Pipeline->>Handler: Emit run-created event
        Handler->>Client: Send SSE stream opened
        
        Pipeline->>Pipeline: Execute phases
        Pipeline->>DB: Update run status
        Pipeline->>Handler: Emit pipeline events
        Handler->>Client: Write SSE events
        
        Pipeline-->>Handler: Complete or fail
        Handler->>Client: Close SSE stream
    else GET /api/runs
        Handler->>DB: listRuns()
        DB-->>Handler: Return run records
        Handler->>Client: JSON response
    end
    
    Server->>Server: Convert Response → ServerResponse
    Client->>Client: Receive result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • feat: custom personas #1: Modifies core engine and database modules (src/db/client.ts, src/db/queries.ts, src/engine/*, src/config.ts) with similar function/type signatures being preserved across the same codebase entities.
  • Add Claude Code GitHub Workflow #8: Adds comprehensive test suite files (pipeline.test.ts, model.test.ts, concurrency.test.ts, db/queries.test.ts, index.test.ts) that are directly affected by the Bun→Vitest migration in this PR.
  • Security report findings #5: Integrates security utilities and session/authorization across overlapping modules (src/security.ts, src/web/server.ts, src/engine/*, src/config.ts) that both reference in their implementations.

Poem

🐰 From Bun we hop to Node so bright,
With better-sqlite holding databases tight,
Each import adorned with .js extension flair,
Vitest runs tests through the spring-scented air,
The web server adapts from serve to flow,
TypeScript compiles—watch our hydra grow!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: switching the project from Bun-based to npm-based build and release flow, which is reflected across all modified files including package.json, CI workflow, tsconfig, and build scripts.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prep-npm

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented Mar 30, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Incremental Review (commit e272be7)

No new issues. Changes since last review:

  • README.md — Added node 24 requirement explanation, updated CLI example to ESM syntax
  • package-lock.json — Regenerated (no logic changes)

Overview

This PR migrates hydra-cli from a Bun-based build/test/release flow to npm-based tooling with a node 24 minimum. The changes are well-structured and consistent across the codebase.

Key migration points reviewed:

  • bun:sqlitebetter-sqlite3 (native npm package)
  • bun:testvitest (test framework migration with vi.doMock replacing mock.module)
  • Module resolution: bundlerNodeNext with .js extensions on all local imports
  • Build: bun build --compiletsc -p tsconfig.build.json + asset copy script
  • Shebang: #!/usr/bin/env bun#!/usr/bin/env node
  • Lock file: bun.lock deleted, package-lock.json added
  • Engines: node >= 24 required
  • Indentation normalized from spaces to tabs across all files
Files Reviewed (36 files)
  • README.md - Documentation updates
  • package.json - Package config migration
  • package-lock.json - New npm lock file (generated)
  • bun.lock - Removed
  • scripts/copy-assets.mjs - Build asset copy helper
  • src/index.ts - Entry point (shebang + imports)
  • src/config.ts - Import path updates
  • src/security.ts - Import path updates
  • src/types.ts - No logic changes
  • src/db/client.ts - bun:sqlitebetter-sqlite3
  • src/db/queries.ts - Import path updates
  • src/engine/pipeline.ts - Import path updates
  • src/engine/model.ts - Import path updates
  • src/engine/personas.ts - Import path updates
  • src/engine/concurrency.ts - Formatting only
  • src/engine/eta.ts - Formatting only
  • src/engine/prompts.ts - Formatting only
  • src/engine/search.ts - Import path updates
  • src/web/server.ts - Import path updates
  • src/web/index.ts - Import path updates
  • src/ui/tui.ts - Import path updates
  • src/ui/agent-mode.ts - Import path updates
  • tsconfig.json - module: NodeNext, types: [node, vitest/globals]
  • tsconfig.build.json - Build config
  • vitest.config.ts - Vitest configuration
  • src/cli.smoke.test.ts - New CLI smoke test
  • src/config.test.ts - bun:testvitest
  • src/index.test.ts - bun:testvitest
  • src/security.test.ts - bun:testvitest
  • src/db/queries.test.ts - bun:testvitest
  • src/engine/concurrency.test.ts - bun:testvitest
  • src/engine/model.test.ts - bun:testvitest
  • src/engine/personas.test.ts - bun:testvitest
  • src/engine/personas.error.test.ts - bun:testvitest
  • src/engine/pipeline.test.ts - bun:testvitest

Reviewed by mimo-v2-pro-20260318 · 150,633 tokens

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (5)
src/opentui-core.d.ts (1)

1-45: Excessive use of unknown undermines type safety.

This declaration file uses unknown throughout, which provides minimal compile-time validation. Based on actual usage in src/ui/tui.ts, more specific types would catch errors earlier:

  1. StyledText = unknown could be an opaque branded type
  2. createCliRenderer config uses known keys (exitOnCtrlC, useAlternateScreen)
  3. add(child: unknown) should constrain to renderables with an id property
  4. Styling helpers should accept string | number | StyledText rather than unknown
♻️ Suggested type improvements
 declare module "@opentui/core" {
-	export type StyledText = unknown;
+	// Opaque type for styled text - prevents accidental misuse
+	export type StyledText = { readonly __brand: unique symbol };
+
+	export interface CliRendererConfig {
+		exitOnCtrlC?: boolean;
+		useAlternateScreen?: boolean;
+	}
+
+	export interface Renderable {
+		id: string;
+	}

 	export class CliRenderer {
 		width: number;
 		root: {
-			add(child: unknown): void;
+			add(child: Renderable): void;
 		};
 		requestLive(): void;
 		dropLive(): void;
 		destroy(): void;
 	}

 	export function createCliRenderer(
-		config?: Record<string, unknown>,
+		config?: CliRendererConfig,
 	): Promise<CliRenderer>;

-	export class BoxRenderable {
+	export class BoxRenderable implements Renderable {
 		id: string;
-		constructor(renderer: CliRenderer, options?: Record<string, unknown>);
-		add(child: unknown): void;
+		constructor(renderer: CliRenderer, options?: BoxRenderableOptions);
+		add(child: Renderable): void;
 		getChildren(): Array<{ id: string }>;
 		remove(id: string): void;
 	}

-	export class TextRenderable {
+	export class TextRenderable implements Renderable {
 		id: string;
 		text: StyledText;
 		content: StyledText;
-		constructor(
-			renderer: CliRenderer,
-			options?: Record<string, unknown> & { text?: StyledText },
-		);
+		constructor(renderer: CliRenderer, options?: TextRenderableOptions);
 	}

-	export function bold(input: unknown): StyledText;
-	export function brightBlack(input: unknown): StyledText;
-	export function green(input: unknown): StyledText;
-	export function magenta(input: unknown): StyledText;
-	export function yellow(input: unknown): StyledText;
+	type Styleable = string | number | StyledText;
+	export function bold(input: Styleable): StyledText;
+	export function brightBlack(input: Styleable): StyledText;
+	export function green(input: Styleable): StyledText;
+	export function magenta(input: Styleable): StyledText;
+	export function yellow(input: Styleable): StyledText;
 	export function t(
 		strings: TemplateStringsArray,
-		...values: unknown[]
+		...values: Styleable[]
 	): StyledText;
 }

Define BoxRenderableOptions with: border?, borderStyle?, flexDirection?, gap?, padding?, width?, height?, flexGrow? properties.
Define TextRenderableOptions with: content? property.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/opentui-core.d.ts` around lines 1 - 45, The declaration overuses unknown;
replace it with concrete types: define an opaque branded type StyledText (e.g.,
type StyledText = string & { __styled?: true }) and update all functions to
return/accept StyledText; tighten createCliRenderer config to an interface with
known keys (exitOnCtrlC?: boolean, useAlternateScreen?: boolean, any other known
flags); change add(child: unknown) and BoxRenderable.getChildren()/remove
signatures to use a Renderable or HasId interface (e.g., { id: string }) and add
a BoxRenderableOptions type (border?, borderStyle?, flexDirection?, gap?,
padding?, width?, height?, flexGrow?); add TextRenderableOptions with content?:
StyledText and update TextRenderable constructor to use it; and change styling
helpers (bold, brightBlack, green, magenta, yellow, t) to accept string | number
| StyledText instead of unknown so callers get proper type checking.
src/engine/pipeline.ts (1)

863-869: Avoid dropping all assignments when only one item is malformed.

Line 863 currently returns an empty set if any parsed assignment is invalid. That makes decomposition brittle to partial LLM noise and discards otherwise valid assignments.

Suggested resilience tweak
-		if (assignments.some((item) => item === null)) {
-			return [];
-		}
-
-		return assignments.filter(
+		return assignments.filter(
 			(assignment): assignment is DecomposedAssignment => assignment !== null,
 		);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/engine/pipeline.ts` around lines 863 - 869, The current code bails out
and returns [] if any entry in assignments is null, which drops all valid
decomposed results; remove the early if (assignments.some((item) => item ===
null)) { return []; } check and instead simply return the filtered list
(assignments.filter((assignment): assignment is DecomposedAssignment =>
assignment !== null)), optionally emitting a warning/log for any discarded nulls
so callers still get all valid DecomposedAssignment entries.
package.json (1)

52-54: Verify Node 24 availability and consider documenting the version requirement rationale.

The engines field requires Node >=24. While Node 24 should be available by this timeframe, it's a relatively new major version. Consider documenting in the README why Node 24 is required (e.g., specific ESM features, native fetch, etc.) to help users understand the constraint.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 52 - 54, The package.json currently enforces
"engines": { "node": ">=24" } which may be surprising to users; update project
docs to justify this requirement by adding a short note in README (or a new
docs/ note) explaining why Node 24 is required (e.g., usage of ESM-only
features, native fetch, new timers/promises APIs, or specific language/runtime
behavior) and, if appropriate, include a fallback or compatibility notes for
older Node versions; reference the "engines" field and the "node" constraint
when adding the rationale so readers can connect the requirement to concrete
features in the codebase.
README.md (1)

44-50: Minor: Consider using ESM syntax in the example for consistency.

The inline node -e command uses require('node:fs') (CommonJS), while the project is ESM ("type": "module"). While this works because -e defaults to CommonJS evaluation, using ESM would be more consistent.

📖 Alternative ESM-based example
-node -e "console.log(JSON.parse(require('node:fs').readFileSync('./examples/ai-transition-2036.json', 'utf8')).brief)"
+node --input-type=module -e "import {readFileSync} from 'node:fs'; console.log(JSON.parse(readFileSync('./examples/ai-transition-2036.json', 'utf8')).brief)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 44 - 50, The README example currently uses a CommonJS
inline command (the `node -e` invocation that calls require('node:fs')), so
update that example to use ESM semantics instead: change the inline command to
run Node in module mode and use an ESM import of 'fs' with top-level await or
fs.promises to read and parse ./examples/ai-transition-2036.json and then print
the .brief field. Locate the example block in README.md (the `node -e` /
require('node:fs') snippet) and replace it with an ESM-based one-liner that
imports fs and logs the parsed brief.
src/db/queries.ts (1)

502-508: Consider capturing Date.now() once for consistency.

The completedAt and elapsedMs calculations use separate Date.now() calls, introducing a minor drift. While negligible in practice, a single timestamp would be more precise.

♻️ Optional fix for timestamp consistency
 export function markRunComplete(runId: string, brief: string): RunRecord {
 	const run = getRun(runId);
 	if (!run) {
 		throw new Error(`Run ${runId} not found`);
 	}
 
+	const now = Date.now();
 	return updateRunStatus(runId, {
 		status: "complete",
 		brief,
-		completedAt: Date.now(),
-		elapsedMs: Date.now() - run.createdAt,
+		completedAt: now,
+		elapsedMs: now - run.createdAt,
 		error: null,
 	});
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/db/queries.ts` around lines 502 - 508, The code calls Date.now() twice
when setting completedAt and computing elapsedMs in the updateRunStatus call;
capture a single timestamp into a local variable (e.g., const completedAt =
Date.now()) before calling updateRunStatus and then pass completedAt and
elapsedMs: completedAt - run.createdAt so both fields are consistent; modify the
block around updateRunStatus(runId, { status: "complete", brief, ... }) to use
that single timestamp variable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Around line 1-59: The repo's package-lock.json is out of sync with
package.json; run npm install locally to regenerate/update package-lock.json to
match the declared dependencies (e.g., those under "dependencies" and
"devDependencies" in package.json), verify the change, and commit the updated
package-lock.json so CI can perform a clean npm ci. Ensure you do not modify
package.json when updating the lockfile and include only the updated
package-lock.json in the commit.

In `@src/cli.smoke.test.ts`:
- Around line 11-21: The two spawnSync invocations that create build and result
(calling npmCommand() for "npm run build" and process.execPath for
"dist/index.js --help") need a timeout option to avoid hung CI; update both
spawnSync calls to include a timeout (e.g., timeout: 120000) in their options
object so the child process is killed after the specified milliseconds and the
test fails fast if the command stalls.

In `@src/config.ts`:
- Around line 267-285: In writeConfig, validation happens after the file is
already written; call normalizeConfig (merging DEFAULTS, readConfigFile(), and
updates) first to validate and obtain the normalized config, throw/propagate any
validation errors, and only then serialize and write that normalized result to
disk (using writeFileSync and chmodSync on CONFIG_FILE); ensure the returned
value is the normalized config (not a re-normalization of fileData) and keep
ensureConfigDir/readConfigFile usage but validate before persisting.

In `@src/web/server.ts`:
- Around line 986-992: Remove the deprecated "aborted" event listener: delete
the req.once("aborted", () => abortController.abort()); line and rely on the
existing req.once("close", () => { if (!req.complete) { abortController.abort();
} }); logic; keep the AbortController instantiation (const abortController = new
AbortController();) and the "close" handler as-is so cancellation behavior
remains unchanged.

---

Nitpick comments:
In `@package.json`:
- Around line 52-54: The package.json currently enforces "engines": { "node":
">=24" } which may be surprising to users; update project docs to justify this
requirement by adding a short note in README (or a new docs/ note) explaining
why Node 24 is required (e.g., usage of ESM-only features, native fetch, new
timers/promises APIs, or specific language/runtime behavior) and, if
appropriate, include a fallback or compatibility notes for older Node versions;
reference the "engines" field and the "node" constraint when adding the
rationale so readers can connect the requirement to concrete features in the
codebase.

In `@README.md`:
- Around line 44-50: The README example currently uses a CommonJS inline command
(the `node -e` invocation that calls require('node:fs')), so update that example
to use ESM semantics instead: change the inline command to run Node in module
mode and use an ESM import of 'fs' with top-level await or fs.promises to read
and parse ./examples/ai-transition-2036.json and then print the .brief field.
Locate the example block in README.md (the `node -e` / require('node:fs')
snippet) and replace it with an ESM-based one-liner that imports fs and logs the
parsed brief.

In `@src/db/queries.ts`:
- Around line 502-508: The code calls Date.now() twice when setting completedAt
and computing elapsedMs in the updateRunStatus call; capture a single timestamp
into a local variable (e.g., const completedAt = Date.now()) before calling
updateRunStatus and then pass completedAt and elapsedMs: completedAt -
run.createdAt so both fields are consistent; modify the block around
updateRunStatus(runId, { status: "complete", brief, ... }) to use that single
timestamp variable.

In `@src/engine/pipeline.ts`:
- Around line 863-869: The current code bails out and returns [] if any entry in
assignments is null, which drops all valid decomposed results; remove the early
if (assignments.some((item) => item === null)) { return []; } check and instead
simply return the filtered list (assignments.filter((assignment): assignment is
DecomposedAssignment => assignment !== null)), optionally emitting a warning/log
for any discarded nulls so callers still get all valid DecomposedAssignment
entries.

In `@src/opentui-core.d.ts`:
- Around line 1-45: The declaration overuses unknown; replace it with concrete
types: define an opaque branded type StyledText (e.g., type StyledText = string
& { __styled?: true }) and update all functions to return/accept StyledText;
tighten createCliRenderer config to an interface with known keys (exitOnCtrlC?:
boolean, useAlternateScreen?: boolean, any other known flags); change add(child:
unknown) and BoxRenderable.getChildren()/remove signatures to use a Renderable
or HasId interface (e.g., { id: string }) and add a BoxRenderableOptions type
(border?, borderStyle?, flexDirection?, gap?, padding?, width?, height?,
flexGrow?); add TextRenderableOptions with content?: StyledText and update
TextRenderable constructor to use it; and change styling helpers (bold,
brightBlack, green, magenta, yellow, t) to accept string | number | StyledText
instead of unknown so callers get proper type checking.
🪄 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: d2ce7df1-b7e5-47f5-8b5e-e166ecd9b11a

📥 Commits

Reviewing files that changed from the base of the PR and between 129c2c1 and 3428710.

⛔ Files ignored due to path filters (2)
  • bun.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (36)
  • .github/workflows/ci.yml
  • README.md
  • package.json
  • scripts/copy-assets.mjs
  • src/cli.smoke.test.ts
  • src/config.test.ts
  • src/config.ts
  • src/db/client.ts
  • src/db/queries.test.ts
  • src/db/queries.ts
  • src/engine/concurrency.test.ts
  • src/engine/concurrency.ts
  • src/engine/eta.ts
  • src/engine/model.test.ts
  • src/engine/model.ts
  • src/engine/personas.error.test.ts
  • src/engine/personas.test.ts
  • src/engine/personas.ts
  • src/engine/pipeline.test.ts
  • src/engine/pipeline.ts
  • src/engine/prompts.ts
  • src/engine/search.ts
  • src/index.test.ts
  • src/index.ts
  • src/opentui-core.d.ts
  • src/security.test.ts
  • src/security.ts
  • src/types.ts
  • src/ui/agent-mode.ts
  • src/ui/animations.test.ts
  • src/ui/tui.ts
  • src/web/index.ts
  • src/web/server.ts
  • tsconfig.build.json
  • tsconfig.json
  • vitest.config.ts

Comment thread package.json
Comment on lines 1 to 59
{
"name": "hydra-swarm",
"version": "0.1.0",
"description": "Multi-model swarm intelligence engine for your terminal",
"repository": {
"type": "git",
"url": "https://github.com/baanish/hydra-cli.git"
},
"type": "module",
"bin": {
"hydra": "./src/index.ts"
},
"scripts": {
"dev": "bun run src/index.ts",
"start": "bun run src/index.ts",
"test": "bun test",
"build": "bun build src/index.ts --compile --outfile dist/hydra",
"typecheck": "tsc --noEmit",
"lint": "biome check src/",
"format": "biome format --write src/"
},
"dependencies": {
"@opentui/core": "^0.1.81",
"commander": "^13.1.0",
"nanoid": "^5.1.5",
"openai": "^4.83.0",
"unicode-animations": "^1.0.3"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@types/bun": "latest",
"typescript": "^5.7.3"
},
"keywords": [
"cli",
"ai",
"swarm",
"multi-agent",
"research",
"intelligence",
"llm",
"tui",
"opentui"
],
"author": "Aanish Bhirud",
"license": "MIT",
"engines": {
"bun": ">=1.1.0"
}
"name": "@baanish/hydra-cli",
"version": "0.1.0",
"description": "Multi-model swarm intelligence engine for your terminal",
"repository": {
"type": "git",
"url": "https://github.com/baanish/hydra-cli.git"
},
"type": "module",
"bin": {
"hydra": "./dist/index.js"
},
"scripts": {
"dev": "tsx src/index.ts",
"start": "tsx src/index.ts",
"test": "vitest run",
"build": "tsc -p tsconfig.build.json && node scripts/copy-assets.mjs",
"typecheck": "tsc --noEmit",
"lint": "biome check src scripts README.md package.json tsconfig.json tsconfig.build.json vitest.config.ts .github",
"format": "biome format --write src scripts README.md package.json tsconfig.json tsconfig.build.json vitest.config.ts .github",
"prepack": "npm run build"
},
"dependencies": {
"@opentui/core": "^0.1.81",
"better-sqlite3": "^12.8.0",
"commander": "^13.1.0",
"nanoid": "^5.1.5",
"openai": "^4.83.0",
"unicode-animations": "^1.0.3"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^24.5.2",
"tsx": "^4.20.5",
"typescript": "^5.7.3",
"vitest": "^3.2.4"
},
"keywords": [
"cli",
"ai",
"swarm",
"multi-agent",
"research",
"intelligence",
"llm",
"tui",
"opentui"
],
"author": "Aanish Bhirud",
"license": "MIT",
"engines": {
"node": ">=24"
},
"files": ["dist", "README.md", "LICENSE"],
"publishConfig": {
"access": "public"
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Pipeline failure: package-lock.json is out of sync with package.json.

The CI pipeline reports:

npm ci cannot perform a clean install when package.json and lock file are not in sync. Please update package-lock.json by running 'npm install' before continuing.

Run npm install locally and commit the updated package-lock.json.

🧰 Tools
🪛 GitHub Actions: ci

[error] 1-1: npm ci cannot perform a clean install when package.json and lock file are not in sync. Please update package-lock.json by running 'npm install' before continuing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 1 - 59, The repo's package-lock.json is out of
sync with package.json; run npm install locally to regenerate/update
package-lock.json to match the declared dependencies (e.g., those under
"dependencies" and "devDependencies" in package.json), verify the change, and
commit the updated package-lock.json so CI can perform a clean npm ci. Ensure
you do not modify package.json when updating the lockfile and include only the
updated package-lock.json in the commit.

Comment thread src/cli.smoke.test.ts
Comment thread src/config.ts
Comment thread src/web/server.ts
- document node-24-first support in the readme
- update cli and test code for esm and web platform primitives
- refresh lockfile after dependency changes
@baanish baanish merged commit aa6c909 into main Mar 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant