relmio 0.2.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +190 -0
  2. package/LICENSE +21 -0
  3. package/README.md +122 -0
  4. package/SPEC.md +140 -0
  5. package/docs/architecture.md +127 -0
  6. package/docs/brand.md +43 -0
  7. package/docs/images/brand/relmio-concept-source.png +0 -0
  8. package/docs/images/brand/relmio-mark.svg +16 -0
  9. package/docs/images/setup/01-local-sign-in-ready.png +0 -0
  10. package/docs/images/setup/02-vps-identity-confirmed.png +0 -0
  11. package/docs/images/setup/03-n8n-detected.png +0 -0
  12. package/docs/images/setup/04-install-plan.png +0 -0
  13. package/docs/images/setup/05-bridge-ready.png +0 -0
  14. package/docs/maintenance.md +157 -0
  15. package/docs/manual-install.md +282 -0
  16. package/docs/n8n-configuration.md +199 -0
  17. package/docs/npm-publish.md +285 -0
  18. package/docs/roadmap.md +109 -0
  19. package/docs/security.md +105 -0
  20. package/docs/troubleshooting.md +193 -0
  21. package/docs/video-outline.md +152 -0
  22. package/package.json +45 -0
  23. package/scripts/build-npm-package.js +112 -0
  24. package/scripts/check-release-metadata.js +100 -0
  25. package/scripts/check-syntax.js +59 -0
  26. package/scripts/preview.js +69 -0
  27. package/src/cli.js +57 -0
  28. package/src/domain/safety.js +59 -0
  29. package/src/domain/templates.js +65 -0
  30. package/src/domain/validation.js +76 -0
  31. package/src/infrastructure/ssh.js +268 -0
  32. package/src/services/discovery.js +96 -0
  33. package/src/services/installer.js +239 -0
  34. package/src/services/oauth.js +351 -0
  35. package/src/ui/app.js +526 -0
  36. package/src/ui/index.html +440 -0
  37. package/src/ui/styles.css +645 -0
  38. package/src/ui/time.js +15 -0
  39. package/src/web/server.js +489 -0
