@routstr/cocod 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +21 -0
- package/.github/workflows/npm-publish.yml +78 -0
- package/.prettierrc +10 -0
- package/AGENTS.md +244 -0
- package/CLAUDE.md +105 -0
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/SKILL.md +238 -0
- package/bun.lock +69 -0
- package/docs/API.md +92 -0
- package/docs/daemon-api.json +245 -0
- package/package.json +32 -0
- package/src/cli-shared.ts +164 -0
- package/src/cli.ts +317 -0
- package/src/daemon.ts +184 -0
- package/src/index.ts +4 -0
- package/src/logs.test.ts +54 -0
- package/src/logs.ts +118 -0
- package/src/routes.test.ts +60 -0
- package/src/routes.ts +523 -0
- package/src/utils/config.ts +17 -0
- package/src/utils/crypto.test.ts +24 -0
- package/src/utils/crypto.ts +68 -0
- package/src/utils/logger.test.ts +82 -0
- package/src/utils/logger.ts +359 -0
- package/src/utils/state.test.ts +55 -0
- package/src/utils/state.ts +128 -0
- package/src/utils/wallet.ts +51 -0
- package/tsconfig.json +29 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- master
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
checks:
|
|
11
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: oven-sh/setup-bun@v2
|
|
16
|
+
- name: Install dependencies
|
|
17
|
+
run: bun install --frozen-lockfile
|
|
18
|
+
- name: Typecheck
|
|
19
|
+
run: bun run lint
|
|
20
|
+
- name: Tests
|
|
21
|
+
run: bun test
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: oven-sh/setup-bun@v2
|
|
17
|
+
- uses: actions/setup-node@v4
|
|
18
|
+
with:
|
|
19
|
+
registry-url: "https://registry.npmjs.org"
|
|
20
|
+
- name: Configure git user
|
|
21
|
+
run: |
|
|
22
|
+
git config user.name "github-actions[bot]"
|
|
23
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
24
|
+
- name: Bump version
|
|
25
|
+
run: bun pm version patch --no-git-tag-version
|
|
26
|
+
- name: Sync SKILL version pins
|
|
27
|
+
run: |
|
|
28
|
+
VERSION=$(bun -e 'const pkg = JSON.parse(await Bun.file("package.json").text()); console.log(pkg.version)')
|
|
29
|
+
VERSION="$VERSION" bun -e '
|
|
30
|
+
const version = process.env.VERSION;
|
|
31
|
+
if (!version) {
|
|
32
|
+
throw new Error("Missing VERSION env var");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const skillPath = "SKILL.md";
|
|
36
|
+
const skill = await Bun.file(skillPath).text();
|
|
37
|
+
|
|
38
|
+
if (!/^metadata:\s*$/m.test(skill)) {
|
|
39
|
+
throw new Error("SKILL.md is missing metadata field");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!/^\s{2}skill_version:\s*.+$/m.test(skill)) {
|
|
43
|
+
throw new Error("SKILL.md is missing metadata.skill_version field");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!/^\s{2}requires_cocod_version:\s*.+$/m.test(skill)) {
|
|
47
|
+
throw new Error("SKILL.md is missing metadata.requires_cocod_version field");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const next = skill
|
|
51
|
+
.replace(/^\s{2}skill_version:\s*.+$/m, ` skill_version: ${version}`)
|
|
52
|
+
.replace(/^\s{2}requires_cocod_version:\s*.+$/m, ` requires_cocod_version: ${version}`);
|
|
53
|
+
|
|
54
|
+
await Bun.write(skillPath, next);
|
|
55
|
+
'
|
|
56
|
+
- name: Pack tarball
|
|
57
|
+
run: bun pm pack
|
|
58
|
+
- name: Publish to npm
|
|
59
|
+
env:
|
|
60
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
61
|
+
run: npm publish --access public *.tgz
|
|
62
|
+
- name: Commit version bump
|
|
63
|
+
run: |
|
|
64
|
+
VERSION=$(bun -e 'console.log(require("./package.json").version)')
|
|
65
|
+
git add package.json bun.lock SKILL.md
|
|
66
|
+
git commit -m "chore(release): v$VERSION [skip ci]"
|
|
67
|
+
git push
|
|
68
|
+
- name: Publish to skill registry
|
|
69
|
+
env:
|
|
70
|
+
TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
|
|
71
|
+
run: |
|
|
72
|
+
VERSION=$(bun -e 'console.log(require("./package.json").version)')
|
|
73
|
+
SLUG=$(bun -e 'console.log(require("./package.json").name)')
|
|
74
|
+
curl -X POST "https://www.clawhub.ai/api/v1/skills" \
|
|
75
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
76
|
+
-H "Accept: application/json" \
|
|
77
|
+
-F "payload={\"slug\":\"$SLUG\",\"displayName\":\"Cocod\",\"version\":\"$VERSION\",\"changelog\":\"Release v$VERSION\",\"tags\":[\"latest\"]}" \
|
|
78
|
+
-F "files=@SKILL.md;filename=SKILL.md"
|
package/.prettierrc
ADDED
package/AGENTS.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This repository is a small Bun + TypeScript CLI/daemon.
|
|
4
|
+
Agents should optimize for: minimal diffs, strict types, Bun-native APIs, and predictable CLI UX.
|
|
5
|
+
|
|
6
|
+
## Ground Rules (Repo Policy)
|
|
7
|
+
|
|
8
|
+
- Runtime: Bun (not Node). Prefer Bun APIs over Node/polyfills.
|
|
9
|
+
- Module system: ESM (`"type": "module"` in `package.json`).
|
|
10
|
+
- TypeScript is the linter: `tsc --noEmit` is the primary check.
|
|
11
|
+
- No Cursor/Copilot rule files were found (`.cursor/rules/**`, `.cursorrules`, `.github/copilot-instructions.md`).
|
|
12
|
+
- Also follow `CLAUDE.md` (Bun defaults, preferred APIs, testing conventions).
|
|
13
|
+
|
|
14
|
+
## Project Shape
|
|
15
|
+
|
|
16
|
+
- `src/index.ts`: entrypoint for the `cocod` binary (shebang: `#!/usr/bin/env bun`).
|
|
17
|
+
- `src/cli.ts` + `src/cli-shared.ts`: Commander-based CLI.
|
|
18
|
+
- `src/daemon.ts`: background daemon implemented with `Bun.serve()` on a UNIX socket.
|
|
19
|
+
- `src/routes.ts`: HTTP route handlers for the daemon (endpoints like /balance, /receive, /init, etc.).
|
|
20
|
+
- `src/utils/`:
|
|
21
|
+
- `state.ts`: DaemonStateManager and wallet state logic
|
|
22
|
+
- `wallet.ts`: Wallet initialization helpers
|
|
23
|
+
- `crypto.ts`: Mnemonic encryption/decryption
|
|
24
|
+
- `config.ts`: Configuration paths, env vars, and types
|
|
25
|
+
- IPC: CLI talks to daemon via `fetch()` with Bun's `RequestInit.unix` option.
|
|
26
|
+
|
|
27
|
+
Key paths/env:
|
|
28
|
+
|
|
29
|
+
- Socket: `COCOD_SOCKET` (default `~/.cocod/cocod.sock`).
|
|
30
|
+
- PID file: `COCOD_PID` (default `~/.cocod/cocod.pid`).
|
|
31
|
+
- Wallet config: `~/.cocod/config.json` (generated; do not commit).
|
|
32
|
+
|
|
33
|
+
## Commands
|
|
34
|
+
|
|
35
|
+
All commands run from repo root (`/home/egge/projects/cocod`).
|
|
36
|
+
|
|
37
|
+
### Install
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
bun install
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Run the CLI (foreground)
|
|
44
|
+
|
|
45
|
+
- Entrypoint:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
bun src/index.ts --help
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- Via npm-style script (use `--` to pass args):
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
bun run start -- --help
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Common commands:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
bun src/index.ts balance
|
|
61
|
+
bun src/index.ts ping
|
|
62
|
+
bun src/index.ts mint list
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Start the daemon
|
|
66
|
+
|
|
67
|
+
The daemon can be started explicitly, but the CLI also auto-starts it when needed.
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
bun run daemon
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Build / bundle
|
|
74
|
+
|
|
75
|
+
There is no required build step (the CLI runs directly via Bun + TypeScript).
|
|
76
|
+
|
|
77
|
+
- Optional: produce a bundled artifact:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
bun build src/index.ts --outdir dist --target bun
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Lint / typecheck
|
|
84
|
+
|
|
85
|
+
This repo currently uses TypeScript as the main lint gate.
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
bun run lint
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If you need to run tsc directly:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
bunx tsc --noEmit
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Tests
|
|
98
|
+
|
|
99
|
+
Bun's test runner is the expected choice.
|
|
100
|
+
|
|
101
|
+
- Run all tests:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
bun test
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- Run a single test file:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
bun test path/to/file.test.ts
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- Run a single test by name (recommended when adding tests):
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
bun test -t "ping returns pong"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Notes:
|
|
120
|
+
|
|
121
|
+
- Prefer test files named `*.test.ts` and colocated near the code they test.
|
|
122
|
+
- Use `import { test, expect } from "bun:test";`.
|
|
123
|
+
|
|
124
|
+
## Code Style
|
|
125
|
+
|
|
126
|
+
There is a formatter config at `.prettierrc`. Match existing style and avoid drive-by reformatting.
|
|
127
|
+
|
|
128
|
+
### Formatting
|
|
129
|
+
|
|
130
|
+
- Indentation: 2 spaces.
|
|
131
|
+
- Quotes: double quotes for strings.
|
|
132
|
+
- Semicolons: use them consistently (match surrounding file).
|
|
133
|
+
- Line length: keep lines reasonably short; wrap long function signatures.
|
|
134
|
+
|
|
135
|
+
### Imports
|
|
136
|
+
|
|
137
|
+
- Order:
|
|
138
|
+
1. external packages
|
|
139
|
+
2. blank line
|
|
140
|
+
3. local relative imports
|
|
141
|
+
- Prefer `import type { ... }` for type-only imports.
|
|
142
|
+
- Prefer named imports; avoid default imports unless the package is default-first.
|
|
143
|
+
- Keep relative imports extensionless (match current code). Only include `.js` when required by ESM packages.
|
|
144
|
+
|
|
145
|
+
### Types and strictness
|
|
146
|
+
|
|
147
|
+
`tsconfig.json` enables strict TypeScript plus `noUncheckedIndexedAccess`.
|
|
148
|
+
|
|
149
|
+
- Avoid `any`. Use `unknown` at boundaries and narrow.
|
|
150
|
+
- Validate untrusted inputs (CLI args, request bodies, env vars).
|
|
151
|
+
- When indexing objects, handle `undefined` explicitly (e.g., `balance[mintUrl] || 0`).
|
|
152
|
+
- Prefer explicit return types on exported functions and non-trivial helpers.
|
|
153
|
+
- Use discriminated unions / literal types for protocol-like payloads.
|
|
154
|
+
|
|
155
|
+
### Naming
|
|
156
|
+
|
|
157
|
+
- Files: kebab-case for multiword modules (e.g., `cli-shared.ts`).
|
|
158
|
+
- Types/interfaces: `PascalCase`.
|
|
159
|
+
- Functions/variables: `camelCase`.
|
|
160
|
+
- Constants: `UPPER_SNAKE_CASE` for configuration-like values.
|
|
161
|
+
- CLI commands: lowercase; nouns/verbs consistent with existing Commander usage.
|
|
162
|
+
|
|
163
|
+
### Error handling
|
|
164
|
+
|
|
165
|
+
General:
|
|
166
|
+
|
|
167
|
+
- Only `process.exit()` from true CLI entrypoints.
|
|
168
|
+
- Prefer throwing `Error` (or subclasses) from library-ish functions.
|
|
169
|
+
- In `catch`, treat the error as `unknown`; derive a safe message:
|
|
170
|
+
- `error instanceof Error ? error.message : String(error)`.
|
|
171
|
+
|
|
172
|
+
Daemon (`src/daemon.ts`):
|
|
173
|
+
|
|
174
|
+
- Return JSON with either `{ output: string }` or `{ error: string }`.
|
|
175
|
+
- Use proper HTTP status codes for failures (e.g., 400 for bad input, 404 unknown endpoint, 500 unexpected).
|
|
176
|
+
- Do not swallow errors silently; if you intentionally suppress errors (e.g., delete stale files), add a short comment.
|
|
177
|
+
|
|
178
|
+
CLI (`src/cli-shared.ts`):
|
|
179
|
+
|
|
180
|
+
- Print user-facing errors to stderr (`console.error`).
|
|
181
|
+
- Exit with code 1 for expected failures.
|
|
182
|
+
- For daemon connectivity issues, prefer actionable messages (socket path, how to start daemon).
|
|
183
|
+
|
|
184
|
+
### Bun-specific guidance (from `CLAUDE.md`)
|
|
185
|
+
|
|
186
|
+
- Use `bun <file>` / `bun run <script>` (not `node`, `ts-node`, `npm`).
|
|
187
|
+
- Use `bun test` (not jest/vitest).
|
|
188
|
+
- Use `Bun.serve()` routes/websocket support (not express).
|
|
189
|
+
- Prefer `Bun.file` for file IO; Bun loads `.env` automatically (avoid `dotenv`).
|
|
190
|
+
- Prefer Bun-native DB/network libs where applicable:
|
|
191
|
+
- `bun:sqlite` for SQLite (avoid `better-sqlite3`)
|
|
192
|
+
- `Bun.sql` for Postgres (avoid `pg`)
|
|
193
|
+
- `Bun.redis` for Redis (avoid `ioredis`)
|
|
194
|
+
- built-in `WebSocket` (avoid `ws`)
|
|
195
|
+
|
|
196
|
+
## Editing Expectations for Agents
|
|
197
|
+
|
|
198
|
+
- Keep diffs surgical; do not reformat unrelated code.
|
|
199
|
+
- Preserve CLI UX and backward compatibility of command names/flags unless explicitly requested.
|
|
200
|
+
- Avoid committing/generated artifacts (e.g., `coco.db`, sockets, pid files, `.env`).
|
|
201
|
+
- When adding new commands/routes:
|
|
202
|
+
- update Commander wiring in `src/cli.ts`
|
|
203
|
+
- add/update the route handler in `src/routes.ts` (and ensure it returns the `{ output | error }` shape)
|
|
204
|
+
- keep the CLI/daemon contract explicit (method, path, request/response types).
|
|
205
|
+
- update `docs/daemon-api.json` to keep the route contract in sync.
|
|
206
|
+
|
|
207
|
+
## Agent Playbook
|
|
208
|
+
|
|
209
|
+
Use these repeatable recipes to keep changes predictable.
|
|
210
|
+
|
|
211
|
+
### Add or update a CLI command
|
|
212
|
+
|
|
213
|
+
1. Update command wiring in `src/cli.ts`.
|
|
214
|
+
2. Add/update daemon route in `src/routes.ts`.
|
|
215
|
+
3. Keep route responses to `{ output: ... }` on success and `{ error: string }` on failure.
|
|
216
|
+
4. Return explicit status codes:
|
|
217
|
+
- 400 invalid input
|
|
218
|
+
- 401 auth/passphrase failure
|
|
219
|
+
- 403 locked wallet for unlocked-only endpoints
|
|
220
|
+
- 404 unknown endpoint
|
|
221
|
+
- 409 state conflict
|
|
222
|
+
- 500 unexpected runtime failure
|
|
223
|
+
5. Update docs:
|
|
224
|
+
- `README.md` command tables/examples
|
|
225
|
+
- `docs/daemon-api.json` endpoint contract
|
|
226
|
+
6. Add/adjust tests and run checks (`bun run lint`, `bun test`).
|
|
227
|
+
|
|
228
|
+
### Validate request bodies
|
|
229
|
+
|
|
230
|
+
- Treat request bodies as untrusted.
|
|
231
|
+
- Validate required fields before calling wallet methods.
|
|
232
|
+
- Return 400 with actionable messages for malformed JSON, missing fields, wrong types, or invalid ranges.
|
|
233
|
+
|
|
234
|
+
### Keep docs and runtime aligned
|
|
235
|
+
|
|
236
|
+
- If you change command names, env var behavior, or defaults, update docs in the same patch.
|
|
237
|
+
- Prefer one source of truth for path constants (`src/utils/config.ts`).
|
|
238
|
+
- Do not leave placeholders in user-facing docs.
|
|
239
|
+
|
|
240
|
+
## Quick Debugging Checklist
|
|
241
|
+
|
|
242
|
+
- CLI can't connect: verify `COCOD_SOCKET` matches daemon and the socket exists.
|
|
243
|
+
- Daemon won't start: check for stale `~/.cocod/cocod.sock` and `~/.cocod/cocod.pid`.
|
|
244
|
+
- Type errors: run `bun run lint` and fix strictness issues (especially `undefined` from indexing).
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Default to using Bun instead of Node.js.
|
|
2
|
+
|
|
3
|
+
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
|
|
4
|
+
- Use `bun test` instead of `jest` or `vitest`
|
|
5
|
+
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
|
|
6
|
+
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
|
|
7
|
+
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
|
|
8
|
+
- Use `bunx <package> <command>` instead of `npx <package> <command>`
|
|
9
|
+
- Bun automatically loads .env, so don't use dotenv.
|
|
10
|
+
|
|
11
|
+
## APIs
|
|
12
|
+
|
|
13
|
+
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
|
|
14
|
+
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
|
|
15
|
+
- `Bun.redis` for Redis. Don't use `ioredis`.
|
|
16
|
+
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
|
|
17
|
+
- `WebSocket` is built-in. Don't use `ws`.
|
|
18
|
+
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
|
19
|
+
- Bun.$`ls` instead of execa.
|
|
20
|
+
|
|
21
|
+
## Testing
|
|
22
|
+
|
|
23
|
+
Use `bun test` to run tests.
|
|
24
|
+
|
|
25
|
+
```ts#index.test.ts
|
|
26
|
+
import { test, expect } from "bun:test";
|
|
27
|
+
|
|
28
|
+
test("hello world", () => {
|
|
29
|
+
expect(1).toBe(1);
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Frontend
|
|
34
|
+
|
|
35
|
+
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
|
|
36
|
+
|
|
37
|
+
Server:
|
|
38
|
+
|
|
39
|
+
```ts#index.ts
|
|
40
|
+
import index from "./index.html"
|
|
41
|
+
|
|
42
|
+
Bun.serve({
|
|
43
|
+
routes: {
|
|
44
|
+
"/": index,
|
|
45
|
+
"/api/users/:id": {
|
|
46
|
+
GET: (req) => {
|
|
47
|
+
return new Response(JSON.stringify({ id: req.params.id }));
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
// optional websocket support
|
|
52
|
+
websocket: {
|
|
53
|
+
open: (ws) => {
|
|
54
|
+
ws.send("Hello, world!");
|
|
55
|
+
},
|
|
56
|
+
message: (ws, message) => {
|
|
57
|
+
ws.send(message);
|
|
58
|
+
},
|
|
59
|
+
close: (ws) => {
|
|
60
|
+
// handle close
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
development: {
|
|
64
|
+
hmr: true,
|
|
65
|
+
console: true,
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
|
|
71
|
+
|
|
72
|
+
```html#index.html
|
|
73
|
+
<html>
|
|
74
|
+
<body>
|
|
75
|
+
<h1>Hello, world!</h1>
|
|
76
|
+
<script type="module" src="./frontend.tsx"></script>
|
|
77
|
+
</body>
|
|
78
|
+
</html>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
With the following `frontend.tsx`:
|
|
82
|
+
|
|
83
|
+
```tsx#frontend.tsx
|
|
84
|
+
import React from "react";
|
|
85
|
+
import { createRoot } from "react-dom/client";
|
|
86
|
+
|
|
87
|
+
// import .css files directly and it works
|
|
88
|
+
import './index.css';
|
|
89
|
+
|
|
90
|
+
const root = createRoot(document.body);
|
|
91
|
+
|
|
92
|
+
export default function Frontend() {
|
|
93
|
+
return <h1>Hello, world!</h1>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
root.render(<Frontend />);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Then, run index.ts
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
bun --hot ./index.ts
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.mdx`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Egge
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# cocod
|
|
2
|
+
|
|
3
|
+
`cocod` is a Cashu wallet CLI with a local daemon.
|
|
4
|
+
|
|
5
|
+
If you like simple tools: run commands in your terminal, and let the daemon handle wallet state in the background.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
- Initialize and secure a Cashu wallet
|
|
10
|
+
- Check balances and transaction history
|
|
11
|
+
- Send and receive Cashu tokens
|
|
12
|
+
- Send and receive Lightning payments (BOLT11)
|
|
13
|
+
- Handle HTTP 402 payments with `X-Cashu`
|
|
14
|
+
- Manage trusted mints
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bun install --global cocod
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or from source:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
git clone <repository-url>
|
|
26
|
+
cd cocod
|
|
27
|
+
bun install
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Check daemon status
|
|
34
|
+
cocod status
|
|
35
|
+
|
|
36
|
+
# Create a wallet (auto-generates mnemonic)
|
|
37
|
+
cocod init
|
|
38
|
+
|
|
39
|
+
# If encrypted during init, unlock it
|
|
40
|
+
cocod unlock "your-passphrase"
|
|
41
|
+
|
|
42
|
+
# Check balance
|
|
43
|
+
cocod balance
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Most common commands
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Receive
|
|
50
|
+
cocod receive cashu "cashuA..."
|
|
51
|
+
cocod receive bolt11 1000
|
|
52
|
+
|
|
53
|
+
# Send
|
|
54
|
+
cocod send cashu 500
|
|
55
|
+
cocod send bolt11 "lnbc..."
|
|
56
|
+
|
|
57
|
+
# Mints
|
|
58
|
+
cocod mints add https://mint.example.com/Bitcoin
|
|
59
|
+
cocod mints list
|
|
60
|
+
|
|
61
|
+
# History
|
|
62
|
+
cocod history --limit 10
|
|
63
|
+
cocod history --watch
|
|
64
|
+
|
|
65
|
+
# Logs
|
|
66
|
+
cocod logs
|
|
67
|
+
cocod logs --follow
|
|
68
|
+
cocod logs --path
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## NPC (Lightning Address)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Your NPC address
|
|
75
|
+
cocod npc address
|
|
76
|
+
|
|
77
|
+
# Check username price, then confirm purchase
|
|
78
|
+
cocod npc username myname
|
|
79
|
+
cocod npc username myname --confirm
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## HTTP 402 / X-Cashu
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Inspect request from a 402 response
|
|
86
|
+
cocod x-cashu parse "<encoded-x-cashu-request>"
|
|
87
|
+
|
|
88
|
+
# Settle and get header value for retry
|
|
89
|
+
cocod x-cashu handle "<encoded-x-cashu-request>"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## How it works
|
|
93
|
+
|
|
94
|
+
- CLI: `src/cli.ts`
|
|
95
|
+
- Daemon: `src/daemon.ts`
|
|
96
|
+
- Routes: `src/routes.ts`
|
|
97
|
+
- IPC transport: HTTP over UNIX socket
|
|
98
|
+
|
|
99
|
+
Defaults:
|
|
100
|
+
|
|
101
|
+
- Socket: `~/.cocod/cocod.sock` (or `COCOD_SOCKET`)
|
|
102
|
+
- PID file: `~/.cocod/cocod.pid` (or `COCOD_PID`)
|
|
103
|
+
- Daemon log: `~/.cocod/daemon.log` (or `COCOD_LOG_FILE`)
|
|
104
|
+
- Config: `~/.cocod/config.json`
|
|
105
|
+
- Database: `~/.cocod/coco.db`
|
|
106
|
+
|
|
107
|
+
Logging defaults:
|
|
108
|
+
|
|
109
|
+
- Structured JSON logs are written to `~/.cocod/daemon.log`
|
|
110
|
+
- Rotation keeps 5 files at 5 MiB each by default
|
|
111
|
+
- Override with `COCOD_LOG_LEVEL`, `COCOD_LOG_MAX_BYTES`, and `COCOD_LOG_MAX_FILES`
|
|
112
|
+
|
|
113
|
+
## Development
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Run CLI from source
|
|
117
|
+
bun src/index.ts --help
|
|
118
|
+
|
|
119
|
+
# Run daemon directly
|
|
120
|
+
bun run daemon
|
|
121
|
+
|
|
122
|
+
# Typecheck
|
|
123
|
+
bun run lint
|
|
124
|
+
|
|
125
|
+
# Tests
|
|
126
|
+
bun test
|
|
127
|
+
|
|
128
|
+
# Isolated daemon smoke test
|
|
129
|
+
bun run smoke:daemon
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Docs
|
|
133
|
+
|
|
134
|
+
- [API and command reference](docs/API.md)
|
|
135
|
+
- [Machine-readable daemon contract](docs/daemon-api.json)
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|