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 +144 -0
- package/README.md +44 -0
- package/bin/rippletide.js +27 -0
- package/counter/README.md +37 -0
- package/counter/frontend/window.jxa +601 -0
- package/counter/src/cli.js +22 -0
- package/counter/src/counter.js +165 -0
- package/counter/src/proxy.js +243 -0
- package/package.json +64 -0
- package/reviewer/.env.example +5 -0
- package/reviewer/README.md +137 -0
- package/reviewer/bin/rippletide-review.js +16 -0
- package/reviewer/bin/rippletide.js +8 -0
- package/reviewer/codex/rippletide-reviewer/README.md +28 -0
- package/reviewer/codex/rippletide-reviewer/scripts/rippletide-codex +16 -0
- package/reviewer/codex/rippletide-reviewer/scripts/rippletide-codex.mjs +24 -0
- package/reviewer/codex/rippletide-reviewer/scripts/rippletide-reviewer +37 -0
- package/reviewer/src/connect/evidence.js +235 -0
- package/reviewer/src/integrations/cli/rippletide.js +1595 -0
- package/reviewer/src/integrations/codex/prepare.js +277 -0
- package/tide/README.md +128 -0
- package/tide/bin/tide.js +4 -0
- package/tide/examples/no-file-writes/POLICY.md +3 -0
- package/tide/src/cli.js +173 -0
- package/tide/src/codex.js +65 -0
- package/tide/src/compile.js +193 -0
- package/tide/src/credentials.js +41 -0
- package/tide/src/engine.js +115 -0
- package/tide/src/expr.js +260 -0
- package/tide/src/hook.js +71 -0
- package/tide/src/ontology.js +28 -0
- package/tide/src/schema.js +87 -0
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.
|