@@ -0,0 +1,285 @@
1
+ # Publish and synchronize the npm package
2
+
3
+ This guide is for the package maintainer. Run every command on the local
4
+ computer in this repository, not on the VPS.
5
+
6
+ The repository is the release source of truth. The initial package is prepared
7
+ in Git, validated by CI, published to npm from that exact commit, and then
8
+ tagged with the same version. Later releases are tagged first and published
9
+ from that exact tag by the trusted workflow. npm does not automatically edit
10
+ `package.json`, `CHANGELOG.md`, or the Git repository after a publish.
11
+
12
+ The first `relmio` publication is a one-time bootstrap with a narrowly scoped
13
+ local access token because npm requires the package to exist before a trusted
14
+ publisher can be attached. After that bootstrap, releases use the
15
+ repository's `.github/workflows/publish.yml` OIDC workflow and no long-lived
16
+ npm token.
17
+
18
+ ## Version contract
19
+
20
+ Every release must use one semantic version in all of these places:
21
+
22
+ - `package.json`;
23
+ - the top-level and root-package entries in `package-lock.json`;
24
+ - the newest numbered release in `CHANGELOG.md`;
25
+ - the Git tag `v<version>`;
26
+ - the version published to npm.
27
+
28
+ Check the local files at any time:
29
+
30
+ ```bash
31
+ npm run release:check
32
+ ```
33
+
34
+ On a tag build, CI also checks that the tag matches the files. The npm badge
35
+ in the README is only an informational, potentially cached view of the
36
+ registry's current `latest` version. The post-publish commands below perform
37
+ the authoritative equality check.
38
+
39
+ ## One-time npm account setup
40
+
41
+ 1. Sign in at <https://www.npmjs.com/>.
42
+ 2. Configure an npm-supported second factor for package publishing. Depending
43
+ on the account, npm may approve with a passkey/security key or request an
44
+ authenticator one-time code.
45
+ 3. Create one granular access token that can create and publish only the new
46
+ package. Keep it in the ignored local `NPM_CREATE_ACCESS_TOKEN` environment
47
+ variable and revoke it after trusted publishing is configured.
48
+
49
+ Never paste an npm password, passkey recovery material, 2FA code, or access
50
+ token into chat, an issue, a shell-history example, or the repository.
51
+
52
+ ## Prepare a release
53
+
54
+ Start from a release branch. Do not retag or reuse an already published
55
+ version.
56
+
57
+ ### 1. Check the current state
58
+
59
+ ```bash
60
+ git status --short --branch
61
+ npm view relmio version \
62
+ --registry=https://registry.npmjs.org
63
+ ```
64
+
65
+ The worktree should contain only the changes intended for the release.
66
+ Before the first Relmio publish, npm returns `E404` because the new package
67
+ name has no published version yet. Confirm the exact package name is still
68
+ available, then continue only from the reviewed rebrand commit.
69
+
70
+ ### 2. Bump the files without creating a tag
71
+
72
+ For a backward-compatible bug or documentation release:
73
+
74
+ ```bash
75
+ npm version patch --no-git-tag-version
76
+ ```
77
+
78
+ Use `minor` for a backward-compatible feature and `major` for a breaking
79
+ change. The command updates both `package.json` and `package-lock.json`.
80
+
81
+ Add a matching release heading and user-visible changes to `CHANGELOG.md`.
82
+ Then run:
83
+
84
+ ```bash
85
+ npm run release:check
86
+ ```
87
+
88
+ ### 3. Run the complete release gate
89
+
90
+ ```bash
91
+ npm ci --ignore-scripts
92
+ npm run check
93
+ npm audit --audit-level=high
94
+ npm run package:build -- .release
95
+ ```
96
+
97
+ The package builder stages the concise npm README as the tarball's root
98
+ `README.md`; it never changes the full GitHub README or its Mermaid diagrams.
99
+ Review the emitted tarball file list. It must not contain:
100
+
101
+ - `.env` or local-context files;
102
+ - OAuth files or tokens;
103
+ - SSH keys, passwords, or real VPS details;
104
+ - browser session URLs;
105
+ - test recordings or unredacted screenshots;
106
+ - unrelated local build artifacts.
107
+
108
+ Documentation images must be sanitized previews. Remember that `docs/**` is
109
+ part of the npm package.
110
+
111
+ Before changing a private repository to public, audit the complete Git
112
+ history as well as the current worktree. Deleting a VPS address, email,
113
+ credential, or token from the latest commit does not remove it from earlier
114
+ commits. If history contains sensitive data, keep the repository private and
115
+ perform a reviewed, coordinated history rewrite before the first public
116
+ release.
117
+
118
+ ### 4. Commit and run CI
119
+
120
+ Stage every intended change, then review the exact staged release:
121
+
122
+ ```bash
123
+ RELEASE_VERSION="$(node -p "require('./package.json').version")"
124
+ git add --all
125
+ git status --short
126
+ git diff --cached --check
127
+ git diff --cached --stat
128
+ git commit -m "release: v${RELEASE_VERSION}"
129
+ git push
130
+ ```
131
+
132
+ Merge the release commit into the repository's default branch according to
133
+ the project workflow and wait for the default-branch CI run to pass. The
134
+ remaining commands assume that branch is named `main`; substitute the actual
135
+ default branch if it differs.
136
+
137
+ ## Publish the exact commit
138
+
139
+ Check out the CI-approved default branch, update it without a merge commit,
140
+ and record the exact clean commit:
141
+
142
+ ```bash
143
+ git switch main
144
+ git pull --ff-only
145
+ test -z "$(git status --porcelain)"
146
+ RELEASE_COMMIT="$(git rev-parse HEAD)"
147
+ npm run release:check
148
+ ```
149
+
150
+ Review the package from that commit. Immediately before publishing, fail if
151
+ either the commit or worktree changed:
152
+
153
+ ```bash
154
+ npm run package:build -- .release
155
+ test "$RELEASE_COMMIT" = "$(git rev-parse HEAD)"
156
+ test -z "$(git status --porcelain)"
157
+ ```
158
+
159
+ For the first `relmio` publication only, place the already-created token in
160
+ the environment without echoing it, write an owner-only temporary npm config,
161
+ and publish the reviewed tarball:
162
+
163
+ ```bash
164
+ umask 077
165
+ NPM_CONFIG_USERCONFIG="$(mktemp)"
166
+ trap 'rm -f "$NPM_CONFIG_USERCONFIG"' EXIT
167
+ printf '%s\n' '//registry.npmjs.org/:_authToken=${NPM_CREATE_ACCESS_TOKEN}' \
168
+ > "$NPM_CONFIG_USERCONFIG"
169
+ export NPM_CONFIG_USERCONFIG NPM_CREATE_ACCESS_TOKEN
170
+ npm whoami --registry=https://registry.npmjs.org
171
+ LOCAL_VERSION="$(node -p "require('./package.json').version")"
172
+ npm publish ".release/relmio-${LOCAL_VERSION}.tgz" \
173
+ --ignore-scripts \
174
+ --access public \
175
+ --registry=https://registry.npmjs.org
176
+ ```
177
+
178
+ Do not place the real token value in `.npmrc`, the workflow, a command-line
179
+ argument, or Git. npm may still require its configured publishing second
180
+ factor.
181
+
182
+ Verify the immutable registry result:
183
+
184
+ ```bash
185
+ LOCAL_VERSION="$(node -p "require('./package.json').version")"
186
+ PUBLISHED_VERSION="$(npm view relmio version \
187
+ --registry=https://registry.npmjs.org)"
188
+ test "$LOCAL_VERSION" = "$PUBLISHED_VERSION"
189
+ npm view "relmio@${LOCAL_VERSION}" dist.integrity \
190
+ --registry=https://registry.npmjs.org
191
+ ```
192
+
193
+ The equality check must succeed before tagging.
194
+
195
+ ## Switch future releases to trusted publishing
196
+
197
+ Do this only after the first `relmio` version exists on npm and the
198
+ `publish.yml` workflow is present on the GitHub default branch.
199
+
200
+ On the npm package's **Trusted Publisher** form, use:
201
+
202
+ | Field | Value |
203
+ |---|---|
204
+ | Publisher | GitHub Actions |
205
+ | Organization or user | `Demonbane18` |
206
+ | Repository | `n8n-openai-oauth-setup` |
207
+ | Workflow filename | `publish.yml` |
208
+ | Environment name | `npm` |
209
+ | Allowed action | Allow npm publish |
210
+
211
+ The environment must match `environment: npm` in the workflow. Add approval
212
+ rules to the GitHub `npm` environment if a maintainer should explicitly
213
+ approve each registry write.
214
+
215
+ The workflow uses a GitHub-hosted runner, `id-token: write`, Node.js `22.14.0`,
216
+ and npm `11.13.0`, which is separate from the application's reviewed npm
217
+ `10.9.8` development runtime. npm exchanges the GitHub OIDC identity for a
218
+ short-lived publishing credential and automatically generates provenance for
219
+ public packages.
220
+
221
+ After one trusted publish is verified:
222
+
223
+ 1. change package publishing access to require 2FA and disallow tokens;
224
+ 2. revoke `NPM_CREATE_ACCESS_TOKEN` and any older automation tokens;
225
+ 3. keep normal development on npm `10.9.8`;
226
+ 4. create future GitHub releases from reviewed `v<version>` tags to trigger
227
+ the trusted workflow.
228
+
229
+ The workflow safely skips a version already present on npm. This lets the
230
+ GitHub release for the token-bootstrapped `v0.2.0` tag be created without a
231
+ duplicate publish attempt.
232
+
233
+ ## Tag the published release
234
+
235
+ For the initial token-bootstrap release, create the tag on the exact published
236
+ commit:
237
+
238
+ ```bash
239
+ RELEASE_VERSION="$(node -p "require('./package.json').version")"
240
+ : "${RELEASE_COMMIT:?Run the publish steps above in this terminal first}"
241
+ test "$RELEASE_COMMIT" = "$(git rev-parse HEAD)"
242
+ git tag -a "v${RELEASE_VERSION}" "$RELEASE_COMMIT" -m "v${RELEASE_VERSION}"
243
+ git push origin "v${RELEASE_VERSION}"
244
+ ```
245
+
246
+ The tag CI run validates that `v<version>` matches the package, lockfile, and
247
+ changelog. For later OIDC releases, push the reviewed tag first and create the
248
+ GitHub release from it; publishing the GitHub release triggers the trusted
249
+ workflow. Copy the matching changelog entry into the release notes.
250
+
251
+ ## Verify as a package user
252
+
253
+ In a separate terminal, check the version and launch the exact release:
254
+
255
+ ```bash
256
+ npm view relmio version
257
+ npx --yes --ignore-scripts relmio@PUBLISHED_VERSION
258
+ ```
259
+
260
+ Replace `PUBLISHED_VERSION` with the number just published. Confirm that the
261
+ local wizard opens, then press Control+C before entering real credentials if
262
+ this is only a smoke test.
263
+
264
+ The CLI currently has no `--help` argument parser. Do not use a `--help`
265
+ invocation as a release check; it starts the wizard like any other argument.
266
+
267
+ ## If something goes wrong
268
+
269
+ - `ENEEDAUTH`: run `npm login`, complete npm's browser approval, and retry
270
+ `npm whoami`.
271
+ - `E403`: confirm the intended npm account owns the package and complete the
272
+ configured publishing second factor.
273
+ - `EPUBLISHCONFLICT`: the version is immutable and already exists. Bump to a
274
+ new patch version; never delete or overwrite it.
275
+ - Registry version differs from `package.json`: stop before tagging. Determine
276
+ whether the publish succeeded and prepare a new release if necessary.
277
+ - The Git commit was pushed but npm publish failed: fix npm authentication or
278
+ policy, rerun the gates on the same clean commit, and publish that version.
279
+ - npm publish succeeded but the tag push failed: do not republish. Push the
280
+ tag for the exact already-published commit.
281
+ - `npx` cannot see a just-published version: verify the exact registry version
282
+ and wait briefly for registry/CDN propagation.
283
+
284
+ Do not publish from the VPS. Never put an npm access token in the GitHub
285
+ Actions workflow; the trusted workflow authenticates only through OIDC.
@@ -0,0 +1,109 @@
1
+ # Product roadmap
2
+
3
+ This roadmap describes intended research and product direction. It is not a
4
+ promise that a provider, subscription tier, or unofficial integration will
5
+ remain available. Every provider must pass its own technical, security, terms,
6
+ and entitlement checks before Relmio presents it as supported.
7
+
8
+ ## Product direction
9
+
10
+ Relmio currently gives self-hosted n8n a private OpenAI-compatible endpoint
11
+ backed by a supported ChatGPT/Codex OAuth sign-in. The longer-term product is a
12
+ provider-neutral local gateway:
13
+
14
+ ```text
15
+ OpenAI-compatible client
16
+ -> private Relmio endpoint
17
+ -> selected provider adapter
18
+ -> provider-authorized OAuth or API access
19
+ ```
20
+
21
+ The client should not need to understand each provider's authentication flow.
22
+ Provider credentials must remain isolated from one another, protected like
23
+ passwords, and excluded from responses, logs, package contents, and Git.
24
+
25
+ ## Before the first npm publication
26
+
27
+ - Finalize the public name while the package is still unpublished.
28
+ - Screen the chosen name for pronunciation, search collisions, npm and GitHub
29
+ availability, relevant domains, and appropriate trademark review.
30
+ - Keep the existing `n8n-openai-oauth` deployment identifiers until a tested
31
+ migration exists; public branding must not silently change safety boundaries.
32
+
33
+ ## Milestone 1: provider-neutral foundation
34
+
35
+ - Define a provider adapter contract for authentication, token refresh, model
36
+ discovery, request transport, streaming, and normalized errors.
37
+ - Keep the current ChatGPT/Codex implementation working while separating its
38
+ provider-specific behavior from the n8n installation workflow.
39
+ - Define capability reporting so clients can distinguish Responses API,
40
+ chat-completions, streaming, reasoning, and tool-calling support.
41
+ - Add contract tests that can be run against fakes without storing real OAuth
42
+ credentials in fixtures.
43
+ - Design future non-n8n client access under a separate threat model. The
44
+ current private-network and no-published-port rules remain in force until
45
+ that design is approved and tested.
46
+
47
+ ### Exit criteria
48
+
49
+ - The current n8n setup behaves exactly as before.
50
+ - A provider can be added without weakening SSH verification, confirmation
51
+ gates, credential handling, or the private sidecar boundary.
52
+ - Unsupported provider capabilities fail explicitly instead of being silently
53
+ translated into a different behavior.
54
+
55
+ ## Milestone 2: SuperGrok / xAI OAuth feasibility
56
+
57
+ Research as of July 29, 2026 indicates this is technically plausible:
58
+
59
+ - xAI's official Grok Build documentation supports browser OAuth and a
60
+ device-code flow, stores credentials locally with owner-only permissions,
61
+ and refreshes access tokens automatically.
62
+ - Hermes Agent documents an `xai-oauth` provider for SuperGrok and X Premium+
63
+ using xAI's Responses-style endpoint at `https://api.x.ai/v1`.
64
+ - Hermes also documents an important limitation: OAuth can succeed while xAI
65
+ inference returns HTTP 403 because access is gated by subscription tier or
66
+ account entitlement.
67
+
68
+ Relmio should run a dedicated feasibility spike before promising support:
69
+
70
+ 1. Confirm current xAI terms and whether Relmio can register or use an
71
+ approved public OAuth client for this purpose.
72
+ 2. Prefer Relmio's own approved client registration or an officially
73
+ supported xAI integration. Do not copy Hermes credentials, browser cookies,
74
+ or another application's private client material.
75
+ 3. Test browser and headless device-code login, refresh-token rotation,
76
+ revocation, expiry, and logout with a non-production account.
77
+ 4. Test entitlement behavior across the intended SuperGrok tiers and preserve
78
+ HTTP 403 as an unsupported-account result; never work around provider gates.
79
+ 5. Prototype `/v1/models`, `/v1/responses`, streaming, reasoning, and
80
+ tool-calling through a provider adapter.
81
+ 6. Verify the resulting endpoint in n8n's OpenAI Chat Model, AI Agent, Basic
82
+ LLM Chain, and HTTP Request nodes.
83
+ 7. Repeat the current secret-handling and network-safety review: owner-only
84
+ credentials, no token logging, no public host port, and no n8n mutation.
85
+
86
+ ### Decision gate
87
+
88
+ - **Proceed:** xAI authorizes the OAuth client and tested subscription tiers,
89
+ refresh works reliably, and the required n8n/OpenAI-compatible contracts
90
+ pass.
91
+ - **Defer:** the flow works only through unstable or undocumented behavior.
92
+ - **Do not implement:** support would require cookie scraping, copied client
93
+ credentials, bypassing entitlement controls, or violating current terms.
94
+ Document the official xAI API-key route as the fallback instead.
95
+
96
+ ## Not in the first provider expansion
97
+
98
+ - Publicly exposing the gateway to the internet.
99
+ - Pooling or sharing subscriptions between users.
100
+ - Bypassing quotas, provider safeguards, or subscription-tier restrictions.
101
+ - Automatically routing one request across multiple paid accounts.
102
+ - Claiming complete OpenAI compatibility when a provider supports only a
103
+ subset of the protocol.
104
+
105
+ ## Research references
106
+
107
+ - [xAI Grok Build authentication](https://github.com/xai-org/grok-build/blob/main/crates/codegen/xai-grok-pager/docs/user-guide/02-authentication.md)
108
+ - [Hermes Agent: xAI Grok OAuth](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/guides/xai-grok-oauth.md)
109
+ - [Hermes Agent provider documentation](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/integrations/providers.md)
@@ -0,0 +1,105 @@
1
+ # Security and limitations
2
+
3
+ This project handles two password-equivalent secrets: a ChatGPT OAuth
4
+ credential and an SSH authentication method. Read this page before offering
5
+ the wizard to another person.
6
+
7
+ ## Trust model
8
+
9
+ The design assumes:
10
+
11
+ - the local computer is trusted;
12
+ - the VPS and its root account are trusted;
13
+ - other containers on the selected Docker network are trusted;
14
+ - the pinned `openai-oauth` and `ssh2` dependencies are acceptable for
15
+ personal experimental use.
16
+
17
+ If any of those assumptions is false, do not use this design.
18
+
19
+ ## Controls implemented by the wizard
20
+
21
+ - The web server binds only to `127.0.0.1`.
22
+ - Every API request needs a random 256-bit session token.
23
+ - POST requests must have the exact localhost origin.
24
+ - Browser responses disable caching, framing, cross-origin access, and
25
+ unnecessary permissions.
26
+ - Request bodies and remote command output have size limits.
27
+ - Login, fingerprint, and connection attempts are rate-limited.
28
+ - The password field unlocks only after the SSH fingerprint is confirmed.
29
+ - The server binds that confirmation to the exact normalized host and port.
30
+ - Passwords are request-scoped, never saved, never logged, and cleared from
31
+ the page immediately after the connection attempt.
32
+ - ChatGPT login is written first to a unique pending file, validated, and then
33
+ stored at `~/.n8n-openai-oauth/auth.json` with owner-only permissions. The
34
+ Codex app credential at `~/.codex/auth.json` is not reused or overwritten.
35
+ - OAuth JSON is validated and transferred through SFTP, never interpolated
36
+ into a shell command.
37
+ - Remote paths are restricted to `/docker/n8n-openai-oauth`.
38
+ - Docker names are allowlisted before they can enter a command.
39
+ - Generated mutation commands come from a closed static allowlist.
40
+ - The sidecar runs as user `node`, drops all Linux capabilities, uses
41
+ `no-new-privileges`, and has a read-only root filesystem.
42
+ - There is no host `ports` mapping and no reverse-proxy route.
43
+ - The installer verifies the absence of a published port after startup.
44
+
45
+ ## What “private” means here
46
+
47
+ Port `10531` is not reachable from the public internet or VPS host through a
48
+ Docker port mapping. It is reachable by containers attached to the selected
49
+ Docker network.
50
+
51
+ The bridge must listen on `0.0.0.0` inside its container so n8n can reach it.
52
+ The upstream warning about a non-loopback host is therefore expected. The
53
+ protection is the absence of `ports:` and Traefik labels.
54
+
55
+ Do not attach untrusted containers to the same Docker network.
56
+
57
+ ## Credential consequences
58
+
59
+ The copied `auth.json` lets the sidecar act through your ChatGPT account. A
60
+ root compromise of the VPS, Docker socket access, or a compromised sidecar can
61
+ expose it.
62
+
63
+ - Never commit `auth.json`.
64
+ - Never paste it into issues, logs, screenshots, or chat.
65
+ - Do not share one account across customers or users.
66
+ - Do not expose the bridge on a domain or public IP.
67
+ - Revoke or refresh the session if the VPS may be compromised.
68
+ - Prefer a dedicated personal VPS with current security updates.
69
+
70
+ ## Product and policy limitations
71
+
72
+ - This is not an OpenAI Platform API key.
73
+ - A ChatGPT subscription does not normally include OpenAI API credits;
74
+ [OpenAI documents the billing separation here](https://help.openai.com/en/articles/8156019-i-want-to-move-my-chatgpt-subscription-to-the-api).
75
+ - The bridge is unofficial and can stop working when upstream behavior changes.
76
+ - Models depend on the ChatGPT plan and can change without a project release.
77
+ - The bridge's Responses endpoint is stateless and expects full conversation
78
+ history from the caller.
79
+ - Rate limits and account restrictions still apply.
80
+ - OpenAI can change or discontinue service behavior and can suspend access for
81
+ Terms or usage-policy violations.
82
+
83
+ This repository does not claim that every possible use of the bridge is
84
+ permitted. The account owner is responsible for reviewing the current
85
+ [OpenAI Terms](https://openai.com/policies/terms-of-use/) and usage policies.
86
+
87
+ ## Dependency policy
88
+
89
+ The current release pins:
90
+
91
+ - Node.js 22+
92
+ - `ssh2` `1.17.0`
93
+ - `openai-oauth` `2.0.0`
94
+
95
+ Install scripts are disabled for local dependencies. The generated sidecar
96
+ also installs `openai-oauth` with `--ignore-scripts`.
97
+
98
+ Do not replace pinned versions with `latest` in production. Follow the upgrade
99
+ checklist in [maintenance.md](maintenance.md).
100
+
101
+ ## Reporting a security problem
102
+
103
+ Do not open a public issue containing a token, password, private IP, hostname,
104
+ workflow data, or unredacted log. Revoke exposed credentials first, then share
105
+ only a sanitized reproduction with the repository owner.