@ory/openclaw 0.13.9 → 1.0.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/README.md +67 -102
- package/dist/cli/main.d.ts +0 -1
- package/dist/cli/main.js +51 -13
- package/dist/cli/plugin-config.d.ts +12 -8
- package/dist/cli/plugin-config.js +22 -16
- package/dist/cli/setup.js +24 -5
- package/dist/plugin.d.ts +1 -19
- package/dist/plugin.js +127 -429
- package/dist/types.d.ts +8 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +9 -8
package/README.md
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Security and developer experience for [OpenClaw](https://github.com/openclaw/openclaw), powered by [Ory](https://ory.com).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
OpenClaw runs real actions on your machine — editing files, running shell commands, calling APIs. This plugin gives those actions an identity, a permission check, and an audit trail.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
One command installs two independent halves:
|
|
8
|
+
|
|
9
|
+
- **Developer experience** — the Ory skill catalog, the local Ory dev stack, an MCP server, and activity logging. No account, no keys, nothing to configure: it works the moment it's installed.
|
|
10
|
+
- **Ory Agent Security** — browser sign-in, brokered permission checks before tool calls, and the delegation trail. Opt-in connection details from the [Ory Console](https://console.ory.sh) switch it on, and it takes nothing away from the half above. See [Connect to Ory Agent Security](#connect-to-ory-agent-security).
|
|
8
11
|
|
|
9
12
|
## What you'll need
|
|
10
13
|
|
|
@@ -15,163 +18,126 @@ Security and developer experience for [OpenClaw](https://github.com/openclaw/ope
|
|
|
15
18
|
|
|
16
19
|
## Get started
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
2. **Govern the agent itself.** Authenticate OpenClaw's own session and authorize every tool it runs against Ory Permissions, with a full audit trail. See [Agent security](#agent-security).
|
|
20
|
-
|
|
21
|
-
If you're just exploring, do the Quickstart first.
|
|
22
|
-
|
|
23
|
-
## Prerequisites
|
|
24
|
-
|
|
25
|
-
- [OpenClaw](https://github.com/openclaw/openclaw) installed and configured
|
|
26
|
-
- Node.js **≥ 22**
|
|
27
|
-
- [Docker](https://docs.docker.com/get-docker/) (only needed for the local Ory stack)
|
|
28
|
-
- macOS or Linux. Windows works via WSL2.
|
|
29
|
-
|
|
30
|
-
## Install
|
|
31
|
-
|
|
32
|
-
OpenClaw discovers plugins by their manifest id (`ory-agent-security`) under the nested `plugins` object in `.openclaw/config.json` — it does not scan `node_modules`, so the plugin's location has to be registered. Two ways to do that:
|
|
33
|
-
|
|
34
|
-
**Recommended — OpenClaw's plugin ecosystem.** Copies the plugin into OpenClaw's managed extensions directory and enables it by id:
|
|
21
|
+
OpenClaw loads in-process plugins by module name plus an entry in `.openclaw/config.json` — it doesn't scan `node_modules`, so the plugin has to be registered. Install the package, then register it.:
|
|
35
22
|
|
|
36
23
|
```bash
|
|
37
|
-
|
|
38
|
-
openclaw
|
|
24
|
+
npm install @ory/openclaw # so OpenClaw can resolve the package
|
|
25
|
+
npx -y -p @ory/openclaw ory-openclaw install # register + enable in .openclaw/config.json
|
|
39
26
|
```
|
|
40
27
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
npm install @ory/openclaw # so OpenClaw can resolve the package
|
|
45
|
-
npx @ory/openclaw install # register + enable in .openclaw/config.json
|
|
46
|
-
npx @ory/openclaw install --project-dir <path>
|
|
47
|
-
npx @ory/openclaw uninstall
|
|
48
|
-
Run one command. It installs the plugin and walks you through connecting:
|
|
28
|
+
Registering also lays down the Ory skills (via `skills.load.extraDirs`) and the Ory MCP server. Confirm everything landed with:
|
|
49
29
|
|
|
50
30
|
```bash
|
|
51
|
-
npx -y -p @ory/openclaw ory-openclaw
|
|
31
|
+
npx -y -p @ory/openclaw ory-openclaw status
|
|
52
32
|
```
|
|
53
33
|
|
|
54
|
-
|
|
34
|
+
`status` is your one-stop check: what's configured, who's signed in, which tools are covered by permissions, plugin and skill registration, and recent activity. Until you connect Agent Security, the identity and permission rows say so and name what's missing.
|
|
55
35
|
|
|
56
|
-
|
|
57
|
-
- **Local** — run a complete Ory on your laptop with Docker. No account, no signup, no keys. Great for trying it out.
|
|
58
|
-
- **Audit-only** — skip Ory entirely and just log what OpenClaw does.
|
|
36
|
+
> Prefer OpenClaw's plugin ecosystem? Run `openclaw plugins install npm:@ory/openclaw` then `openclaw plugins enable ory-agent-security`. That registers the plugin the same way, with Agent Security not connected. Run `npx -y -p @ory/openclaw ory-openclaw install` afterwards to lay down the Ory skills and MCP server. Point the installer at another project with `install --project-dir <path>`.
|
|
59
37
|
|
|
60
|
-
|
|
38
|
+
## Skills and commands
|
|
61
39
|
|
|
62
|
-
|
|
63
|
-
npx -y -p @ory/openclaw ory-openclaw status
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
`status` is your one-stop check: what's configured, who's signed in, which tools are covered by permissions, plugin and skill registration, and recent activity. Anything not set up yet shows as `(unset)`.
|
|
40
|
+
Installing the plugin drops the full Ory playbook catalog into OpenClaw. **Skills** are model-invoked — say what you want in plain language, or pick one from OpenClaw's skill picker.
|
|
67
41
|
|
|
68
|
-
|
|
42
|
+
| Skill | What it does for you |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `ory-auth-setup` | Adds a complete auth system to your app — login, registration, recovery, verification, settings — on [Ory Elements](https://github.com/ory/elements) |
|
|
45
|
+
| `ory-login-flow` | Builds just the pages, wired to Ory's self-service flows |
|
|
46
|
+
| `ory-social-login` | "Sign in with…" for Google, GitHub, Apple, Microsoft, Discord, Slack, GitLab, Facebook |
|
|
47
|
+
| `ory-local-dev` | Develops and tests login/permission flows against a local Ory — no project, no account, offline |
|
|
48
|
+
| `ory-permissions-onboarding` | Walks a fresh install from observe mode to enforced per-tool permissions without getting blocked |
|
|
49
|
+
| `ory-build-agent` | Drops `@ory/argus` into an agent *you* own — Claude Agent SDK, OpenAI Agents, Mastra, Vercel AI, LangGraph/PydanticAI |
|
|
50
|
+
| `ory-build-integration` | Wires Ory into your app: Action webhooks, JWT validation at a gateway, live event streams |
|
|
51
|
+
| `ory-contribute-integration` | Authors and submits an integration to the public `ory/integrates` registry |
|
|
52
|
+
| `ory-e2b-sandbox` | Scaffolds an E2B sandbox template that boots with this plugin preinstalled |
|
|
53
|
+
| `ory-temporal-worker` | Scaffolds a Temporal TypeScript worker where every Activity is authenticated, authorized, and audited |
|
|
69
54
|
|
|
70
|
-
|
|
71
|
-
<summary>Register the plugin by hand</summary>
|
|
55
|
+
The local stack has its own playbooks — ask for them by name:
|
|
72
56
|
|
|
73
|
-
|
|
57
|
+
| Command | What it does |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `ory-local-up` | Starts a local Ory (Identities, OAuth2, Permissions) in Docker and seeds a test user — it prints the email + password to sign in with |
|
|
60
|
+
| `ory-local-down` | Stops it, keeping your data volumes |
|
|
61
|
+
| `ory-temporal-up` | Starts a local Temporal dev server for the `ory-temporal-worker` scaffold |
|
|
74
62
|
|
|
75
|
-
|
|
76
|
-
npx @ory/openclaw install # registers in .openclaw/config.json
|
|
77
|
-
npx @ory/openclaw install --project-dir <path>
|
|
78
|
-
npx @ory/openclaw uninstall
|
|
79
|
-
```
|
|
63
|
+
The local stack runs entirely on your laptop: Ory APIs at `http://localhost:4000`, a login UI on `:4455` (not `:3000`, to dodge Next.js port clashes), and the Ory Console on `:4100`.
|
|
80
64
|
|
|
81
|
-
|
|
65
|
+
A built-in **Ory MCP server** rounds it out — OpenClaw can manage identities, projects, and permissions straight from chat.
|
|
82
66
|
|
|
83
|
-
|
|
67
|
+
So: ask OpenClaw *"add Ory login to this app"* and it scaffolds the pages, starts a local Ory, and wires them together.
|
|
84
68
|
|
|
85
69
|
## What you get
|
|
86
70
|
|
|
87
|
-
|
|
71
|
+
Out of the box, every tool OpenClaw runs produces a privacy-safe structured activity event in the unified local log.
|
|
72
|
+
|
|
73
|
+
Once you connect to Ory Agent Security, two more things happen automatically:
|
|
88
74
|
|
|
89
|
-
- **Who's driving.** You sign in once in your browser;
|
|
90
|
-
- **What it's allowed to do.** Before a tool runs, Ory checks whether it's permitted. It starts in **
|
|
91
|
-
- **A record of everything.** Every decision (allowed, denied, skipped) is logged as a trace you can send to Jaeger, Honeycomb, Grafana, or just a file.
|
|
75
|
+
- **Who's driving.** You sign in once in your browser; each OpenClaw session and typed sub-agent gets its own identity, registered automatically on first use. No tokens to copy around, and the "who acted on whose behalf" trail stays queryable later.
|
|
76
|
+
- **What it's allowed to do.** Before a tool runs, Ory checks whether it's permitted. It starts in **observe mode** — nothing is blocked, you just *see* what would be — so it never gets in your way on day one.
|
|
92
77
|
|
|
93
78
|
If Ory is ever unreachable, the plugin gets out of the way and lets OpenClaw keep working — so it can't lock you out.
|
|
94
79
|
|
|
95
|
-
> **One nuance:** because the plugin runs inside OpenClaw's own process, it can't hard-block at the moment a session opens. Browser sign-in still runs there and the record stays correct — but the session always proceeds. Per-tool checks are unaffected: when a tool is about to run, a denial blocks it for real.
|
|
80
|
+
> **One nuance:** because the plugin runs inside OpenClaw's own process, it can't hard-block at the moment a session opens. Browser sign-in still runs there and the record stays correct — but the session always proceeds. Per-tool checks are unaffected: when a tool is about to run, a denial blocks it for real (the plugin returns `{ block: true }`).
|
|
96
81
|
|
|
97
82
|
### See what's happening
|
|
98
83
|
|
|
99
|
-
Everything the plugin does is observable out of the box
|
|
84
|
+
Everything the plugin does is observable out of the box:
|
|
100
85
|
|
|
101
|
-
- **
|
|
102
|
-
- **Live traces.** Every tool call is recorded as an OpenTelemetry-style span. Watch them stream as the agent works:
|
|
86
|
+
- **Activity log.** Privacy-safe activity is always appended to `~/.config/ory-agent-plugins/openclaw/ory-agent-debug.log`. View events, decisions, and errors live with:
|
|
103
87
|
|
|
104
88
|
```bash
|
|
105
89
|
npx -y -p @ory/openclaw ory-openclaw watch
|
|
106
90
|
```
|
|
107
91
|
|
|
108
|
-
|
|
109
|
-
- **
|
|
92
|
+
Set `ORY_AGENT_LOG_FILE` to override the path; set it empty to disable file persistence.
|
|
93
|
+
- **Live debug.** Launch OpenClaw with `ORY_AGENT_DEBUG=true` to add verbose local diagnostics, including raw shell commands, to the watched log and stderr. Secrets are recursively redacted; pass `watch --json` for NDJSON.
|
|
110
94
|
|
|
111
95
|
### Ready to enforce?
|
|
112
96
|
|
|
113
|
-
|
|
97
|
+
Once connected, the deny posture lives on the Ory project: when the observe-mode activity looks right, an admin promotes it to **enforce** in the **Ory Console** (Agent Security). Every session reads that posture live, so nothing has to be reinstalled.
|
|
114
98
|
|
|
115
99
|
```bash
|
|
116
|
-
npx -y -p @ory/openclaw ory-openclaw permissions
|
|
100
|
+
npx -y -p @ory/openclaw ory-openclaw permissions # what the project grants, and the live mode
|
|
117
101
|
```
|
|
118
102
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
## Also: add login to your own app
|
|
103
|
+
Then a denied tool is actually blocked and OpenClaw shows why.
|
|
122
104
|
|
|
123
|
-
|
|
105
|
+
## Connect to Ory Agent Security
|
|
124
106
|
|
|
125
|
-
|
|
107
|
+
Copy the connection details from the [Ory Console](https://console.ory.sh) under **Agent Security**:
|
|
126
108
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
109
|
+
| Value | Flag | Environment variable |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| Project URL | `--project-url` | `ORY_PROJECT_URL` |
|
|
112
|
+
| Agent Security URL | `--agent-security-url` | `ORY_AGENT_SECURITY_URL` |
|
|
113
|
+
| Sign-in client id override (default `ory-agent-security-login`) | `--oauth2-client-id` | `ORY_OAUTH2_CLIENT_ID` |
|
|
130
114
|
|
|
131
115
|
```bash
|
|
132
116
|
npx -y -p @ory/openclaw ory-openclaw configure \
|
|
133
117
|
--project-url https://<slug>.projects.oryapis.com \
|
|
134
|
-
--
|
|
135
|
-
--user-login
|
|
118
|
+
--agent-security-url https://agents.console.ory.com
|
|
136
119
|
```
|
|
137
120
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
<details>
|
|
141
|
-
<summary>Create the sign-in client by hand</summary>
|
|
142
|
-
|
|
143
|
-
The guided setup normally does this. To do it yourself, create a **public** OAuth2 client (no secret) listing all four loopback URLs — the plugin tries each in turn so sign-in survives a busy port:
|
|
121
|
+
`install` accepts the same flags, so you can register the plugin **and** connect in one shot (`install --project-url <URL> --agent-security-url <URL>`). The login client defaults to `ory-agent-security-login`; custom deployments can override it with `--oauth2-client-id`. Existing configurations fall back to the project URL when the Agent Security URL is unset. To turn sign-in and checks back off later, use `configure --disconnect`.
|
|
144
122
|
|
|
145
|
-
|
|
146
|
-
ory create oauth2-client --project <project-id> \
|
|
147
|
-
--name "ory-agent-plugin" \
|
|
148
|
-
--grant-type authorization_code,refresh_token \
|
|
149
|
-
--response-type code \
|
|
150
|
-
--scope openid,offline_access \
|
|
151
|
-
--token-endpoint-auth-method none \
|
|
152
|
-
--redirect-uri http://127.0.0.1:47823/callback \
|
|
153
|
-
--redirect-uri http://127.0.0.1:47824/callback \
|
|
154
|
-
--redirect-uri http://127.0.0.1:47825/callback \
|
|
155
|
-
--redirect-uri http://127.0.0.1:47826/callback
|
|
156
|
-
```
|
|
123
|
+
**Ory Network or OEL.** Either works. For an Ory Network project the URL is `https://<slug>.projects.oryapis.com`; for a self-hosted **Ory Enterprise License** deployment, point `--project-url` at that deployment's base URL and use the sign-in client id from its Agent Security configuration. Everything downstream — sign-in, checks, delegation — is identical.
|
|
157
124
|
|
|
158
|
-
|
|
125
|
+
**There is nothing else for you to create.** The sign-in client, the permission model, the per-tool grants and blocks, and the observe/enforce posture are all provisioned in the Console by someone with project access. At runtime the plugin only *reads* permissions — it has no write path into your project, which is why installing it needs no workspace privilege. Each OpenClaw session registers its own identity automatically on first use.
|
|
159
126
|
|
|
160
|
-
|
|
127
|
+
Sign-in runs at the start of every session and never blocks — a declined, skipped, or timed-out login simply leaves that session without a user identity.
|
|
161
128
|
|
|
162
|
-
|
|
129
|
+
Settings are saved to `~/.config/ory-agent-plugins/config.json` and shared across all your Ory agent plugins; environment variables win when both are set. Running headless with an OAuth2 access token already? Set `ORY_USER_OAUTH2_TOKEN` and the browser step is skipped entirely.
|
|
163
130
|
|
|
164
131
|
## Commands
|
|
165
132
|
|
|
166
133
|
```
|
|
167
|
-
ory-openclaw install | uninstall
|
|
134
|
+
ory-openclaw install | uninstall Install (add --project-url to also connect Agent Security) / remove; --project-dir <path> targets another project
|
|
168
135
|
ory-openclaw status Show configuration, identities, permission coverage, recent activity
|
|
169
|
-
ory-openclaw
|
|
170
|
-
ory-openclaw
|
|
171
|
-
ory-openclaw configure <flags> Point at a project by hand (--project-url, --oauth2-client-id, --user-login, --audit-only)
|
|
136
|
+
ory-openclaw permissions <cmd> status (read-only; grants + posture live in the Ory Console)
|
|
137
|
+
ory-openclaw configure <flags> Connect a project (--project-url) or --disconnect
|
|
172
138
|
ory-openclaw agent <status|unregister> Manage OpenClaw's own auto-created identity
|
|
173
139
|
ory-openclaw local <up|down|status|…> Run / manage a local Ory in Docker
|
|
174
|
-
ory-openclaw
|
|
140
|
+
ory-openclaw version Print plugin, core, and Node versions (--json for machine-readable)
|
|
175
141
|
```
|
|
176
142
|
|
|
177
143
|
All prefixed with `npx -y -p @ory/openclaw`.
|
|
@@ -179,9 +145,8 @@ All prefixed with `npx -y -p @ory/openclaw`.
|
|
|
179
145
|
## Troubleshooting
|
|
180
146
|
|
|
181
147
|
- **`local-up` fails** — make sure Docker is running and ports `4000`, `4100`, `4455`, and `16686` are free.
|
|
182
|
-
- **Browser sign-in loops** — reset with `ory-openclaw agent unregister` and try again.
|
|
183
|
-
- **
|
|
184
|
-
- **Want to see what's happening** — `npx -y -p @ory/openclaw ory-openclaw status` for a snapshot, `npx -y -p @ory/openclaw ory-openclaw watch` for the live trace stream, or set `ORY_AGENT_DEBUG=true` for a verbose log. Traces and logs live under `~/.config/ory-agent-plugins/openclaw/` (see [See what's happening](#see-whats-happening)).
|
|
148
|
+
- **Browser sign-in loops** (after connecting) — reset with `ory-openclaw agent unregister` and try again.
|
|
149
|
+
- **Running an older CLI than expected** — `npx -p @ory/openclaw` (no version pin) reuses a previously-downloaded copy instead of re-resolving to the latest. The install banner prints the running version; confirm it with `npx -y -p @ory/openclaw ory-openclaw version`. To force the current release, clear the cache and reinstall: `rm -rf ~/.npm/_npx` then `npx -y -p @ory/openclaw ory-openclaw install`. Pinning an exact version (`@ory/openclaw@<version>`) also bypasses the cached copy.
|
|
185
150
|
|
|
186
151
|
## Learn more
|
|
187
152
|
|
package/dist/cli/main.d.ts
CHANGED
package/dist/cli/main.js
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* npx ory-openclaw uninstall Remove plugin from OpenClaw config
|
|
9
9
|
* npx ory-openclaw configure Set or view Ory project URL and API key
|
|
10
10
|
* npx ory-openclaw status Show plugin status
|
|
11
|
-
* npx ory-openclaw watch [trace-file] Watch live trace output
|
|
12
11
|
*/
|
|
13
12
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
13
|
if (k2 === undefined) k2 = k;
|
|
@@ -53,8 +52,18 @@ const CONFIG_DIR = ".openclaw";
|
|
|
53
52
|
const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
|
|
54
53
|
function main() {
|
|
55
54
|
const [command, ...args] = process.argv.slice(2);
|
|
55
|
+
// `--help` after a matched subcommand: print usage, do nothing else.
|
|
56
|
+
// Without this the switch below ignores the flag and `install --help`
|
|
57
|
+
// performs a real install (#221).
|
|
58
|
+
if ((0, argus_1.shouldPrintHelp)(command, args))
|
|
59
|
+
return help();
|
|
56
60
|
switch (command) {
|
|
57
61
|
case "install":
|
|
62
|
+
if (args.includes("--print")) {
|
|
63
|
+
process.argv = ["node", "setup.js", ...args];
|
|
64
|
+
require("./setup.js");
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
58
67
|
(0, argus_1.beginDeferNextSteps)();
|
|
59
68
|
install(args);
|
|
60
69
|
(0, argus_1.runPostInstall)("ory-openclaw", "openclaw", args).then(() => process.exit(0), (err) => {
|
|
@@ -64,7 +73,10 @@ function main() {
|
|
|
64
73
|
break;
|
|
65
74
|
case "uninstall":
|
|
66
75
|
uninstall(args);
|
|
67
|
-
(0, argus_1.clearCredentialsForUninstall)(
|
|
76
|
+
(0, argus_1.clearCredentialsForUninstall)({
|
|
77
|
+
harness: "openclaw",
|
|
78
|
+
purge: args.includes("--purge"),
|
|
79
|
+
}).then(() => process.exit(0), (err) => {
|
|
68
80
|
console.error(err.message ?? err);
|
|
69
81
|
process.exit(1);
|
|
70
82
|
});
|
|
@@ -73,7 +85,7 @@ function main() {
|
|
|
73
85
|
(0, argus_1.runConfigureCommand)("ory-openclaw", args);
|
|
74
86
|
break;
|
|
75
87
|
case "agent":
|
|
76
|
-
(0, argus_1.runAgentCommand)("ory-openclaw", args).then((code) => process.exit(code), (err) => {
|
|
88
|
+
(0, argus_1.runAgentCommand)("ory-openclaw", "openclaw", args).then((code) => process.exit(code), (err) => {
|
|
77
89
|
console.error(err.message ?? err);
|
|
78
90
|
process.exit(1);
|
|
79
91
|
});
|
|
@@ -90,15 +102,15 @@ function main() {
|
|
|
90
102
|
process.exit(1);
|
|
91
103
|
});
|
|
92
104
|
break;
|
|
105
|
+
case "watch":
|
|
106
|
+
(0, argus_1.runWatchCommand)("ory-openclaw", "openclaw", args).then((code) => process.exit(code), (err) => { console.error(err.message ?? err); process.exit(1); });
|
|
107
|
+
break;
|
|
93
108
|
case "local":
|
|
94
109
|
(0, argus_1.runLocalCommand)("ory-openclaw", args).catch((err) => {
|
|
95
110
|
console.error(err.message ?? err);
|
|
96
111
|
process.exit(1);
|
|
97
112
|
});
|
|
98
113
|
break;
|
|
99
|
-
case "watch":
|
|
100
|
-
(0, argus_1.runWatchCommand)("openclaw", args);
|
|
101
|
-
break;
|
|
102
114
|
case "version":
|
|
103
115
|
case "--version":
|
|
104
116
|
case "-v":
|
|
@@ -136,11 +148,33 @@ function install(args) {
|
|
|
136
148
|
const configPath = getOpenClawConfigPath(projectDir);
|
|
137
149
|
ensureConfigDir(projectDir);
|
|
138
150
|
const config = (0, argus_1.readJsonFile)(configPath);
|
|
139
|
-
|
|
151
|
+
// OpenClaw loads the plugin in-process from a directory on
|
|
152
|
+
// `plugins.load.paths`, so the runtime dir *is* the registration — there is
|
|
153
|
+
// no hook subprocess and no hook shim.
|
|
154
|
+
const runtime = (0, argus_1.wireRuntime)({
|
|
155
|
+
harness: "openclaw",
|
|
156
|
+
packageName: "@ory/openclaw",
|
|
157
|
+
packageRoot: PACKAGE_ROOT,
|
|
158
|
+
installCommand: "npx -y -p @ory/openclaw ory-openclaw install",
|
|
159
|
+
args,
|
|
160
|
+
entryRelPath: "dist/index.js",
|
|
161
|
+
inProcess: true,
|
|
162
|
+
});
|
|
163
|
+
console.log(runtime.target.kind === "linked"
|
|
164
|
+
? `Runtime: linked to ${runtime.target.packageDir} (dev)`
|
|
165
|
+
: `Runtime: ${runtime.target.packageName}@${runtime.target.version} in ${runtime.target.storeDir}`);
|
|
166
|
+
for (const pruned of runtime.prunedStores) {
|
|
167
|
+
console.log(` Removed stale runtime: ${pruned}`);
|
|
168
|
+
}
|
|
169
|
+
let merged = (0, plugin_config_js_1.registerPluginInConfig)(config, runtime.target.packageDir);
|
|
170
|
+
if (runtime.mcpServer) {
|
|
171
|
+
merged = (0, argus_1.mergeMcpServer)(merged, runtime.mcpServer);
|
|
172
|
+
}
|
|
140
173
|
fs.writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n");
|
|
141
174
|
(0, assets_js_1.installOpenclawOryAssets)(projectDir);
|
|
142
175
|
console.log(`Ory plugin registered in ${configPath}`);
|
|
143
176
|
console.log(` Plugin id: ${plugin_config_js_1.PLUGIN_ID}`);
|
|
177
|
+
console.log(` Loads from: ${runtime.target.packageDir}`);
|
|
144
178
|
console.log(` Skills + commands installed under ${path.join(projectDir, CONFIG_DIR, "skills")}`);
|
|
145
179
|
(0, argus_1.printEnvHelp)("ory-openclaw");
|
|
146
180
|
}
|
|
@@ -153,9 +187,14 @@ function uninstall(args) {
|
|
|
153
187
|
}
|
|
154
188
|
(0, assets_js_1.uninstallOpenclawOryAssets)(projectDir);
|
|
155
189
|
const config = (0, argus_1.readJsonFile)(configPath);
|
|
156
|
-
|
|
190
|
+
let updated = (0, plugin_config_js_1.unregisterPluginFromConfig)(config);
|
|
191
|
+
updated = (0, argus_1.removeMcpServer)(updated);
|
|
157
192
|
fs.writeFileSync(configPath, JSON.stringify(updated, null, 2) + "\n");
|
|
158
193
|
console.log(`Ory plugin and skills removed from ${configPath}`);
|
|
194
|
+
(0, argus_1.removeRuntimeWiring)("openclaw");
|
|
195
|
+
for (const pruned of (0, argus_1.pruneRuntimeStores)()) {
|
|
196
|
+
console.log(` Removed runtime: ${pruned}`);
|
|
197
|
+
}
|
|
159
198
|
}
|
|
160
199
|
async function status(args) {
|
|
161
200
|
const projectDir = parseProjectDir(args);
|
|
@@ -188,22 +227,21 @@ Commands:
|
|
|
188
227
|
uninstall [--project-dir <path>] Remove the Ory plugin from OpenClaw config
|
|
189
228
|
configure Set or view Ory project URL and API key
|
|
190
229
|
agent <cmd> Manage the agent's OAuth2 (DCR) identity (status, unregister)
|
|
191
|
-
permissions
|
|
230
|
+
permissions Show the live permission mode and per-tool coverage
|
|
192
231
|
status [--project-dir <path>] Show plugin configuration and status
|
|
193
|
-
watch [
|
|
232
|
+
watch [--json] [--lines <count>] Follow the live activity/debug log
|
|
194
233
|
version Show version and the ory-agent-plugins build commit
|
|
195
234
|
local <cmd> Manage local Ory dev environment (up, down, status, seed, ...)
|
|
196
235
|
|
|
197
236
|
After installing, the plugin hooks into these OpenClaw lifecycle events:
|
|
198
237
|
session_start Verify agent session via Ory Identities
|
|
199
238
|
before_tool_call Check tool permissions via Ory Permissions (can block)
|
|
200
|
-
after_tool_call Record tool completion
|
|
239
|
+
after_tool_call Record tool completion activity
|
|
201
240
|
|
|
202
241
|
Examples:
|
|
203
242
|
npx -y -p @ory/openclaw ory-openclaw install # Register in current directory
|
|
204
|
-
npx -y -p @ory/openclaw ory-openclaw configure --project-url https://my.oryapis.com --
|
|
243
|
+
npx -y -p @ory/openclaw ory-openclaw configure --project-url https://my.oryapis.com --agent-security-url https://agents.console.ory.com
|
|
205
244
|
npx -y -p @ory/openclaw ory-openclaw status # Check configuration
|
|
206
|
-
npx -y -p @ory/openclaw ory-openclaw watch # Watch trace output in real-time
|
|
207
245
|
npx -y -p @ory/openclaw ory-openclaw uninstall # Remove plugin
|
|
208
246
|
`);
|
|
209
247
|
}
|
|
@@ -30,23 +30,27 @@ type Rec = Record<string, unknown>;
|
|
|
30
30
|
* Resolve the directory that contains the plugin's `openclaw.plugin.json`
|
|
31
31
|
* manifest, so it can be registered on `plugins.load.paths`.
|
|
32
32
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* `
|
|
33
|
+
* This is the runtime directory the install resolved: a materialized store
|
|
34
|
+
* under the shared data dir, or a linked workspace build. Both are stable
|
|
35
|
+
* across sessions, which the previous candidates were not — the project's
|
|
36
|
+
* `node_modules` disappears with a `rm -rf`, and the running CLI's own package
|
|
37
|
+
* root is npx's ephemeral cache under the documented `npx -p @ory/openclaw`
|
|
38
|
+
* invocation.
|
|
39
|
+
*
|
|
40
|
+
* Falls back to the wiring recorded in the runtime manifest when no runtime is
|
|
41
|
+
* passed (the uninstall path, which must find the same path install wrote).
|
|
38
42
|
*/
|
|
39
|
-
export declare function resolvePluginRoot(
|
|
43
|
+
export declare function resolvePluginRoot(runtimeDir?: string): string;
|
|
40
44
|
/**
|
|
41
45
|
* Non-destructively register + enable the Ory plugin in an OpenClaw config
|
|
42
46
|
* object. Returns a new config; does not mutate the input.
|
|
43
47
|
*/
|
|
44
|
-
export declare function registerPluginInConfig(config: Rec,
|
|
48
|
+
export declare function registerPluginInConfig(config: Rec, runtimeDir?: string): Rec;
|
|
45
49
|
/**
|
|
46
50
|
* Non-destructively remove the Ory plugin from an OpenClaw config object,
|
|
47
51
|
* leaving any other plugins' config intact. Returns a new config.
|
|
48
52
|
*/
|
|
49
|
-
export declare function unregisterPluginFromConfig(config: Rec,
|
|
53
|
+
export declare function unregisterPluginFromConfig(config: Rec, runtimeDir?: string): Rec;
|
|
50
54
|
/** True when the plugin is enabled under the current nested schema. */
|
|
51
55
|
export declare function isPluginRegistered(config: Rec): boolean;
|
|
52
56
|
export {};
|
|
@@ -61,8 +61,8 @@ exports.resolvePluginRoot = resolvePluginRoot;
|
|
|
61
61
|
exports.registerPluginInConfig = registerPluginInConfig;
|
|
62
62
|
exports.unregisterPluginFromConfig = unregisterPluginFromConfig;
|
|
63
63
|
exports.isPluginRegistered = isPluginRegistered;
|
|
64
|
-
const fs = __importStar(require("node:fs"));
|
|
65
64
|
const path = __importStar(require("node:path"));
|
|
65
|
+
const argus_1 = require("@ory/argus");
|
|
66
66
|
/** Plugin manifest id (from `openclaw.plugin.json`). */
|
|
67
67
|
exports.PLUGIN_ID = "ory-agent-security";
|
|
68
68
|
/** npm module name — used only to migrate away the legacy flat-array shape. */
|
|
@@ -77,30 +77,36 @@ function asRec(value) {
|
|
|
77
77
|
* Resolve the directory that contains the plugin's `openclaw.plugin.json`
|
|
78
78
|
* manifest, so it can be registered on `plugins.load.paths`.
|
|
79
79
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* `
|
|
80
|
+
* This is the runtime directory the install resolved: a materialized store
|
|
81
|
+
* under the shared data dir, or a linked workspace build. Both are stable
|
|
82
|
+
* across sessions, which the previous candidates were not — the project's
|
|
83
|
+
* `node_modules` disappears with a `rm -rf`, and the running CLI's own package
|
|
84
|
+
* root is npx's ephemeral cache under the documented `npx -p @ory/openclaw`
|
|
85
|
+
* invocation.
|
|
86
|
+
*
|
|
87
|
+
* Falls back to the wiring recorded in the runtime manifest when no runtime is
|
|
88
|
+
* passed (the uninstall path, which must find the same path install wrote).
|
|
85
89
|
*/
|
|
86
|
-
function resolvePluginRoot(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
function resolvePluginRoot(runtimeDir) {
|
|
91
|
+
if (runtimeDir)
|
|
92
|
+
return path.resolve(runtimeDir);
|
|
93
|
+
const wired = (0, argus_1.getRuntimeWiring)("openclaw");
|
|
94
|
+
if (wired)
|
|
95
|
+
return path.resolve(wired.packageDir);
|
|
96
|
+
// Nothing wired (uninstall before install, or a manifest that was wiped):
|
|
97
|
+
// fall back to the running CLI so an existing registration still matches.
|
|
92
98
|
return path.resolve(__dirname, "..", "..");
|
|
93
99
|
}
|
|
94
100
|
/**
|
|
95
101
|
* Non-destructively register + enable the Ory plugin in an OpenClaw config
|
|
96
102
|
* object. Returns a new config; does not mutate the input.
|
|
97
103
|
*/
|
|
98
|
-
function registerPluginInConfig(config,
|
|
104
|
+
function registerPluginInConfig(config, runtimeDir) {
|
|
99
105
|
const next = { ...config };
|
|
100
106
|
// asRec drops any legacy flat `plugins: [...]` array — that shape was never
|
|
101
107
|
// read by current OpenClaw, so nothing functional is lost by migrating it.
|
|
102
108
|
const plugins = asRec(next.plugins);
|
|
103
|
-
const root = resolvePluginRoot(
|
|
109
|
+
const root = resolvePluginRoot(runtimeDir);
|
|
104
110
|
// 1. Discovery — add the package dir to plugins.load.paths (deduped).
|
|
105
111
|
const load = asRec(plugins.load);
|
|
106
112
|
const paths = Array.isArray(load.paths)
|
|
@@ -129,7 +135,7 @@ function registerPluginInConfig(config, projectDir) {
|
|
|
129
135
|
* Non-destructively remove the Ory plugin from an OpenClaw config object,
|
|
130
136
|
* leaving any other plugins' config intact. Returns a new config.
|
|
131
137
|
*/
|
|
132
|
-
function unregisterPluginFromConfig(config,
|
|
138
|
+
function unregisterPluginFromConfig(config, runtimeDir) {
|
|
133
139
|
const next = { ...config };
|
|
134
140
|
if (next.plugins == null)
|
|
135
141
|
return next;
|
|
@@ -143,7 +149,7 @@ function unregisterPluginFromConfig(config, projectDir) {
|
|
|
143
149
|
return next;
|
|
144
150
|
}
|
|
145
151
|
const plugins = asRec(next.plugins);
|
|
146
|
-
const root = resolvePluginRoot(
|
|
152
|
+
const root = resolvePluginRoot(runtimeDir);
|
|
147
153
|
// Remove our load path.
|
|
148
154
|
const load = asRec(plugins.load);
|
|
149
155
|
if (Array.isArray(load.paths)) {
|
package/dist/cli/setup.js
CHANGED
|
@@ -65,7 +65,8 @@ function main() {
|
|
|
65
65
|
}
|
|
66
66
|
const args = (0, argus_1.parseSetupArgs)();
|
|
67
67
|
if (args.print) {
|
|
68
|
-
|
|
68
|
+
// Nothing is resolved or written on a --print run.
|
|
69
|
+
console.log(JSON.stringify((0, plugin_config_js_1.registerPluginInConfig)({}, "<resolved runtime>"), null, 2));
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
71
72
|
const configPath = getConfigPath(args);
|
|
@@ -76,15 +77,30 @@ function main() {
|
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
79
|
(0, assets_js_1.uninstallOpenclawOryAssets)(args.projectDir);
|
|
79
|
-
let updated = (0, plugin_config_js_1.unregisterPluginFromConfig)(existing
|
|
80
|
+
let updated = (0, plugin_config_js_1.unregisterPluginFromConfig)(existing);
|
|
80
81
|
updated = (0, argus_1.removeMcpServer)(updated);
|
|
81
82
|
(0, argus_1.writeJsonFile)(configPath, updated);
|
|
82
83
|
console.log(`Removed Ory plugin, MCP server, and skills from ${configPath}`);
|
|
84
|
+
(0, argus_1.removeRuntimeWiring)("openclaw");
|
|
85
|
+
for (const pruned of (0, argus_1.pruneRuntimeStores)()) {
|
|
86
|
+
console.log(` Removed runtime: ${pruned}`);
|
|
87
|
+
}
|
|
83
88
|
return;
|
|
84
89
|
}
|
|
85
90
|
ensureConfigDir(args);
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
const runtime = (0, argus_1.wireRuntime)({
|
|
92
|
+
harness: "openclaw",
|
|
93
|
+
packageName: "@ory/openclaw",
|
|
94
|
+
packageRoot: path.resolve(__dirname, "..", ".."),
|
|
95
|
+
installCommand: "npx -y -p @ory/openclaw ory-openclaw install",
|
|
96
|
+
args: process.argv.slice(2),
|
|
97
|
+
entryRelPath: "dist/index.js",
|
|
98
|
+
inProcess: true,
|
|
99
|
+
});
|
|
100
|
+
let merged = (0, plugin_config_js_1.registerPluginInConfig)(existing, runtime.target.packageDir);
|
|
101
|
+
if (runtime.mcpServer) {
|
|
102
|
+
merged = (0, argus_1.mergeMcpServer)(merged, runtime.mcpServer);
|
|
103
|
+
}
|
|
88
104
|
(0, argus_1.writeJsonFile)(configPath, merged);
|
|
89
105
|
(0, assets_js_1.installOpenclawOryAssets)(args.projectDir);
|
|
90
106
|
console.log(`Ory plugin and MCP server configured in ${configPath}`);
|
|
@@ -99,7 +115,10 @@ main();
|
|
|
99
115
|
// stored Ory credentials. When required by the plugin's main CLI, that
|
|
100
116
|
// command owns the purge, so the `require.main` guard prevents a double run.
|
|
101
117
|
if (require.main === module && process.argv.includes("--uninstall")) {
|
|
102
|
-
(0, argus_1.clearCredentialsForUninstall)(
|
|
118
|
+
(0, argus_1.clearCredentialsForUninstall)({
|
|
119
|
+
harness: "openclaw",
|
|
120
|
+
purge: process.argv.includes("--purge"),
|
|
121
|
+
}).then(() => process.exit(0), (err) => {
|
|
103
122
|
console.error(err.message ?? err);
|
|
104
123
|
process.exit(1);
|
|
105
124
|
});
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,28 +1,10 @@
|
|
|
1
|
-
import { OryAgentClient,
|
|
1
|
+
import { OryAgentClient, ensureAgentIdentity, ensureSubAgentIdentity, ensureUserAuthenticated } from "@ory/argus";
|
|
2
2
|
import type { OpenClawPluginEntry } from "./types.js";
|
|
3
3
|
export interface CreateOryPluginDeps {
|
|
4
|
-
/** Test injection point for the user login flow. */
|
|
5
4
|
userLogin?: typeof ensureUserAuthenticated;
|
|
6
|
-
/** Test injection point for the agent identity gate. */
|
|
7
5
|
agentGate?: typeof ensureAgentIdentity;
|
|
8
|
-
/** Test injection point for the sub-agent identity resolver. */
|
|
9
6
|
subAgentGate?: typeof ensureSubAgentIdentity;
|
|
10
7
|
}
|
|
11
|
-
/**
|
|
12
|
-
* Create the Ory plugin entry for OpenClaw.
|
|
13
|
-
*
|
|
14
|
-
* OpenClaw plugins export { id, name, register(api) } where register
|
|
15
|
-
* receives a PluginApi for registering hooks. The `before_tool_call`
|
|
16
|
-
* hook can return `{ block: true }` to deny tool execution — this
|
|
17
|
-
* makes permission checks enforceable, unlike harnesses that can only
|
|
18
|
-
* log denials.
|
|
19
|
-
*
|
|
20
|
-
* The `session_start` hook returns `Promise<void>` so user login is
|
|
21
|
-
* advisory at session start: the flow still runs to emit the audit span,
|
|
22
|
-
* refresh tokens, and prompt for the project URL when interactive, but
|
|
23
|
-
* cannot hard-block the session.
|
|
24
|
-
*/
|
|
25
8
|
export declare function createOryPlugin(clientOrConfig?: OryAgentClient | {
|
|
26
9
|
projectUrl: string;
|
|
27
|
-
apiKey?: string;
|
|
28
10
|
}, deps?: CreateOryPluginDeps): OpenClawPluginEntry;
|