This repository is a small Bun + TypeScript CLI/daemon. Agents should optimize for: minimal diffs, strict types, Bun-native APIs, and predictable CLI UX.
- Runtime: Bun (not Node). Prefer Bun APIs over Node/polyfills.
- Module system: ESM (
"type": "module"inpackage.json). - TypeScript is the linter:
tsc --noEmitis the primary check. - No Cursor/Copilot rule files were found (
.cursor/rules/**,.cursorrules,.github/copilot-instructions.md). - Also follow
CLAUDE.md(Bun defaults, preferred APIs, testing conventions).
src/index.ts: entrypoint for thecocodbinary (shebang:#!/usr/bin/env bun).src/cli.ts+src/cli-shared.ts: Commander-based CLI.src/daemon.ts: background daemon implemented withBun.serve()on a UNIX socket.src/routes.ts: HTTP route handlers for the daemon (endpoints like /balance, /receive, /init, etc.).src/utils/:state.ts: DaemonStateManager and wallet state logicwallet.ts: Wallet initialization helperscrypto.ts: Mnemonic encryption/decryptionconfig.ts: Configuration paths, env vars, and types
- IPC: CLI talks to daemon via
fetch()with Bun'sRequestInit.unixoption.
Key paths/env:
- Socket:
COCOD_SOCKET(default~/.cocod/cocod.sock). - PID file:
COCOD_PID(default~/.cocod/cocod.pid). - Wallet config:
~/.cocod/config.json(generated; do not commit).
All commands run from repo root (/home/egge/projects/cocod).
bun install- Entrypoint:
bun src/index.ts --help- Via npm-style script (use
--to pass args):
bun run start -- --help- Common commands:
bun src/index.ts balance
bun src/index.ts ping
bun src/index.ts mint listThe daemon can be started explicitly, but the CLI also auto-starts it when needed.
bun run daemonThere is no required build step (the CLI runs directly via Bun + TypeScript).
- Optional: produce a bundled artifact:
bun build src/index.ts --outdir dist --target bunThis repo currently uses TypeScript as the main lint gate.
bun run lintIf you need to run tsc directly:
bunx tsc --noEmitBun's test runner is the expected choice.
- Run all tests:
bun test- Run a single test file:
bun test path/to/file.test.ts- Run a single test by name (recommended when adding tests):
bun test -t "ping returns pong"Notes:
- Prefer test files named
*.test.tsand colocated near the code they test. - Use
import { test, expect } from "bun:test";.
There is a formatter config at .prettierrc. Match existing style and avoid drive-by reformatting.
- Indentation: 2 spaces.
- Quotes: double quotes for strings.
- Semicolons: use them consistently (match surrounding file).
- Line length: keep lines reasonably short; wrap long function signatures.
- Order:
- external packages
- blank line
- local relative imports
- Prefer
import type { ... }for type-only imports. - Prefer named imports; avoid default imports unless the package is default-first.
- Keep relative imports extensionless (match current code). Only include
.jswhen required by ESM packages.
tsconfig.json enables strict TypeScript plus noUncheckedIndexedAccess.
- Avoid
any. Useunknownat boundaries and narrow. - Validate untrusted inputs (CLI args, request bodies, env vars).
- When indexing objects, handle
undefinedexplicitly (e.g.,balance[mintUrl] || 0). - Prefer explicit return types on exported functions and non-trivial helpers.
- Use discriminated unions / literal types for protocol-like payloads.
- Files: kebab-case for multiword modules (e.g.,
cli-shared.ts). - Types/interfaces:
PascalCase. - Functions/variables:
camelCase. - Constants:
UPPER_SNAKE_CASEfor configuration-like values. - CLI commands: lowercase; nouns/verbs consistent with existing Commander usage.
General:
- Only
process.exit()from true CLI entrypoints. - Prefer throwing
Error(or subclasses) from library-ish functions. - In
catch, treat the error asunknown; derive a safe message:error instanceof Error ? error.message : String(error).
Daemon (src/daemon.ts):
- Return JSON with either
{ output: string }or{ error: string }. - Use proper HTTP status codes for failures (e.g., 400 for bad input, 404 unknown endpoint, 500 unexpected).
- Do not swallow errors silently; if you intentionally suppress errors (e.g., delete stale files), add a short comment.
CLI (src/cli-shared.ts):
- Print user-facing errors to stderr (
console.error). - Exit with code 1 for expected failures.
- For daemon connectivity issues, prefer actionable messages (socket path, how to start daemon).
- Use
bun <file>/bun run <script>(notnode,ts-node,npm). - Use
bun test(not jest/vitest). - Use
Bun.serve()routes/websocket support (not express). - Prefer
Bun.filefor file IO; Bun loads.envautomatically (avoiddotenv). - Prefer Bun-native DB/network libs where applicable:
bun:sqlitefor SQLite (avoidbetter-sqlite3)Bun.sqlfor Postgres (avoidpg)Bun.redisfor Redis (avoidioredis)- built-in
WebSocket(avoidws)
- Keep diffs surgical; do not reformat unrelated code.
- Preserve CLI UX and backward compatibility of command names/flags unless explicitly requested.
- Avoid committing/generated artifacts (e.g.,
coco.db, sockets, pid files,.env). - When adding new commands/routes:
- update Commander wiring in
src/cli.ts - add/update the route handler in
src/routes.ts(and ensure it returns the{ output | error }shape) - keep the CLI/daemon contract explicit (method, path, request/response types).
- update
docs/daemon-api.jsonto keep the route contract in sync.
- update Commander wiring in
Use these repeatable recipes to keep changes predictable.
- Update command wiring in
src/cli.ts. - Add/update daemon route in
src/routes.ts. - Keep route responses to
{ output: ... }on success and{ error: string }on failure. - Return explicit status codes:
- 400 invalid input
- 401 auth/passphrase failure
- 403 locked wallet for unlocked-only endpoints
- 404 unknown endpoint
- 409 state conflict
- 500 unexpected runtime failure
- Update docs:
README.mdcommand tables/examplesdocs/daemon-api.jsonendpoint contract
- Add/adjust tests and run checks (
bun run lint,bun test).
- Treat request bodies as untrusted.
- Validate required fields before calling wallet methods.
- Return 400 with actionable messages for malformed JSON, missing fields, wrong types, or invalid ranges.
- If you change command names, env var behavior, or defaults, update docs in the same patch.
- Prefer one source of truth for path constants (
src/utils/config.ts). - Do not leave placeholders in user-facing docs.
- CLI can't connect: verify
COCOD_SOCKETmatches daemon and the socket exists. - Daemon won't start: check for stale
~/.cocod/cocod.sockand~/.cocod/cocod.pid. - Type errors: run
bun run lintand fix strictness issues (especiallyundefinedfrom indexing).