rippletide-package 0.1.0

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/PUBLISHING.md ADDED
@@ -0,0 +1,144 @@
1
+ # Publishing
2
+
3
+ Rippletide is distributed from the repo root as **one npm CLI package**. Every feature is a
4
+ subcommand of the same command:
5
+
6
+ ```bash
7
+ npx rippletide-package <feature-name> [flags]
8
+ ```
9
+
10
+ > Published on npm as **`rippletide-package`** (the name `rippletide` is already taken by
11
+ > another package); the installed command is **`rippletide`**. Via `npx` use the package
12
+ > name; after `npm i -g rippletide-package` you run `rippletide`.
13
+
14
+ ## One product, many features
15
+
16
+ `rippletide-package` is a multi-feature repo — we expect to iterate on several product bets
17
+ before product-market fit — but it should feel like **one product** to users:
18
+
19
+ - the publishing unit is the repo root;
20
+ - the npm package name is `rippletide-package`; the installed command is `rippletide`;
21
+ - each user-facing feature is a **subcommand** (`<feature-name>`), implemented in its own
22
+ self-contained top-level folder;
23
+ - **flags** choose behavior *inside* a feature, e.g. `rippletide <feature-name> --<flag>`;
24
+ - a new feature becomes a subcommand or flag before we ever create another package name.
25
+
26
+ This keeps experiments cheap without fragmenting the user experience: users learn one
27
+ command, while the repo isolates each product bet in its own folder until a shared contract
28
+ is worth designing. The root CLI ([`bin/rippletide.js`](bin/rippletide.js)) is a small,
29
+ feature-agnostic dispatcher that routes each subcommand to the folder that owns it.
30
+
31
+ ## Adding a feature to the CLI
32
+
33
+ Build the feature in its own top-level folder:
34
+
35
+ ```text
36
+ <feature>/
37
+ package.json or build/deploy config, only if the feature needs it
38
+ src/ (and bin/, docs/, tests/, examples/ as needed)
39
+ ```
40
+
41
+ When it graduates from experiment to a user-facing surface:
42
+
43
+ 1. Keep implementation code in its feature folder (no cross-folder imports).
44
+ 2. Add one route for it in `bin/rippletide.js`.
45
+ 3. Add its runtime files to the root `package.json` `files` (and any dependency it needs to
46
+ `dependencies`).
47
+ 4. Add root-level verification (extend the `check` script).
48
+ 5. Document its command in the root `README.md`.
49
+
50
+ Do not create a new public npm package for every experiment. Create another package only
51
+ when a feature needs a separate install surface, audience, or lifecycle that would make the
52
+ single `rippletide` CLI worse.
53
+
54
+ ## Package shape
55
+
56
+ ```text
57
+ npm registry : https://registry.npmjs.org/
58
+ repo folder : ./
59
+ package name : rippletide-package
60
+ command : rippletide
61
+ ```
62
+
63
+ The published tarball ships the root dispatcher plus each user-facing feature's runtime and
64
+ docs (see `files` in `package.json`). It excludes curated test agents and generated artifacts.
65
+
66
+ ## Local verification
67
+
68
+ From the repo root:
69
+
70
+ ```bash
71
+ npm run release:check # syntax-checks every feature + a packaging dry-run
72
+ npm pack # build the tarball
73
+ npx ./rippletide-package-0.1.0.tgz --help # or: ... <feature-name> --help
74
+ ```
75
+
76
+ ## Publish
77
+
78
+ Before the first publish:
79
+
80
+ 1. Confirm the package name is available or owned by Rippletide:
81
+ ```bash
82
+ npm view rippletide-package name version # a 404 means the name is free
83
+ ```
84
+ 2. Confirm npm auth: `npm whoami`.
85
+ 3. Confirm the root `package.json` version is what you intend.
86
+
87
+ Then, from a machine logged in as an owner:
88
+
89
+ ```bash
90
+ npm run release:dry # dry-run
91
+ npm run release:publish # publish (prompts for a 2FA OTP if your account requires one)
92
+ ```
93
+
94
+ ### Publishing rights: tokens, CI, and teammates
95
+
96
+ Interactive `npm publish` asks for a 2FA one-time code if your npm account requires 2FA on
97
+ writes. For releases, prefer a **token** — it never prompts for an OTP and isn't tied to one
98
+ person's laptop.
99
+
100
+ **CI release (recommended).** [`.github/workflows/release.yml`](.github/workflows/release.yml)
101
+ publishes automatically when a `rippletide-package-v*` tag is pushed (or via Actions → *Run
102
+ workflow*). One-time setup:
103
+
104
+ 1. On npmjs.com → **Access Tokens**, create a token with publish rights to this package — a
105
+ **Granular Access Token** scoped to `rippletide-package` with read+write is safest; a
106
+ classic **Automation** token also works. Both bypass 2FA.
107
+ 2. Store it as the repo secret **`RIPPLETIDE_PACKAGE_TOKEN`** (never commit it):
108
+ ```bash
109
+ gh secret set RIPPLETIDE_PACKAGE_TOKEN --repo rippletideco/rippletide-package # paste the token when prompted
110
+ ```
111
+ 3. Release by pushing a version tag — **any teammate who can push** can do this; no npm login
112
+ or OTP needed (see the checklist below).
113
+
114
+ **Manual publish by a teammate.** Have a current owner grant rights, then they publish with
115
+ their own npm account:
116
+
117
+ ```bash
118
+ npm owner add <their-npm-username> rippletide-package # run by a current owner
119
+ npm owner ls rippletide-package # see who can publish
120
+ ```
121
+
122
+ ## Repeatable release checklist
123
+
124
+ From the repo root, every time:
125
+
126
+ ```bash
127
+ git pull --ff-only origin main
128
+ npm version patch --no-git-tag-version # minor / major when warranted
129
+ npm run release:dry
130
+ VERSION=$(node -p "require('./package.json').version")
131
+ git add package.json
132
+ git commit -m "Release rippletide-package v${VERSION}"
133
+ git tag "rippletide-package-v${VERSION}"
134
+ git push origin main --tags
135
+ npm run release:publish
136
+ ```
137
+
138
+ ## Hosted direction (optional, per feature)
139
+
140
+ The CLI stays the user entry point. A feature may later move its heavy logic behind a hosted
141
+ Rippletide API — the CLI collects and redacts local context, calls the service, and renders
142
+ the result — without changing this release flow. Only that feature's implementation and its
143
+ backend config change. Aim to avoid requiring users to configure model API keys in a
144
+ hosted-first flow.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # rippletide-package
2
+
3
+ Rippletide's product package. It ships as **one npm CLI** — `npx rippletide-package <feature-name>` —
4
+ while each feature lives in its own self-contained top-level folder.
5
+
6
+ > Published on npm as **`rippletide-package`** (the name `rippletide` is taken); the
7
+ > installed command is **`rippletide`**. So: `npx rippletide-package <feature-name>`, or
8
+ > `npm i -g rippletide-package` then `rippletide <feature-name>`.
9
+
10
+ **Zero sharing between folders.** Each feature folder is fully self-contained — its own
11
+ code, dependencies, config, and docs. Nothing imports from or reaches into another
12
+ feature's folder. The only place features meet is the root CLI, which routes a subcommand
13
+ to the feature that owns it.
14
+
15
+ ## Features
16
+
17
+ Each feature is a **subcommand** of `rippletide`, implemented in its own top-level folder.
18
+ **A feature is explained in its own folder** — see that folder's `README.md` (and any
19
+ `PRD.md`/`docs`) for what it does and how to use it.
20
+
21
+ ```bash
22
+ npx rippletide-package <feature-name> [flags]
23
+ ```
24
+
25
+ ## How it fits together
26
+
27
+ One product, one command, many features. The root [`bin/rippletide.js`](bin/rippletide.js)
28
+ is a small, **feature-agnostic dispatcher**: it reads the first argument and hands off to
29
+ the feature folder that owns that subcommand. Behavior *within* a feature is chosen with
30
+ flags (e.g. `rippletide <feature-name> --<flag>`). Runtime code is not shared across feature
31
+ folders until a shared contract is deliberately designed.
32
+
33
+ ## Adding a feature
34
+
35
+ Repeat this shape for every new feature:
36
+
37
+ 1. Create a top-level folder; keep everything it needs inside it (code, deps, docs, tests)
38
+ and explain it in that folder's `README.md`.
39
+ 2. When it becomes user-facing, add one route in `bin/rippletide.js`, and its runtime files
40
+ (plus any dependency it needs) to the root `package.json`.
41
+ 3. Prefer a subcommand or a flag over a new npm package; create a separate package only if a
42
+ single command would make the product worse.
43
+
44
+ Publishing: [`PUBLISHING.md`](PUBLISHING.md).
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ // Rippletide product CLI — the single public entry point (`npx rippletide <feature> …`).
3
+ //
4
+ // The repo is one product with several self-contained feature folders. This dispatcher
5
+ // routes a subcommand to the feature that owns it; it is feature-agnostic — add one route
6
+ // per user-facing feature. See PUBLISHING.md.
7
+ //
8
+ // rippletide review [...] -> reviewer/ (review, inspect, …)
9
+ // rippletide tide [...] -> tide/ (compile, install, check, …)
10
+ // rippletide counter [...] -> counter/ (live Codex calls/tokens/cost window)
11
+
12
+ const argv = process.argv.slice(2);
13
+ const sub = argv[0];
14
+
15
+ if (sub === "tide") {
16
+ const { main } = await import("../tide/src/cli.js");
17
+ process.exit(await main(argv.slice(1)));
18
+ }
19
+
20
+ if (sub === "counter") {
21
+ const { main } = await import("../counter/src/cli.js");
22
+ process.exit(await main(argv.slice(1)));
23
+ }
24
+
25
+ // Every other subcommand (review, inspect, --help, …) is owned by the reviewer feature,
26
+ // which reads process.argv itself.
27
+ await import("../reviewer/src/integrations/cli/rippletide.js");
@@ -0,0 +1,37 @@
1
+ # counter — live Codex calls / tokens / cost
2
+
3
+ A floating **sticky window** that counts your Codex LLM usage in real time: the running
4
+ **call count** (big number), and a caption with **total tokens** and **estimated cost**.
5
+ Ported from the [x-ray](https://github.com/tototozip/x-ray) counter — the counting +
6
+ token/cost half only (no risk scanning, no enforcement).
7
+
8
+ ```bash
9
+ rippletide counter
10
+ ```
11
+
12
+ Then use Codex — the desktop app or the CLI. The window updates on every model call.
13
+ Press **Ctrl-C** (or close the window) to stop; your Codex config is restored on exit.
14
+
15
+ ## How it works
16
+
17
+ - Points Codex's `openai_base_url` at a tiny local **reverse proxy** (a managed block in
18
+ `~/.codex/config.toml`, removed on exit).
19
+ - The proxy forwards every model call to OpenAI **untouched**, and on the way back reads the
20
+ response `usage` to tally tokens and estimate cost from a per-model price table
21
+ (`gpt-5.x`, etc.). Each inference request bumps the call count.
22
+ - Codex tries a **WebSocket** transport for `/v1/responses` first; the HTTP proxy can't carry
23
+ that upgrade, so it refuses the handshake (`426`) and Codex falls straight back to its HTTPS
24
+ transport — which the proxy does forward. This keeps the CLI fast (no reconnect stall) while
25
+ every call still flows through the counter.
26
+ - A JXA sticky window (`frontend/window.jxa`) renders the live state
27
+ (`~/.local/state/rippletide/counter.json`): call count, tokens, cost, and a per-model
28
+ breakdown (click the window for details).
29
+ - On macOS it relaunches the Codex **app** once so it picks up the base URL
30
+ (disable with `RIPPLETIDE_RELAUNCH_CODEX_APP=0`). The **CLI** picks it up on the next run.
31
+
32
+ ## Notes
33
+
34
+ - The floating window is **macOS-only** (JXA); counting still runs elsewhere.
35
+ - Nothing is sent anywhere — the proxy only forwards to OpenAI and reads token counts
36
+ locally. It never changes requests or responses.
37
+ - Cost is an **estimate** from a local price table; treat it as a live gauge, not a bill.