@oalo-ai/cli 0.1.0 → 0.1.1
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/README.md +1 -1
- package/man/oalo.1 +13 -13
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/src/channel.js +1 -1
- package/src/commands/deploy.js +4 -4
- package/src/commands/env.js +2 -2
- package/src/commands/link.js +3 -3
- package/src/commands/logs.js +1 -1
- package/src/commands/secrets.js +1 -1
- package/src/commands/skill.js +4 -4
- package/src/commands/typegen.js +8 -8
- package/src/commands/whoami.js +1 -1
- package/src/config.js +1 -1
- package/src/help.js +13 -13
- package/src/server.js +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @oalo-ai/cli
|
|
2
2
|
|
|
3
|
-
Work on an
|
|
3
|
+
Work on an Oalo workspace from your terminal: edit chat flows, loops and code
|
|
4
4
|
tools as files and push them back safely, run test conversations with a bot,
|
|
5
5
|
generate typed bindings for your own app, and serve all of it to a coding agent
|
|
6
6
|
over MCP.
|
package/man/oalo.1
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.TH OALO 1 "" "oalo 0.1.0" "OALO CLI"
|
|
2
2
|
.SH NAME
|
|
3
|
-
oalo \- wire a local app into your
|
|
3
|
+
oalo \- wire a local app into your Oalo workspace
|
|
4
4
|
.SH SYNOPSIS
|
|
5
5
|
.B oalo
|
|
6
6
|
.I command
|
|
@@ -85,13 +85,13 @@ Which schema later commands touch. Default dev.
|
|
|
85
85
|
Show the current link and re\-check reachability.
|
|
86
86
|
.TP
|
|
87
87
|
\fB\-\-no\-skill\fR
|
|
88
|
-
Don't install or refresh the
|
|
88
|
+
Don't install or refresh the Oalo skill for coding agents (see \fBoalo skill\fR).
|
|
89
89
|
.IP \(bu 2
|
|
90
90
|
Every token is verified against the thing it is for BEFORE anything is saved, so a bad or mixed\-up token fails here rather than later.
|
|
91
91
|
.IP \(bu 2
|
|
92
92
|
Writes .oalo/config.json (safe to commit) and ~/.oalo/credentials.json (mode 0600, never in the project). OALO_HOME relocates the credential store.
|
|
93
93
|
.IP \(bu 2
|
|
94
|
-
Also installs the
|
|
94
|
+
Also installs the Oalo skill for coding agents (.claude/skills/oalo/SKILL.md), or refreshes it, from this CLI version; an AGENTS.md section from \fBoalo skill \-\-agents\fR is refreshed too.
|
|
95
95
|
.PP
|
|
96
96
|
Exit codes: 0 linked; 1 verification failed; 2 missing or invalid arguments.
|
|
97
97
|
.SS typegen
|
|
@@ -802,7 +802,7 @@ The token is printed once. Copy it into the app server's secrets right away.
|
|
|
802
802
|
.PP
|
|
803
803
|
Exit codes: 0 done; 1 refused or failed; 2 bad arguments or no CLI token.
|
|
804
804
|
.SS docs
|
|
805
|
-
Read the
|
|
805
|
+
Read the Oalo platform docs from your workspace: list, search, or print a page as markdown.
|
|
806
806
|
.PP
|
|
807
807
|
\fBoalo docs [\-\-audience developer|trainer] [\-\-json]\fR
|
|
808
808
|
.br
|
|
@@ -822,7 +822,7 @@ Structured output: summaries for a list or search, the full page with markdown f
|
|
|
822
822
|
.IP \(bu 2
|
|
823
823
|
Served by your workspace's own server (its Base), so the pages match the version it runs.
|
|
824
824
|
.IP \(bu 2
|
|
825
|
-
Good starting pages for building on
|
|
825
|
+
Good starting pages for building on Oalo: bring\-your\-repo and connect\-your\-own\-frontend for your own code, app\-environment, tokens\-and\-credentials, data\-models, sync\-rest\-api, triggers\-and\-chaining.
|
|
826
826
|
.IP \(bu 2
|
|
827
827
|
A page goes to stdout as markdown, so \fBoalo docs data\-models > notes.md\fR saves it. Related pages are listed on stderr.
|
|
828
828
|
.PP
|
|
@@ -879,7 +879,7 @@ With \-\-from: the branch to import. Default: the repository's default branch.
|
|
|
879
879
|
With \-\-from: for a private repository, the environment variable holding an access token that can read it (a GitHub, GitLab, Bitbucket or Forgejo personal access token). Without it, at a terminal, you're asked for the token, hidden, when the host wants one. It is used for that one clone: never stored, logged or kept in the app's repo.
|
|
880
880
|
.TP
|
|
881
881
|
\fB\-\-pull\fR
|
|
882
|
-
Fetch the app's code as
|
|
882
|
+
Fetch the app's code as Oalo has it into oalo/<slug>, to merge changes made there (by the builder agent or a teammate).
|
|
883
883
|
.TP
|
|
884
884
|
\fB\-\-replace\fR
|
|
885
885
|
Make this branch the app's code even though the histories differ. The app's current code is tagged first so it can be recovered.
|
|
@@ -912,7 +912,7 @@ Admins and members with Developer access only. Progress streams while it runs.
|
|
|
912
912
|
.PP
|
|
913
913
|
Exit codes: 0 deployed; 1 refused or failed; 2 bad arguments, no CLI token, or not in a git repo.
|
|
914
914
|
.SS env
|
|
915
|
-
An app's environment variables on
|
|
915
|
+
An app's environment variables on Oalo (API keys, settings), per env: list, set, unset, rotate\-token.
|
|
916
916
|
.PP
|
|
917
917
|
\fBoalo env [\-\-app <slug>] [\-\-env dev|prod] [\-\-json]\fR
|
|
918
918
|
.br
|
|
@@ -951,7 +951,7 @@ Server apps get every variable, in the preview and live. Static apps (React, Exp
|
|
|
951
951
|
.IP \(bu 2
|
|
952
952
|
Names Oalo sets itself can't be set: any starting with OALO_, PORT, DATABASE_URL, APP_SCHEMA, APP_SLUG, CONTAINER_HOST (and their VITE_/EXPO_PUBLIC_ forms), and the process basics (PATH, HOME, LANG, TZ, the Mix, Hex and Flutter homes). \fBoalo env set\fR refuses one by name.
|
|
953
953
|
.IP \(bu 2
|
|
954
|
-
A server app gets OALO_URL and OALO_SYNC_TOKEN: a Sync API token for its own env's data that can also send events, call workflows and start chat sessions, so it needs no token of its own. It also signs
|
|
954
|
+
A server app gets OALO_URL and OALO_SYNC_TOKEN: a Sync API token for its own env's data that can also send events, call workflows and start chat sessions, so it needs no token of its own. It also signs Oalo's calls to the app's endpoints (.oalo/app.json tools). The preview's token can't touch live data, and its events and workflow calls are test runs. \fBrotate\-token\fR replaces it at once and restarts the app on the new one.
|
|
955
955
|
.IP \(bu 2
|
|
956
956
|
A dev change restarts the preview. A prod change relaunches the live app at the commit it already runs (a build; no new code goes out). \-\-no\-restart skips that, to batch several changes: the last one without it relaunches.
|
|
957
957
|
.IP \(bu 2
|
|
@@ -994,7 +994,7 @@ How a server app's live image is built, and the Dockerfile it builds from.
|
|
|
994
994
|
The app (\fBoalo apps\fR lists them). Default: the app saved with \fBoalo link \-\-app\fR.
|
|
995
995
|
.TP
|
|
996
996
|
\fB\-\-write\fR
|
|
997
|
-
Save
|
|
997
|
+
Save Oalo's Dockerfile as ./Dockerfile, to change. Once committed, the repo's copy is used.
|
|
998
998
|
.TP
|
|
999
999
|
\fB\-\-force\fR
|
|
1000
1000
|
With \-\-write, replace an existing ./Dockerfile.
|
|
@@ -1002,7 +1002,7 @@ With \-\-write, replace an existing ./Dockerfile.
|
|
|
1002
1002
|
\fB\-\-json\fR
|
|
1003
1003
|
method, source (repo or oalo), runtime and the Dockerfile's text.
|
|
1004
1004
|
.IP \(bu 2
|
|
1005
|
-
The first that fits: the repo's own Dockerfile;
|
|
1005
|
+
The first that fits: the repo's own Dockerfile; Oalo's for the runtime, for the languages buildpacks can't build; buildpacks for the rest. \fBoalo docs live\-server\-apps\fR lists which language gets which.
|
|
1006
1006
|
.IP \(bu 2
|
|
1007
1007
|
Every image runs as uid 1000 with a read\-only filesystem (/tmp is writable) and must serve $PORT. A Procfile's lines still name the processes: web runs the image's own command when the Procfile has no web line.
|
|
1008
1008
|
.PP
|
|
@@ -1020,7 +1020,7 @@ The app (\fBoalo apps\fR lists them). Default: the app saved with \fBoalo link \
|
|
|
1020
1020
|
dev is the preview, prod the live app. Default dev.
|
|
1021
1021
|
.TP
|
|
1022
1022
|
\fB\-\-process <name>\fR
|
|
1023
|
-
Only this process: web, a Procfile worker's name, release, build (a live build's output, with \-\-env prod), or oalo (
|
|
1023
|
+
Only this process: web, a Procfile worker's name, release, build (a live build's output, with \-\-env prod), or oalo (Oalo's own notes).
|
|
1024
1024
|
.TP
|
|
1025
1025
|
\fB\-\-limit N\fR
|
|
1026
1026
|
How many recent lines (default 200, at most 2000).
|
|
@@ -1033,7 +1033,7 @@ One JSON object per line: at, process, line.
|
|
|
1033
1033
|
.IP \(bu 2
|
|
1034
1034
|
The workspace keeps the last 2,000 lines per env in memory; restarting the workspace empties them.
|
|
1035
1035
|
.IP \(bu 2
|
|
1036
|
-
Lines from \fBoalo\fR are
|
|
1036
|
+
Lines from \fBoalo\fR are Oalo's own: which command started, and when a process exited and with what status.
|
|
1037
1037
|
.IP \(bu 2
|
|
1038
1038
|
Admins and members with Developer access only: an app can print secrets or customers' details.
|
|
1039
1039
|
.PP
|
|
@@ -1263,7 +1263,7 @@ Needs a CLI token.
|
|
|
1263
1263
|
.PP
|
|
1264
1264
|
Exit codes: 0 every scenario passed; 1 a scenario failed or the run failed; 2 bad arguments or no token.
|
|
1265
1265
|
.SS skill
|
|
1266
|
-
Teach this project's coding agent how to work on
|
|
1266
|
+
Teach this project's coding agent how to work on Oalo.
|
|
1267
1267
|
.PP
|
|
1268
1268
|
\fBoalo skill [\-\-agents]\fR
|
|
1269
1269
|
.br
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oalo",
|
|
3
|
-
"description": "Work on an
|
|
3
|
+
"description": "Work on an Oalo workspace from Claude Code: edit chat flows, loops and code tools, lint and push them safely, and run test conversations with a bot.",
|
|
4
4
|
"version": "0.1.0",
|
|
5
|
-
"author": { "name": "
|
|
5
|
+
"author": { "name": "Oalo" },
|
|
6
6
|
"mcpServers": {
|
|
7
7
|
"oalo": {
|
|
8
8
|
"command": "npx",
|
package/src/channel.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Socket } from "phoenix";
|
|
|
2
2
|
import WebSocket from "ws";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Thin client over the
|
|
5
|
+
* Thin client over the Oalo BuilderChannel — the same Phoenix channel the
|
|
6
6
|
* dashboard drives, which is where the whole build surface lives (there is no
|
|
7
7
|
* REST API for it).
|
|
8
8
|
*
|
package/src/commands/deploy.js
CHANGED
|
@@ -16,7 +16,7 @@ import { readValue } from "./env.js";
|
|
|
16
16
|
* oalo deploy --new [<name>] a new app from this repo, its history kept
|
|
17
17
|
* oalo deploy --new [<name>] --from <url> a new app from a Git URL, cloned by the Base
|
|
18
18
|
* oalo deploy --app <slug> --env prod build and swap the live release
|
|
19
|
-
* oalo deploy --app <slug> --pull fetch the app's code from
|
|
19
|
+
* oalo deploy --app <slug> --pull fetch the app's code from Oalo as oalo/<slug>
|
|
20
20
|
* oalo deploy --app <slug> --replace make this branch the app's code (old code is tagged)
|
|
21
21
|
* oalo deploy --app <slug> --history the live releases it has had
|
|
22
22
|
* oalo deploy --app <slug> --rollback [--to <sha>] make an earlier release live again
|
|
@@ -118,7 +118,7 @@ export async function deploy(flags) {
|
|
|
118
118
|
if (result.error) {
|
|
119
119
|
const e = result.error;
|
|
120
120
|
console.error(`deploy failed: ${e.message}`);
|
|
121
|
-
for (const c of e.box_only || []) console.error(dim(` on
|
|
121
|
+
for (const c of e.box_only || []) console.error(dim(` on Oalo only: ${c}`));
|
|
122
122
|
process.exitCode = 1;
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
@@ -323,7 +323,7 @@ async function pull(url, token, app, root) {
|
|
|
323
323
|
const ref = `refs/remotes/oalo/${app}`;
|
|
324
324
|
git(["fetch", "--quiet", "--no-tags", file, `+HEAD:${ref}`], root);
|
|
325
325
|
const sha = git(["rev-parse", ref], root);
|
|
326
|
-
console.log(`fetched ${app} as it is on
|
|
326
|
+
console.log(`fetched ${app} as it is on Oalo (${sha.slice(0, 8)}) into oalo/${app}.`);
|
|
327
327
|
console.log(dim(`Merge it, then deploy again:\n git merge oalo/${app}\n oalo deploy --app ${app}`));
|
|
328
328
|
} finally {
|
|
329
329
|
rmSync(dir, { recursive: true, force: true });
|
|
@@ -381,7 +381,7 @@ function fail(message, code) {
|
|
|
381
381
|
* `--history` lists the live releases; `--rollback` launches the one before the
|
|
382
382
|
* current release (or `--to <sha>`). A rollback builds and checks that commit
|
|
383
383
|
* like any live deploy, so a failing one leaves the current release live. It
|
|
384
|
-
* doesn't touch the app's code on
|
|
384
|
+
* doesn't touch the app's code on Oalo: the next deploy carries on from there.
|
|
385
385
|
*/
|
|
386
386
|
async function releases(url, token, app, flags, opts = {}) {
|
|
387
387
|
const { OaloChannel } = await import("../channel.js");
|
package/src/commands/env.js
CHANGED
|
@@ -6,7 +6,7 @@ import { dim } from "../events.js";
|
|
|
6
6
|
import { parseDotenv, parseAssignment } from "../envfile.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* `oalo env`: an app's environment variables on
|
|
9
|
+
* `oalo env`: an app's environment variables on Oalo, per env.
|
|
10
10
|
*
|
|
11
11
|
* oalo env [--app <slug>] [--env dev|prod] [--json] list them
|
|
12
12
|
* oalo env set NAME=value [NAME=value ...] [--secret | --public]
|
|
@@ -22,7 +22,7 @@ import { parseDotenv, parseAssignment } from "../envfile.js";
|
|
|
22
22
|
* the live app at the commit it already runs (no new code), unless
|
|
23
23
|
* --no-restart, to batch several.
|
|
24
24
|
*
|
|
25
|
-
* A server app also gets OALO_URL and OALO_SYNC_TOKEN from
|
|
25
|
+
* A server app also gets OALO_URL and OALO_SYNC_TOKEN from Oalo itself, a
|
|
26
26
|
* token for its own env's data. `rotate-token` replaces it: the old one stops
|
|
27
27
|
* working at once, and the preview restarts, or the live app's current commit
|
|
28
28
|
* is relaunched.
|
package/src/commands/link.js
CHANGED
|
@@ -98,15 +98,15 @@ export async function link(flags) {
|
|
|
98
98
|
console.log(` token ${credPath} (never committed)`);
|
|
99
99
|
if (addedRule) console.log(`\n added .oalo/credentials* to .gitignore`);
|
|
100
100
|
|
|
101
|
-
// The coding agent in this project learns
|
|
101
|
+
// The coding agent in this project learns Oalo from the skill, the one that
|
|
102
102
|
// matches this CLI. --no-skill leaves the project alone.
|
|
103
103
|
if (!flags["no-skill"]) {
|
|
104
104
|
try {
|
|
105
105
|
const had = installedSkillVersion();
|
|
106
106
|
const r = installSkill();
|
|
107
|
-
console.log(`\n ${had ? "refreshed" : "installed"} the
|
|
107
|
+
console.log(`\n ${had ? "refreshed" : "installed"} the Oalo skill for coding agents: ${r.path}${r.agents ? ` (and AGENTS.md)` : ""}`);
|
|
108
108
|
} catch (e) {
|
|
109
|
-
console.error(`\n couldn't install the
|
|
109
|
+
console.error(`\n couldn't install the Oalo skill (${e.message}); \`oalo skill\` tries again`);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
// A Flutter app from Oalo's template takes Dart, not TypeScript.
|
package/src/commands/logs.js
CHANGED
|
@@ -10,7 +10,7 @@ import { dim } from "../events.js";
|
|
|
10
10
|
* oalo logs [--app <slug>] [--env dev|prod] [--process web|<worker>] [--limit N] [--follow] [--json]
|
|
11
11
|
*
|
|
12
12
|
* The workspace keeps the last 2,000 lines of each env in memory, so a restart
|
|
13
|
-
* of the workspace empties them. `oalo` lines are
|
|
13
|
+
* of the workspace empties them. `oalo` lines are Oalo's own notes: starts,
|
|
14
14
|
* exits and their status.
|
|
15
15
|
*/
|
|
16
16
|
export async function logs(flags, rest, opts = {}) {
|
package/src/commands/secrets.js
CHANGED
|
@@ -4,7 +4,7 @@ import { requireFeature } from "../server.js";
|
|
|
4
4
|
import { dim } from "../events.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* `oalo secrets`: keys and tokens
|
|
7
|
+
* `oalo secrets`: keys and tokens Oalo found committed to an app's code (on
|
|
8
8
|
* import, and in each push or deploy's new commits). Only where each one is
|
|
9
9
|
* and what it looks like: no value is ever kept.
|
|
10
10
|
*
|
package/src/commands/skill.js
CHANGED
|
@@ -7,7 +7,7 @@ import { CLI_VERSION } from "../server.js";
|
|
|
7
7
|
import { dim } from "../events.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* `oalo skill`: teach the coding agent in this project how to work on
|
|
10
|
+
* `oalo skill`: teach the coding agent in this project how to work on Oalo.
|
|
11
11
|
*
|
|
12
12
|
* oalo skill install .claude/skills/oalo/SKILL.md (Claude Code loads it)
|
|
13
13
|
* oalo skill --agents also add the same rules to AGENTS.md, for other agents
|
|
@@ -124,9 +124,9 @@ export function skillNotice(cwd = process.cwd()) {
|
|
|
124
124
|
} catch {
|
|
125
125
|
/* a read-only home: say it every time rather than never */
|
|
126
126
|
}
|
|
127
|
-
if (sameVersion) return "This project's
|
|
127
|
+
if (sameVersion) return "This project's Oalo skill (.claude/skills/oalo/SKILL.md) is older than the one this CLI carries. Run `oalo skill` to update it.";
|
|
128
128
|
const from = installed === "old" ? "an older CLI" : `CLI ${installed}`;
|
|
129
|
-
return `This project's
|
|
129
|
+
return `This project's Oalo skill (.claude/skills/oalo/SKILL.md) is from ${from}; you have ${CLI_VERSION}. Run \`oalo skill\` to update it.`;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
export async function skill(flags) {
|
|
@@ -137,6 +137,6 @@ export async function skill(flags) {
|
|
|
137
137
|
|
|
138
138
|
const r = installSkill(process.cwd(), { agents: !!flags.agents });
|
|
139
139
|
console.log(`installed ${r.path}`);
|
|
140
|
-
if (r.agents) console.log(`${r.agents} the
|
|
140
|
+
if (r.agents) console.log(`${r.agents} the Oalo section in AGENTS.md`);
|
|
141
141
|
console.log(dim(`From CLI ${CLI_VERSION}. Run \`oalo skill\` again after updating the CLI.`));
|
|
142
142
|
}
|
package/src/commands/typegen.js
CHANGED
|
@@ -109,7 +109,7 @@ function renderFields(name, fields) {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
// The workflows an app can call: their types, and `runWorkflow` to call one
|
|
112
|
-
// from the app's server with the token
|
|
112
|
+
// from the app's server with the token Oalo gives it.
|
|
113
113
|
function renderWorkflows(workflows) {
|
|
114
114
|
const list = [...workflows].sort((a, b) => a.name.localeCompare(b.name));
|
|
115
115
|
const type = (w) => pascal(w.name);
|
|
@@ -172,7 +172,7 @@ function renderServerHelpers() {
|
|
|
172
172
|
return [
|
|
173
173
|
``,
|
|
174
174
|
`// ── Server-side helpers ───────────────────────────────────────────────────`,
|
|
175
|
-
`// They use the OALO_URL and OALO_SYNC_TOKEN
|
|
175
|
+
`// They use the OALO_URL and OALO_SYNC_TOKEN Oalo gives a server app. Never`,
|
|
176
176
|
`// call them from a browser: the token must stay on the server.`,
|
|
177
177
|
``,
|
|
178
178
|
`export interface OaloServerOptions {`,
|
|
@@ -186,7 +186,7 @@ function renderServerHelpers() {
|
|
|
186
186
|
`async function oaloFetch(path: string, init: RequestInit, opts: OaloServerOptions): Promise<unknown> {`,
|
|
187
187
|
` const url = opts.url ?? oaloEnv("OALO_URL");`,
|
|
188
188
|
` const token = opts.token ?? oaloEnv("OALO_SYNC_TOKEN");`,
|
|
189
|
-
` if (!url || !token) throw new Error("OALO_URL and OALO_SYNC_TOKEN are not set: call
|
|
189
|
+
` if (!url || !token) throw new Error("OALO_URL and OALO_SYNC_TOKEN are not set: call Oalo from the app's server");`,
|
|
190
190
|
` const res = await fetch(url.replace(/\\/$/, "") + path, { ...init, headers: { Authorization: \`Bearer \${token}\`, "Content-Type": "application/json" } });`,
|
|
191
191
|
` const body = (await res.json().catch(() => null)) as { error?: string | { message?: string } } | null;`,
|
|
192
192
|
` const message = typeof body?.error === "string" ? body.error : body?.error?.message;`,
|
|
@@ -263,9 +263,9 @@ function renderServerHelpers() {
|
|
|
263
263
|
`}`,
|
|
264
264
|
``,
|
|
265
265
|
`/**`,
|
|
266
|
-
` * Check a request to a tool endpoint came from
|
|
266
|
+
` * Check a request to a tool endpoint came from Oalo, and for which user. Pass the`,
|
|
267
267
|
` * method, the path with its query as received, the headers and the RAW body (before`,
|
|
268
|
-
` * JSON parsing). Throws when it isn't
|
|
268
|
+
` * JSON parsing). Throws when it isn't Oalo's, or is over 5 minutes old.`,
|
|
269
269
|
` */`,
|
|
270
270
|
`export async function verifyOaloToolCall(`,
|
|
271
271
|
` req: { method: string; path: string; headers: Headers | Record<string, string | string[] | undefined>; body: string },`,
|
|
@@ -280,8 +280,8 @@ function renderServerHelpers() {
|
|
|
280
280
|
` const ts = header("x-oalo-timestamp");`,
|
|
281
281
|
` const sig = header("x-oalo-signature");`,
|
|
282
282
|
` const user = header("x-oalo-user") ?? "";`,
|
|
283
|
-
` if (!ts || !sig || !sig.startsWith("v1=")) throw new Error("not an
|
|
284
|
-
` if (!(Math.abs(Date.now() / 1000 - Number(ts)) <= (opts.maxAgeSeconds ?? 300))) throw new Error("the
|
|
283
|
+
` if (!ts || !sig || !sig.startsWith("v1=")) throw new Error("not an Oalo tool call");`,
|
|
284
|
+
` if (!(Math.abs(Date.now() / 1000 - Number(ts)) <= (opts.maxAgeSeconds ?? 300))) throw new Error("the Oalo tool call is too old");`,
|
|
285
285
|
` const enc = new TextEncoder();`,
|
|
286
286
|
` const key = await crypto.subtle.importKey("raw", enc.encode(token), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);`,
|
|
287
287
|
` const mac = new Uint8Array(await crypto.subtle.sign("HMAC", key, enc.encode([ts, req.method.toUpperCase(), req.path, user, req.body].join("\\n"))));`,
|
|
@@ -289,7 +289,7 @@ function renderServerHelpers() {
|
|
|
289
289
|
` const got = sig.slice(3);`,
|
|
290
290
|
` let diff = want.length ^ got.length;`,
|
|
291
291
|
` for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ (got.charCodeAt(i) || 0);`,
|
|
292
|
-
` if (diff !== 0) throw new Error("the
|
|
292
|
+
` if (diff !== 0) throw new Error("the Oalo signature doesn't match");`,
|
|
293
293
|
` return { tool: header("x-oalo-tool") ?? "", bot: header("x-oalo-bot") ?? "", conversation: header("x-oalo-conversation") || null, user: user || null };`,
|
|
294
294
|
`}`,
|
|
295
295
|
``,
|
package/src/commands/whoami.js
CHANGED
|
@@ -34,7 +34,7 @@ export async function whoami(flags) {
|
|
|
34
34
|
} catch (e) {
|
|
35
35
|
out.problems.push(
|
|
36
36
|
e.code === "unknown_event"
|
|
37
|
-
? `${url} runs an older
|
|
37
|
+
? `${url} runs an older Oalo, so it can't say who you are. Your CLI token does work.`
|
|
38
38
|
: `CLI token: ${e.message}`,
|
|
39
39
|
);
|
|
40
40
|
} finally {
|
package/src/config.js
CHANGED
|
@@ -140,7 +140,7 @@ export function ensureGitignored(cwd = process.cwd()) {
|
|
|
140
140
|
const rule = ".oalo/credentials*";
|
|
141
141
|
const current = existsSync(gi) ? readFileSync(gi, "utf8") : "";
|
|
142
142
|
if (current.includes(rule)) return false;
|
|
143
|
-
appendFileSync(gi, `${current.endsWith("\n") || !current ? "" : "\n"}\n#
|
|
143
|
+
appendFileSync(gi, `${current.endsWith("\n") || !current ? "" : "\n"}\n# Oalo — never commit credentials\n${rule}\n`);
|
|
144
144
|
return true;
|
|
145
145
|
}
|
|
146
146
|
|
package/src/help.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* same reason typegen reads the manifest instead of hardcoding a schema.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export const TAGLINE = "wire a local app into your
|
|
7
|
+
export const TAGLINE = "wire a local app into your Oalo workspace";
|
|
8
8
|
|
|
9
9
|
export const TOKENS = [
|
|
10
10
|
{
|
|
@@ -74,12 +74,12 @@ export const COMMANDS = [
|
|
|
74
74
|
{ flag: "--app <slug>", desc: "The app that deploy, env, logs, secrets and dockerfile use when you don't pass --app (`oalo apps` lists them). `oalo deploy --new` sets it." },
|
|
75
75
|
{ flag: "--env dev|prod", desc: "Which schema later commands touch. Default dev." },
|
|
76
76
|
{ flag: "--status", desc: "Show the current link and re-check reachability." },
|
|
77
|
-
{ flag: "--no-skill", desc: "Don't install or refresh the
|
|
77
|
+
{ flag: "--no-skill", desc: "Don't install or refresh the Oalo skill for coding agents (see `oalo skill`)." },
|
|
78
78
|
],
|
|
79
79
|
notes: [
|
|
80
80
|
"Every token is verified against the thing it is for BEFORE anything is saved, so a bad or mixed-up token fails here rather than later.",
|
|
81
81
|
"Writes .oalo/config.json (safe to commit) and ~/.oalo/credentials.json (mode 0600, never in the project). OALO_HOME relocates the credential store.",
|
|
82
|
-
"Also installs the
|
|
82
|
+
"Also installs the Oalo skill for coding agents (.claude/skills/oalo/SKILL.md), or refreshes it, from this CLI version; an AGENTS.md section from `oalo skill --agents` is refreshed too.",
|
|
83
83
|
],
|
|
84
84
|
exits: { 0: "linked", 1: "verification failed", 2: "missing or invalid arguments" },
|
|
85
85
|
},
|
|
@@ -500,7 +500,7 @@ export const COMMANDS = [
|
|
|
500
500
|
},
|
|
501
501
|
{
|
|
502
502
|
name: "docs",
|
|
503
|
-
summary: "Read the
|
|
503
|
+
summary: "Read the Oalo platform docs from your workspace: list, search, or print a page as markdown.",
|
|
504
504
|
usage: ["oalo docs [--audience developer|trainer] [--json]", "oalo docs <slug> [--json]", "oalo docs --search \"<words>\" [--json]"],
|
|
505
505
|
flags: [
|
|
506
506
|
{ flag: "--search <words>", desc: "Pages ranked for the words, each with the line that matched." },
|
|
@@ -509,7 +509,7 @@ export const COMMANDS = [
|
|
|
509
509
|
],
|
|
510
510
|
notes: [
|
|
511
511
|
"Served by your workspace's own server (its Base), so the pages match the version it runs.",
|
|
512
|
-
"Good starting pages for building on
|
|
512
|
+
"Good starting pages for building on Oalo: bring-your-repo and connect-your-own-frontend for your own code, app-environment, tokens-and-credentials, data-models, sync-rest-api, triggers-and-chaining.",
|
|
513
513
|
"A page goes to stdout as markdown, so `oalo docs data-models > notes.md` saves it. Related pages are listed on stderr.",
|
|
514
514
|
],
|
|
515
515
|
exits: { 0: "done", 1: "no such page, or the workspace failed", 2: "no CLI token" },
|
|
@@ -542,7 +542,7 @@ export const COMMANDS = [
|
|
|
542
542
|
{ flag: "--from <https url>", desc: "With --new: make the app from a Git repository at this address instead of this folder (no local checkout needed). The Base clones one branch with its whole history (https to a public host only, up to 200 MB, 5 minutes), then makes the app as --new does. The name defaults to the repository's. Nothing is linked here." },
|
|
543
543
|
{ flag: "--branch <name>", desc: "With --from: the branch to import. Default: the repository's default branch." },
|
|
544
544
|
{ flag: "--token-env <VAR>", desc: "With --from: for a private repository, the environment variable holding an access token that can read it (a GitHub, GitLab, Bitbucket or Forgejo personal access token). Without it, at a terminal, you're asked for the token, hidden, when the host wants one. It is used for that one clone: never stored, logged or kept in the app's repo." },
|
|
545
|
-
{ flag: "--pull", desc: "Fetch the app's code as
|
|
545
|
+
{ flag: "--pull", desc: "Fetch the app's code as Oalo has it into oalo/<slug>, to merge changes made there (by the builder agent or a teammate)." },
|
|
546
546
|
{ flag: "--replace", desc: "Make this branch the app's code even though the histories differ. The app's current code is tagged first so it can be recovered." },
|
|
547
547
|
{ flag: "--allow-dirty", desc: "Deploy the last commit even though there are uncommitted changes (which are not sent)." },
|
|
548
548
|
{ flag: "--history", desc: "The live releases the app has had, newest first." },
|
|
@@ -562,7 +562,7 @@ export const COMMANDS = [
|
|
|
562
562
|
},
|
|
563
563
|
{
|
|
564
564
|
name: "env",
|
|
565
|
-
summary: "An app's environment variables on
|
|
565
|
+
summary: "An app's environment variables on Oalo (API keys, settings), per env: list, set, unset, rotate-token.",
|
|
566
566
|
usage: [
|
|
567
567
|
"oalo env [--app <slug>] [--env dev|prod] [--json]",
|
|
568
568
|
"oalo env set NAME=value [NAME=value ...] [--secret | --public] [--no-restart]",
|
|
@@ -583,7 +583,7 @@ export const COMMANDS = [
|
|
|
583
583
|
"A variable is secret unless its name starts with VITE_, EXPO_PUBLIC_, NEXT_PUBLIC_, PUBLIC_ or REACT_APP_, or it's set with --public.",
|
|
584
584
|
"Server apps get every variable, in the preview and live. Static apps (React, Expo, Flutter) only get public ones, because whatever their build sees ends up in the browser.",
|
|
585
585
|
"Names Oalo sets itself can't be set: any starting with OALO_, PORT, DATABASE_URL, APP_SCHEMA, APP_SLUG, CONTAINER_HOST (and their VITE_/EXPO_PUBLIC_ forms), and the process basics (PATH, HOME, LANG, TZ, the Mix, Hex and Flutter homes). `oalo env set` refuses one by name.",
|
|
586
|
-
"A server app gets OALO_URL and OALO_SYNC_TOKEN: a Sync API token for its own env's data that can also send events, call workflows and start chat sessions, so it needs no token of its own. It also signs
|
|
586
|
+
"A server app gets OALO_URL and OALO_SYNC_TOKEN: a Sync API token for its own env's data that can also send events, call workflows and start chat sessions, so it needs no token of its own. It also signs Oalo's calls to the app's endpoints (.oalo/app.json tools). The preview's token can't touch live data, and its events and workflow calls are test runs. `rotate-token` replaces it at once and restarts the app on the new one.",
|
|
587
587
|
"A dev change restarts the preview. A prod change relaunches the live app at the commit it already runs (a build; no new code goes out). --no-restart skips that, to batch several changes: the last one without it relaunches.",
|
|
588
588
|
"Admins and members with Developer access only.",
|
|
589
589
|
],
|
|
@@ -611,12 +611,12 @@ export const COMMANDS = [
|
|
|
611
611
|
usage: ["oalo dockerfile [--app <slug>] [--json]", "oalo dockerfile --write [--force] [--app <slug>]"],
|
|
612
612
|
flags: [
|
|
613
613
|
{ flag: "--app <slug>", desc: "The app (`oalo apps` lists them). Default: the app saved with `oalo link --app`." },
|
|
614
|
-
{ flag: "--write", desc: "Save
|
|
614
|
+
{ flag: "--write", desc: "Save Oalo's Dockerfile as ./Dockerfile, to change. Once committed, the repo's copy is used." },
|
|
615
615
|
{ flag: "--force", desc: "With --write, replace an existing ./Dockerfile." },
|
|
616
616
|
{ flag: "--json", desc: "method, source (repo or oalo), runtime and the Dockerfile's text." },
|
|
617
617
|
],
|
|
618
618
|
notes: [
|
|
619
|
-
"The first that fits: the repo's own Dockerfile;
|
|
619
|
+
"The first that fits: the repo's own Dockerfile; Oalo's for the runtime, for the languages buildpacks can't build; buildpacks for the rest. `oalo docs live-server-apps` lists which language gets which.",
|
|
620
620
|
"Every image runs as uid 1000 with a read-only filesystem (/tmp is writable) and must serve $PORT. A Procfile's lines still name the processes: web runs the image's own command when the Procfile has no web line.",
|
|
621
621
|
],
|
|
622
622
|
exits: { 0: "done", 1: "refused or failed", 2: "bad arguments or no CLI token" },
|
|
@@ -628,14 +628,14 @@ export const COMMANDS = [
|
|
|
628
628
|
flags: [
|
|
629
629
|
{ flag: "--app <slug>", desc: "The app (`oalo apps` lists them). Default: the app saved with `oalo link --app`." },
|
|
630
630
|
{ flag: "--env dev|prod", desc: "dev is the preview, prod the live app. Default dev." },
|
|
631
|
-
{ flag: "--process <name>", desc: "Only this process: web, a Procfile worker's name, release, build (a live build's output, with --env prod), or oalo (
|
|
631
|
+
{ flag: "--process <name>", desc: "Only this process: web, a Procfile worker's name, release, build (a live build's output, with --env prod), or oalo (Oalo's own notes)." },
|
|
632
632
|
{ flag: "--limit N", desc: "How many recent lines (default 200, at most 2000)." },
|
|
633
633
|
{ flag: "--follow", desc: "Keep printing new lines as they come, until Ctrl-C." },
|
|
634
634
|
{ flag: "--json", desc: "One JSON object per line: at, process, line." },
|
|
635
635
|
],
|
|
636
636
|
notes: [
|
|
637
637
|
"The workspace keeps the last 2,000 lines per env in memory; restarting the workspace empties them.",
|
|
638
|
-
"Lines from `oalo` are
|
|
638
|
+
"Lines from `oalo` are Oalo's own: which command started, and when a process exited and with what status.",
|
|
639
639
|
"Admins and members with Developer access only: an app can print secrets or customers' details.",
|
|
640
640
|
],
|
|
641
641
|
exits: { 0: "done", 1: "refused or failed", 2: "bad arguments or no CLI token" },
|
|
@@ -790,7 +790,7 @@ export const COMMANDS = [
|
|
|
790
790
|
},
|
|
791
791
|
{
|
|
792
792
|
name: "skill",
|
|
793
|
-
summary: "Teach this project's coding agent how to work on
|
|
793
|
+
summary: "Teach this project's coding agent how to work on Oalo.",
|
|
794
794
|
usage: ["oalo skill [--agents]", "oalo skill --print"],
|
|
795
795
|
flags: [
|
|
796
796
|
{ flag: "--agents", desc: "Also write the rules into AGENTS.md (between oalo markers), for agents other than Claude Code." },
|
package/src/server.js
CHANGED
|
@@ -66,7 +66,7 @@ export async function requireFeature(url, feature, what) {
|
|
|
66
66
|
if (old) throw new Error(old);
|
|
67
67
|
if (!info.features.includes(feature)) {
|
|
68
68
|
throw new Error(
|
|
69
|
-
`${url} runs an older
|
|
69
|
+
`${url} runs an older Oalo than this CLI, so \`${what}\` isn't available there yet. It will be once the workspace is updated.`,
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
return info;
|