@ory/openclaw 0.14.0 → 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 -105
- package/dist/cli/main.d.ts +0 -1
- package/dist/cli/main.js +51 -20
- 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 -18
- package/dist/plugin.js +128 -303
- 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,166 +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
|
-
|
|
55
|
-
|
|
56
|
-
- **Ory Network** *(default)* — sign in, or create a free account, in your browser. The project, keys, permissions, and login are all set up for you. Nothing to configure by hand.
|
|
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.
|
|
59
|
-
|
|
60
|
-
> No browser available (CI, SSH, headless)? The same walkthrough runs right in your terminal instead — or force it with `--no-web`.
|
|
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.
|
|
61
35
|
|
|
62
|
-
|
|
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>`.
|
|
63
37
|
|
|
64
|
-
|
|
65
|
-
npx -y -p @ory/openclaw ory-openclaw status
|
|
66
|
-
```
|
|
38
|
+
## Skills and commands
|
|
67
39
|
|
|
68
|
-
|
|
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.
|
|
69
41
|
|
|
70
|
-
|
|
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 |
|
|
71
54
|
|
|
72
|
-
|
|
73
|
-
<summary>Register the plugin by hand</summary>
|
|
55
|
+
The local stack has its own playbooks — ask for them by name:
|
|
74
56
|
|
|
75
|
-
|
|
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 |
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
npx @ory/openclaw install # registers in .openclaw/config.json
|
|
79
|
-
npx @ory/openclaw install --project-dir <path>
|
|
80
|
-
npx @ory/openclaw uninstall
|
|
81
|
-
```
|
|
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`.
|
|
82
64
|
|
|
83
|
-
|
|
65
|
+
A built-in **Ory MCP server** rounds it out — OpenClaw can manage identities, projects, and permissions straight from chat.
|
|
84
66
|
|
|
85
|
-
|
|
67
|
+
So: ask OpenClaw *"add Ory login to this app"* and it scaffolds the pages, starts a local Ory, and wires them together.
|
|
86
68
|
|
|
87
69
|
## What you get
|
|
88
70
|
|
|
89
|
-
|
|
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:
|
|
90
74
|
|
|
91
|
-
- **Who's driving.** You sign in once in your browser;
|
|
92
|
-
- **What it's allowed to do.** Before a tool runs, Ory checks whether it's permitted. It starts in **
|
|
93
|
-
- **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.
|
|
94
77
|
|
|
95
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.
|
|
96
79
|
|
|
97
|
-
> **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 }`).
|
|
98
81
|
|
|
99
82
|
### See what's happening
|
|
100
83
|
|
|
101
|
-
Everything the plugin does is observable out of the box
|
|
84
|
+
Everything the plugin does is observable out of the box:
|
|
102
85
|
|
|
103
|
-
- **
|
|
104
|
-
- **Live dashboard.** `npx -y -p @ory/openclaw ory-openclaw dashboard` opens the same picture in your browser — configuration, identities, permission coverage, Ory service health, and the latest tool-call activity, all refreshing live. From there you can flip **enforcement** on or off, toggle **user login**, and use **Change stack** to reconnect to a different Ory — no CLI required.
|
|
105
|
-
- **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:
|
|
106
87
|
|
|
107
88
|
```bash
|
|
108
89
|
npx -y -p @ory/openclaw ory-openclaw watch
|
|
109
90
|
```
|
|
110
91
|
|
|
111
|
-
|
|
112
|
-
- **
|
|
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.
|
|
113
94
|
|
|
114
95
|
### Ready to enforce?
|
|
115
96
|
|
|
116
|
-
|
|
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.
|
|
117
98
|
|
|
118
99
|
```bash
|
|
119
|
-
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
|
|
120
101
|
```
|
|
121
102
|
|
|
122
|
-
|
|
103
|
+
Then a denied tool is actually blocked and OpenClaw shows why.
|
|
123
104
|
|
|
124
|
-
##
|
|
105
|
+
## Connect to Ory Agent Security
|
|
125
106
|
|
|
126
|
-
|
|
107
|
+
Copy the connection details from the [Ory Console](https://console.ory.sh) under **Agent Security**:
|
|
127
108
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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` |
|
|
133
114
|
|
|
134
115
|
```bash
|
|
135
116
|
npx -y -p @ory/openclaw ory-openclaw configure \
|
|
136
117
|
--project-url https://<slug>.projects.oryapis.com \
|
|
137
|
-
--
|
|
118
|
+
--agent-security-url https://agents.console.ory.com
|
|
138
119
|
```
|
|
139
120
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
<details>
|
|
143
|
-
<summary>Create the sign-in client by hand</summary>
|
|
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
|
-
|
|
147
|
-
```bash
|
|
148
|
-
ory create oauth2-client --project <project-id> \
|
|
149
|
-
--name "Ory Agent Security · user login (PKCE)" \
|
|
150
|
-
--grant-type authorization_code,refresh_token \
|
|
151
|
-
--response-type code \
|
|
152
|
-
--scope openid,offline_access \
|
|
153
|
-
--token-endpoint-auth-method none \
|
|
154
|
-
--redirect-uri http://127.0.0.1:47823/callback \
|
|
155
|
-
--redirect-uri http://127.0.0.1:47824/callback \
|
|
156
|
-
--redirect-uri http://127.0.0.1:47825/callback \
|
|
157
|
-
--redirect-uri http://127.0.0.1:47826/callback
|
|
158
|
-
```
|
|
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.
|
|
159
124
|
|
|
160
|
-
|
|
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.
|
|
161
126
|
|
|
162
|
-
|
|
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.
|
|
163
128
|
|
|
164
|
-
|
|
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.
|
|
165
130
|
|
|
166
131
|
## Commands
|
|
167
132
|
|
|
168
133
|
```
|
|
169
|
-
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
|
|
170
135
|
ory-openclaw status Show configuration, identities, permission coverage, recent activity
|
|
171
|
-
ory-openclaw
|
|
172
|
-
ory-openclaw
|
|
173
|
-
ory-openclaw permissions <cmd> status | bootstrap | observe (watch) | enforce (block)
|
|
174
|
-
ory-openclaw configure <flags> Point at a project by hand (--project-url, --oauth2-client-id, --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
|
|
175
138
|
ory-openclaw agent <status|unregister> Manage OpenClaw's own auto-created identity
|
|
176
139
|
ory-openclaw local <up|down|status|…> Run / manage a local Ory in Docker
|
|
177
|
-
ory-openclaw
|
|
140
|
+
ory-openclaw version Print plugin, core, and Node versions (--json for machine-readable)
|
|
178
141
|
```
|
|
179
142
|
|
|
180
143
|
All prefixed with `npx -y -p @ory/openclaw`.
|
|
@@ -182,9 +145,8 @@ All prefixed with `npx -y -p @ory/openclaw`.
|
|
|
182
145
|
## Troubleshooting
|
|
183
146
|
|
|
184
147
|
- **`local-up` fails** — make sure Docker is running and ports `4000`, `4100`, `4455`, and `16686` are free.
|
|
185
|
-
- **Browser sign-in loops** — reset with `ory-openclaw agent unregister` and try again.
|
|
186
|
-
- **
|
|
187
|
-
- **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.
|
|
188
150
|
|
|
189
151
|
## Learn more
|
|
190
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,17 +102,11 @@ function main() {
|
|
|
90
102
|
process.exit(1);
|
|
91
103
|
});
|
|
92
104
|
break;
|
|
93
|
-
case "local":
|
|
94
|
-
(0, argus_1.runLocalCommand)("ory-openclaw", args).catch((err) => {
|
|
95
|
-
console.error(err.message ?? err);
|
|
96
|
-
process.exit(1);
|
|
97
|
-
});
|
|
98
|
-
break;
|
|
99
105
|
case "watch":
|
|
100
|
-
(0, argus_1.runWatchCommand)("openclaw", args);
|
|
106
|
+
(0, argus_1.runWatchCommand)("ory-openclaw", "openclaw", args).then((code) => process.exit(code), (err) => { console.error(err.message ?? err); process.exit(1); });
|
|
101
107
|
break;
|
|
102
|
-
case "
|
|
103
|
-
(0, argus_1.
|
|
108
|
+
case "local":
|
|
109
|
+
(0, argus_1.runLocalCommand)("ory-openclaw", args).catch((err) => {
|
|
104
110
|
console.error(err.message ?? err);
|
|
105
111
|
process.exit(1);
|
|
106
112
|
});
|
|
@@ -142,11 +148,33 @@ function install(args) {
|
|
|
142
148
|
const configPath = getOpenClawConfigPath(projectDir);
|
|
143
149
|
ensureConfigDir(projectDir);
|
|
144
150
|
const config = (0, argus_1.readJsonFile)(configPath);
|
|
145
|
-
|
|
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
|
+
}
|
|
146
173
|
fs.writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n");
|
|
147
174
|
(0, assets_js_1.installOpenclawOryAssets)(projectDir);
|
|
148
175
|
console.log(`Ory plugin registered in ${configPath}`);
|
|
149
176
|
console.log(` Plugin id: ${plugin_config_js_1.PLUGIN_ID}`);
|
|
177
|
+
console.log(` Loads from: ${runtime.target.packageDir}`);
|
|
150
178
|
console.log(` Skills + commands installed under ${path.join(projectDir, CONFIG_DIR, "skills")}`);
|
|
151
179
|
(0, argus_1.printEnvHelp)("ory-openclaw");
|
|
152
180
|
}
|
|
@@ -159,9 +187,14 @@ function uninstall(args) {
|
|
|
159
187
|
}
|
|
160
188
|
(0, assets_js_1.uninstallOpenclawOryAssets)(projectDir);
|
|
161
189
|
const config = (0, argus_1.readJsonFile)(configPath);
|
|
162
|
-
|
|
190
|
+
let updated = (0, plugin_config_js_1.unregisterPluginFromConfig)(config);
|
|
191
|
+
updated = (0, argus_1.removeMcpServer)(updated);
|
|
163
192
|
fs.writeFileSync(configPath, JSON.stringify(updated, null, 2) + "\n");
|
|
164
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
|
+
}
|
|
165
198
|
}
|
|
166
199
|
async function status(args) {
|
|
167
200
|
const projectDir = parseProjectDir(args);
|
|
@@ -194,23 +227,21 @@ Commands:
|
|
|
194
227
|
uninstall [--project-dir <path>] Remove the Ory plugin from OpenClaw config
|
|
195
228
|
configure Set or view Ory project URL and API key
|
|
196
229
|
agent <cmd> Manage the agent's OAuth2 (DCR) identity (status, unregister)
|
|
197
|
-
permissions
|
|
230
|
+
permissions Show the live permission mode and per-tool coverage
|
|
198
231
|
status [--project-dir <path>] Show plugin configuration and status
|
|
199
|
-
|
|
200
|
-
watch [trace-file] Watch live trace output
|
|
232
|
+
watch [--json] [--lines <count>] Follow the live activity/debug log
|
|
201
233
|
version Show version and the ory-agent-plugins build commit
|
|
202
234
|
local <cmd> Manage local Ory dev environment (up, down, status, seed, ...)
|
|
203
235
|
|
|
204
236
|
After installing, the plugin hooks into these OpenClaw lifecycle events:
|
|
205
237
|
session_start Verify agent session via Ory Identities
|
|
206
238
|
before_tool_call Check tool permissions via Ory Permissions (can block)
|
|
207
|
-
after_tool_call Record tool completion
|
|
239
|
+
after_tool_call Record tool completion activity
|
|
208
240
|
|
|
209
241
|
Examples:
|
|
210
242
|
npx -y -p @ory/openclaw ory-openclaw install # Register in current directory
|
|
211
|
-
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
|
|
212
244
|
npx -y -p @ory/openclaw ory-openclaw status # Check configuration
|
|
213
|
-
npx -y -p @ory/openclaw ory-openclaw watch # Watch trace output in real-time
|
|
214
245
|
npx -y -p @ory/openclaw ory-openclaw uninstall # Remove plugin
|
|
215
246
|
`);
|
|
216
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,27 +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 user login runs every session but never blocks: it emits the audit
|
|
21
|
-
* span, refreshes tokens, and prompts for the project URL when interactive.
|
|
22
|
-
* Enforcement is governed solely by permissionMode at tool-call time.
|
|
23
|
-
*/
|
|
24
8
|
export declare function createOryPlugin(clientOrConfig?: OryAgentClient | {
|
|
25
9
|
projectUrl: string;
|
|
26
|
-
apiKey?: string;
|
|
27
10
|
}, deps?: CreateOryPluginDeps): OpenClawPluginEntry;
|
package/dist/plugin.js
CHANGED
|
@@ -2,19 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createOryPlugin = createOryPlugin;
|
|
4
4
|
const argus_1 = require("@ory/argus");
|
|
5
|
-
|
|
6
|
-
* Create the Ory plugin entry for OpenClaw.
|
|
7
|
-
*
|
|
8
|
-
* OpenClaw plugins export { id, name, register(api) } where register
|
|
9
|
-
* receives a PluginApi for registering hooks. The `before_tool_call`
|
|
10
|
-
* hook can return `{ block: true }` to deny tool execution — this
|
|
11
|
-
* makes permission checks enforceable, unlike harnesses that can only
|
|
12
|
-
* log denials.
|
|
13
|
-
*
|
|
14
|
-
* The user login runs every session but never blocks: it emits the audit
|
|
15
|
-
* span, refreshes tokens, and prompts for the project URL when interactive.
|
|
16
|
-
* Enforcement is governed solely by permissionMode at tool-call time.
|
|
17
|
-
*/
|
|
5
|
+
const HARNESS = "openclaw";
|
|
18
6
|
function createOryPlugin(clientOrConfig, deps = {}) {
|
|
19
7
|
return {
|
|
20
8
|
id: "ory-agent-security",
|
|
@@ -23,195 +11,91 @@ function createOryPlugin(clientOrConfig, deps = {}) {
|
|
|
23
11
|
const client = clientOrConfig instanceof argus_1.OryAgentClient
|
|
24
12
|
? clientOrConfig
|
|
25
13
|
: clientOrConfig
|
|
26
|
-
? new argus_1.OryAgentClient({
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
api.registerHook("
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
api.registerHook("
|
|
14
|
+
? new argus_1.OryAgentClient({ ...clientOrConfig, harness: HARNESS })
|
|
15
|
+
: argus_1.OryAgentClient.fromEnv(HARNESS);
|
|
16
|
+
const subagents = new Map();
|
|
17
|
+
api.registerHook("session_start", createSessionStartHandler(client, deps), {
|
|
18
|
+
name: "ory.session-verify",
|
|
19
|
+
description: "Verify session via Ory Identities",
|
|
20
|
+
});
|
|
21
|
+
api.registerHook("before_agent_run", createBeforeAgentRunHandler(client, deps), {
|
|
22
|
+
name: "ory.user-login",
|
|
23
|
+
description: "Block runs when the user login denies",
|
|
24
|
+
});
|
|
25
|
+
api.registerHook("before_tool_call", createBeforeToolCallHandler(client, subagents), {
|
|
26
|
+
name: "ory.permission-check",
|
|
27
|
+
description: "Check tool permissions via Ory Permissions",
|
|
28
|
+
});
|
|
29
|
+
api.registerHook("after_tool_call", createAfterToolCallHandler(client), {
|
|
30
|
+
name: "ory.activity-complete",
|
|
31
|
+
description: "Record tool completion activity",
|
|
32
|
+
});
|
|
33
|
+
api.registerHook("subagent_spawning", createSubagentSpawningHandler(client, deps, subagents), {
|
|
34
|
+
name: "ory.subagent-register",
|
|
35
|
+
description: "Register Ory identity and write delegation tuple for spawned sub-agent",
|
|
36
|
+
});
|
|
37
|
+
api.registerHook("subagent_spawned", createSubagentSpawnedHandler(client), {
|
|
38
|
+
name: "ory.subagent-spawned",
|
|
39
|
+
description: "Record sub-agent spawn activity",
|
|
40
|
+
});
|
|
41
|
+
api.registerHook("subagent_ended", createSubagentEndedHandler(client, subagents), {
|
|
42
|
+
name: "ory.subagent-ended",
|
|
43
|
+
description: "Record sub-agent termination activity",
|
|
44
|
+
});
|
|
38
45
|
},
|
|
39
46
|
};
|
|
40
47
|
}
|
|
41
|
-
// ─── session_start ─────────────────────────────────────────────────
|
|
42
48
|
function createSessionStartHandler(client, deps) {
|
|
43
|
-
return async (
|
|
49
|
+
return (ctx) => (0, argus_1.withHookContext)(client, { sessionId: ctx.sessionId }, async () => {
|
|
44
50
|
client.logger.info("lifecycle.session_start", {
|
|
45
51
|
sessionId: ctx.sessionId,
|
|
46
52
|
model: ctx.model,
|
|
47
53
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
traceId: (0, argus_1.deriveTraceId)(ctx.sessionId),
|
|
51
|
-
sessionId: ctx.sessionId,
|
|
52
|
-
});
|
|
53
|
-
// Run the user login every session. Authentication is non-blocking:
|
|
54
|
-
// the flow emits the user.auth audit span, refreshes tokens, and
|
|
55
|
-
// prompts for the project URL when interactive, but never prevents the
|
|
56
|
-
// session from starting — enforcement is governed solely by
|
|
57
|
-
// permissionMode at tool-call time.
|
|
58
|
-
const userGate = deps.userLogin ?? argus_1.ensureUserAuthenticated;
|
|
59
|
-
await userGate(client, {
|
|
54
|
+
await (0, argus_1.sessionStart)(client, {
|
|
55
|
+
harness: HARNESS,
|
|
60
56
|
binName: "ory-openclaw",
|
|
61
|
-
|
|
57
|
+
userLogin: deps.userLogin,
|
|
58
|
+
agentGate: deps.agentGate,
|
|
59
|
+
activityAttributes: { model: ctx.model },
|
|
62
60
|
});
|
|
63
|
-
|
|
64
|
-
// attaches the agent's bearer token to outgoing Ory API calls.
|
|
65
|
-
const agentGate = deps.agentGate ?? argus_1.ensureAgentIdentity;
|
|
66
|
-
await agentGate(client, { projectUrl: (0, argus_1.resolveConfig)().projectUrl, harness: "openclaw" });
|
|
67
|
-
// Record the user→agent delegation so the audit trail captures that
|
|
68
|
-
// this user authorized this agent for this session. Best-effort and
|
|
69
|
-
// written at most once per install: requires both principals to be
|
|
70
|
-
// populated, and any failure is logged and swallowed (fail-open —
|
|
71
|
-
// delegation tracking is for audit, not enforcement).
|
|
72
|
-
await (0, argus_1.writeUserDelegatesAgent)(client);
|
|
73
|
-
};
|
|
61
|
+
});
|
|
74
62
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return async (ctx) => {
|
|
63
|
+
function createBeforeToolCallHandler(client, subagents) {
|
|
64
|
+
return (ctx) => (0, argus_1.withHookContext)(client, { sessionId: ctx.sessionId }, async () => {
|
|
78
65
|
client.logger.info("lifecycle.before_tool_call", {
|
|
79
66
|
toolId: ctx.toolId,
|
|
80
67
|
toolName: ctx.toolName,
|
|
81
68
|
sessionId: ctx.sessionId,
|
|
82
69
|
callId: ctx.callId,
|
|
83
70
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
// If Ory is not configured, pass through
|
|
98
|
-
if (!(0, argus_1.resolveConfig)().projectUrl) {
|
|
99
|
-
client.tracer.record("tool.invoke", "skipped", {
|
|
100
|
-
attributes: { toolName: ctx.toolId, reason: "not_configured", ...inputSummary },
|
|
101
|
-
});
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const subject = (0, argus_1.resolveUserSubject)(client, ctx.sessionId ? `session:${ctx.sessionId}` : "agent:openclaw");
|
|
105
|
-
const subjectId = (0, argus_1.subjectLabel)(subject);
|
|
106
|
-
const mcpTool = (0, argus_1.parseMcpToolGeneric)(ctx.toolId);
|
|
107
|
-
try {
|
|
108
|
-
if (mcpTool) {
|
|
109
|
-
const mcpResult = await (0, argus_1.checkMcpPermission)(client, mcpTool, {
|
|
110
|
-
subject,
|
|
111
|
-
spanAttributes: { toolName: ctx.toolId },
|
|
112
|
-
});
|
|
113
|
-
const mcpAttrs = {
|
|
114
|
-
toolName: ctx.toolId,
|
|
115
|
-
mcpServer: mcpTool.serverName,
|
|
116
|
-
mcpTool: mcpTool.toolName,
|
|
117
|
-
...inputSummary,
|
|
118
|
-
};
|
|
119
|
-
const decision = (0, argus_1.applyPermissionMode)(client, mcpResult.allowed, {
|
|
120
|
-
object: mcpTool.serverName,
|
|
121
|
-
relation: "use",
|
|
122
|
-
subjectId,
|
|
123
|
-
...("subjectSet" in subject ? { subjectSet: subject.subjectSet } : {}),
|
|
124
|
-
spanAttributes: mcpAttrs,
|
|
125
|
-
});
|
|
126
|
-
const decisionAttrs = decision.spanAttributes;
|
|
127
|
-
if (decision.kind === "allow") {
|
|
128
|
-
client.tracer.record("tool.invoke", "ok", {
|
|
129
|
-
attributes: { ...mcpAttrs, ...decisionAttrs },
|
|
130
|
-
});
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (decision.kind === "observe") {
|
|
134
|
-
client.tracer.record("tool.block", "denied", {
|
|
135
|
-
attributes: { ...mcpAttrs, ...decisionAttrs, allowed: false, ...(0, argus_1.alertAttributes)(false) },
|
|
136
|
-
});
|
|
137
|
-
client.tracer.record("tool.invoke", "ok", {
|
|
138
|
-
attributes: { ...mcpAttrs, ...decisionAttrs, allowed: false, observed: true },
|
|
139
|
-
});
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
client.tracer.record("tool.block", "denied", {
|
|
143
|
-
attributes: { ...mcpAttrs, ...decisionAttrs, allowed: false, ...(0, argus_1.alertAttributes)(true) },
|
|
144
|
-
});
|
|
145
|
-
const blockReason = (0, argus_1.formatDenialMessage)({
|
|
146
|
-
tool: ctx.toolId,
|
|
147
|
-
subjectId,
|
|
148
|
-
mcp: mcpTool,
|
|
149
|
-
});
|
|
150
|
-
client.logger.warn("tool.denied", {
|
|
151
|
-
toolId: ctx.toolId,
|
|
152
|
-
subjectId,
|
|
153
|
-
message: blockReason,
|
|
154
|
-
});
|
|
155
|
-
return { block: true, blockReason };
|
|
156
|
-
}
|
|
157
|
-
const namespace = resolveNamespace();
|
|
158
|
-
const outcome = await (0, argus_1.gateToolCall)(client, {
|
|
159
|
-
harness: "openclaw",
|
|
160
|
-
toolName: ctx.toolId,
|
|
161
|
-
check: { namespace, object: ctx.toolId, relation: "use", ...subject },
|
|
162
|
-
spanAttributes: { toolName: ctx.toolId },
|
|
163
|
-
});
|
|
164
|
-
// Interactive tools (operator-extensible via ORY_INTERACTIVE_TOOLS):
|
|
165
|
-
// the user.interaction span is already recorded; pass through.
|
|
166
|
-
if (outcome.kind === "interactive") {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const decision = outcome;
|
|
170
|
-
if (decision.kind === "fail_open") {
|
|
171
|
-
handlePermissionError(decision.error, ctx.toolId, client);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
const attrs = { toolName: ctx.toolId, ...inputSummary };
|
|
175
|
-
const decisionAttrs = decision.spanAttributes;
|
|
176
|
-
if (decision.kind === "allow") {
|
|
177
|
-
client.tracer.record("tool.invoke", "ok", {
|
|
178
|
-
attributes: { ...attrs, ...decisionAttrs, allowed: true },
|
|
179
|
-
});
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
if (decision.kind === "observe") {
|
|
183
|
-
client.tracer.record("tool.block", "denied", {
|
|
184
|
-
attributes: { ...attrs, ...decisionAttrs, allowed: false, ...(0, argus_1.alertAttributes)(false) },
|
|
185
|
-
});
|
|
186
|
-
client.tracer.record("tool.invoke", "ok", {
|
|
187
|
-
attributes: { ...attrs, ...decisionAttrs, allowed: false, observed: true },
|
|
188
|
-
});
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
client.tracer.record("tool.block", "denied", {
|
|
192
|
-
attributes: { ...attrs, ...decisionAttrs, allowed: false, ...(0, argus_1.alertAttributes)(true) },
|
|
193
|
-
});
|
|
194
|
-
const blockReason = (0, argus_1.formatDenialMessage)({
|
|
195
|
-
tool: ctx.toolId,
|
|
196
|
-
subjectId,
|
|
197
|
-
namespace,
|
|
198
|
-
});
|
|
199
|
-
client.logger.warn("tool.denied", {
|
|
200
|
-
toolId: ctx.toolId,
|
|
201
|
-
subjectId,
|
|
202
|
-
message: blockReason,
|
|
203
|
-
});
|
|
204
|
-
return { block: true, blockReason };
|
|
205
|
-
}
|
|
206
|
-
catch (err) {
|
|
207
|
-
handlePermissionError(err, ctx.toolId, client);
|
|
208
|
-
// Fail open — allow the tool call
|
|
71
|
+
const result = await (0, argus_1.gate)(client, {
|
|
72
|
+
harness: HARNESS,
|
|
73
|
+
toolName: ctx.toolId,
|
|
74
|
+
toolArgs: ctx.args,
|
|
75
|
+
subjectFallback: ctx.sessionId ? `session:${ctx.sessionId}` : "agent:openclaw",
|
|
76
|
+
canBlock: true,
|
|
77
|
+
mcpTool: (0, argus_1.parseMcpToolGeneric)(ctx.toolId) ?? undefined,
|
|
78
|
+
principals: openClawSubagentPrincipals(ctx, subagents),
|
|
79
|
+
});
|
|
80
|
+
if (result.blocked) {
|
|
81
|
+
return { block: true, blockReason: result.denialMessage };
|
|
209
82
|
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function openClawSubagentPrincipals(ctx, subagents) {
|
|
86
|
+
const childSession = ctx.sessionKey ?? ctx.sessionId;
|
|
87
|
+
const subagent = subagents.get(childSession);
|
|
88
|
+
if (!subagent)
|
|
89
|
+
return undefined;
|
|
90
|
+
return {
|
|
91
|
+
subAgentClientId: subagent.clientId,
|
|
92
|
+
subAgentType: subagent.type,
|
|
93
|
+
perSpawnId: childSession,
|
|
94
|
+
sessionId: subagent.parentSession,
|
|
210
95
|
};
|
|
211
96
|
}
|
|
212
|
-
// ─── after_tool_call ───────────────────────────────────────────────
|
|
213
97
|
function createAfterToolCallHandler(client) {
|
|
214
|
-
return async (
|
|
98
|
+
return (ctx) => (0, argus_1.withHookContext)(client, { sessionId: ctx.sessionId }, async () => {
|
|
215
99
|
client.logger.info("lifecycle.after_tool_call", {
|
|
216
100
|
toolId: ctx.toolId,
|
|
217
101
|
toolName: ctx.toolName,
|
|
@@ -220,59 +104,40 @@ function createAfterToolCallHandler(client) {
|
|
|
220
104
|
durationMs: ctx.durationMs,
|
|
221
105
|
hasError: !!ctx.error,
|
|
222
106
|
});
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
});
|
|
228
|
-
const status = ctx.error ? "error" : "ok";
|
|
229
|
-
client.tracer.record("tool.complete", status, {
|
|
230
|
-
attributes: {
|
|
107
|
+
if (ctx.error)
|
|
108
|
+
client.logger.debug("lifecycle.after_tool_call.error", { error: ctx.error });
|
|
109
|
+
if (ctx.error) {
|
|
110
|
+
(0, argus_1.fail)(client, {
|
|
231
111
|
toolName: ctx.toolId,
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
durationMs: ctx.durationMs,
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
112
|
+
input: ctx.args,
|
|
113
|
+
error: ctx.error,
|
|
114
|
+
extraActivityAttributes: { durationMs: ctx.durationMs },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
(0, argus_1.complete)(client, {
|
|
119
|
+
toolName: ctx.toolId,
|
|
120
|
+
input: ctx.args,
|
|
121
|
+
output: ctx.result,
|
|
122
|
+
extraActivityAttributes: { durationMs: ctx.durationMs },
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
239
126
|
}
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
// Per-turn user login refresh. The user login runs at `session_start` and
|
|
243
|
-
// again here; it never blocks (authentication is non-blocking — enforcement
|
|
244
|
-
// is governed by permissionMode at tool-call time). `ensureUserAuthenticated`
|
|
245
|
-
// reuses persisted tokens, so per-turn calls are non-interactive after the
|
|
246
|
-
// first session.
|
|
127
|
+
// OpenClaw refreshes the interactive user credential before every model turn.
|
|
247
128
|
function createBeforeAgentRunHandler(client, deps) {
|
|
248
|
-
return
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// (non-interactive after the first session) and never stops the run —
|
|
255
|
-
// enforcement is governed by permissionMode at tool-call time.
|
|
256
|
-
const userGate = deps.userLogin ?? argus_1.ensureUserAuthenticated;
|
|
257
|
-
await userGate(client, {
|
|
258
|
-
binName: "ory-openclaw",
|
|
259
|
-
harness: "openclaw",
|
|
260
|
-
});
|
|
261
|
-
return;
|
|
262
|
-
};
|
|
129
|
+
return (ctx) => (0, argus_1.withHookContext)(client, {
|
|
130
|
+
sessionId: ctx.sessionKey ?? ctx.sessionId,
|
|
131
|
+
}, async () => {
|
|
132
|
+
const userLogin = deps.userLogin ?? argus_1.ensureUserAuthenticated;
|
|
133
|
+
await userLogin(client, { binName: "ory-openclaw", harness: HARNESS });
|
|
134
|
+
});
|
|
263
135
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
// delegation tuple. Best-effort: failures here never abort the child run.
|
|
269
|
-
function createSubagentSpawningHandler(client, deps) {
|
|
270
|
-
return async (ctx) => {
|
|
136
|
+
function createSubagentSpawningHandler(client, deps, subagents) {
|
|
137
|
+
return (ctx) => (0, argus_1.withHookContext)(client, {
|
|
138
|
+
sessionId: ctx.sessionKey,
|
|
139
|
+
}, async () => {
|
|
271
140
|
const subAgentType = ctx.agentId ?? ctx.label;
|
|
272
|
-
client.tracer.setContext({
|
|
273
|
-
traceId: (0, argus_1.deriveTraceId)(ctx.sessionKey ?? ctx.childSessionKey ?? "openclaw"),
|
|
274
|
-
sessionId: ctx.sessionKey,
|
|
275
|
-
});
|
|
276
141
|
client.logger.info("lifecycle.subagent_spawning", {
|
|
277
142
|
agentId: ctx.agentId,
|
|
278
143
|
label: ctx.label,
|
|
@@ -280,7 +145,7 @@ function createSubagentSpawningHandler(client, deps) {
|
|
|
280
145
|
mode: ctx.mode,
|
|
281
146
|
requester: ctx.requester,
|
|
282
147
|
});
|
|
283
|
-
client.
|
|
148
|
+
client.logger.activity("subagent.prepare", "ok", {
|
|
284
149
|
attributes: {
|
|
285
150
|
subAgentType,
|
|
286
151
|
agentId: ctx.agentId,
|
|
@@ -291,44 +156,40 @@ function createSubagentSpawningHandler(client, deps) {
|
|
|
291
156
|
});
|
|
292
157
|
if (!subAgentType) {
|
|
293
158
|
client.logger.debug("subagent.no_type", {
|
|
294
|
-
message: "subagent_spawning event without agentId/label
|
|
159
|
+
message: "subagent_spawning event without agentId/label; skipping DCR.",
|
|
295
160
|
});
|
|
296
161
|
return;
|
|
297
162
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
163
|
+
await (0, argus_1.registerSubagent)(client, {
|
|
164
|
+
harness: HARNESS,
|
|
165
|
+
subAgentType,
|
|
166
|
+
subAgentGate: deps.subAgentGate,
|
|
167
|
+
perSpawnId: ctx.childSessionKey,
|
|
168
|
+
});
|
|
169
|
+
if (ctx.childSessionKey) {
|
|
170
|
+
const credential = ctx.sessionKey
|
|
171
|
+
? (0, argus_1.loadSubAgentDynamicCredentials)(HARNESS, ctx.sessionKey, subAgentType)
|
|
172
|
+
: (0, argus_1.loadSubAgentDynamicCredentials)(HARNESS, subAgentType);
|
|
173
|
+
if (credential) {
|
|
174
|
+
subagents.set(ctx.childSessionKey, {
|
|
175
|
+
clientId: credential.clientId,
|
|
176
|
+
type: subAgentType,
|
|
177
|
+
parentSession: ctx.sessionKey,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
313
180
|
}
|
|
314
|
-
|
|
315
|
-
return;
|
|
316
|
-
await (0, argus_1.writeAgentDelegatesSubagent)(client, identity.subject, subAgentType);
|
|
317
|
-
};
|
|
181
|
+
});
|
|
318
182
|
}
|
|
319
|
-
// ─── subagent_spawned ──────────────────────────────────────────────
|
|
320
183
|
function createSubagentSpawnedHandler(client) {
|
|
321
|
-
return
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
sessionId: ctx.sessionKey,
|
|
325
|
-
});
|
|
184
|
+
return (ctx) => (0, argus_1.withHookContext)(client, {
|
|
185
|
+
sessionId: ctx.sessionKey,
|
|
186
|
+
}, async () => {
|
|
326
187
|
client.logger.info("lifecycle.subagent_spawned", {
|
|
327
188
|
agentId: ctx.agentId,
|
|
328
189
|
childRunId: ctx.childRunId,
|
|
329
190
|
childSessionKey: ctx.childSessionKey,
|
|
330
191
|
});
|
|
331
|
-
client.
|
|
192
|
+
client.logger.activity("subagent.start", "ok", {
|
|
332
193
|
attributes: {
|
|
333
194
|
subAgentType: ctx.agentId ?? ctx.label,
|
|
334
195
|
agentId: ctx.agentId,
|
|
@@ -336,21 +197,21 @@ function createSubagentSpawnedHandler(client) {
|
|
|
336
197
|
stage: "spawned",
|
|
337
198
|
},
|
|
338
199
|
});
|
|
339
|
-
};
|
|
200
|
+
});
|
|
340
201
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
202
|
+
function createSubagentEndedHandler(client, subagents) {
|
|
203
|
+
return (ctx) => (0, argus_1.withHookContext)(client, {
|
|
204
|
+
sessionId: ctx.sessionKey,
|
|
205
|
+
}, async () => {
|
|
206
|
+
const childSessionKey = ctx.targetSessionKey ?? ctx.childSessionKey;
|
|
207
|
+
if (childSessionKey)
|
|
208
|
+
subagents.delete(childSessionKey);
|
|
348
209
|
client.logger.info("lifecycle.subagent_ended", {
|
|
349
210
|
agentId: ctx.agentId,
|
|
350
211
|
childRunId: ctx.childRunId,
|
|
351
212
|
reason: ctx.reason,
|
|
352
213
|
});
|
|
353
|
-
client.
|
|
214
|
+
client.logger.activity("subagent.stop", "ok", {
|
|
354
215
|
attributes: {
|
|
355
216
|
subAgentType: ctx.agentId ?? ctx.label,
|
|
356
217
|
agentId: ctx.agentId,
|
|
@@ -358,41 +219,5 @@ function createSubagentEndedHandler(client) {
|
|
|
358
219
|
reason: ctx.reason,
|
|
359
220
|
},
|
|
360
221
|
});
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
// ─── Helpers ───────────────────────────────────────────────────────
|
|
364
|
-
function resolveNamespace() {
|
|
365
|
-
return process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools";
|
|
366
|
-
}
|
|
367
|
-
function isOryError(err) {
|
|
368
|
-
return (typeof err === "object" &&
|
|
369
|
-
err !== null &&
|
|
370
|
-
"code" in err &&
|
|
371
|
-
"message" in err);
|
|
372
|
-
}
|
|
373
|
-
function handlePermissionError(err, toolId, client) {
|
|
374
|
-
if (isOryError(err)) {
|
|
375
|
-
if (err.code === "network_error" || err.code === "rate_limited") {
|
|
376
|
-
client.logger.warn("permission.fallback", {
|
|
377
|
-
toolId,
|
|
378
|
-
code: err.code,
|
|
379
|
-
message: "Failing open",
|
|
380
|
-
});
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
client.logger.error("permission.check.error", {
|
|
384
|
-
toolId,
|
|
385
|
-
code: err.code,
|
|
386
|
-
message: err.message,
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
client.logger.error("permission.check.error", {
|
|
391
|
-
toolId,
|
|
392
|
-
error: err instanceof Error ? err.message : String(err),
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
// Fail-open is log-and-allow: no tool.invoke span, matching the core
|
|
396
|
-
// gate() vocabulary. The errored permission.check span carries the audit
|
|
397
|
-
// trail for the failed check itself.
|
|
222
|
+
});
|
|
398
223
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -32,6 +32,11 @@ export interface BeforeToolCallContext {
|
|
|
32
32
|
args: Record<string, unknown>;
|
|
33
33
|
sessionId: string;
|
|
34
34
|
callId: string;
|
|
35
|
+
/** Agent definition currently executing the tool, when supplied by OpenClaw. */
|
|
36
|
+
agentId?: string;
|
|
37
|
+
/** Session key currently executing the tool; child agents use their child key. */
|
|
38
|
+
sessionKey?: string;
|
|
39
|
+
runId?: string;
|
|
35
40
|
}
|
|
36
41
|
export interface AfterToolCallContext {
|
|
37
42
|
toolId: string;
|
|
@@ -109,8 +114,10 @@ export interface SubagentSpawnedContext extends SubagentSpawningContext {
|
|
|
109
114
|
}
|
|
110
115
|
export interface SubagentEndedContext extends SubagentSpawningContext {
|
|
111
116
|
childRunId?: string;
|
|
117
|
+
/** Canonical OpenClaw identifier for the child session that ended. */
|
|
118
|
+
targetSessionKey?: string;
|
|
112
119
|
reason?: string;
|
|
113
|
-
/** Final response/output from the child run (audit-only). */
|
|
120
|
+
/** Final response/output from the child run (audit-trail only). */
|
|
114
121
|
result?: unknown;
|
|
115
122
|
}
|
|
116
123
|
export interface HookResult {
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"id": "ory-agent-security",
|
|
3
3
|
"name": "Ory Agent Security",
|
|
4
4
|
"version": "0.1.0",
|
|
5
|
-
"description": "Authentication, authorization, and
|
|
5
|
+
"description": "Authentication, authorization, and activity auditing for OpenClaw via Ory",
|
|
6
6
|
"entry": "./dist/index.js"
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ory/openclaw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Ory plugin for OpenClaw: scaffolding skills, a local Ory instance, and authentication, authorization, and audit for every tool call",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://ory.com",
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
"agent-security",
|
|
34
34
|
"guardrails",
|
|
35
35
|
"llm",
|
|
36
|
-
"
|
|
37
|
-
"distributed-tracing",
|
|
36
|
+
"activity-auditing",
|
|
38
37
|
"observability",
|
|
39
38
|
"kratos",
|
|
40
39
|
"keto",
|
|
@@ -45,6 +44,10 @@
|
|
|
45
44
|
"registry": "https://registry.npmjs.org/",
|
|
46
45
|
"provenance": true
|
|
47
46
|
},
|
|
47
|
+
"reova": {
|
|
48
|
+
"enabled": true,
|
|
49
|
+
"endpoint": "https://telemetry.reo.dev/data"
|
|
50
|
+
},
|
|
48
51
|
"main": "dist/index.js",
|
|
49
52
|
"types": "dist/index.d.ts",
|
|
50
53
|
"exports": {
|
|
@@ -61,12 +64,11 @@
|
|
|
61
64
|
"files": [
|
|
62
65
|
"dist",
|
|
63
66
|
"openclaw.plugin.json",
|
|
64
|
-
"!dist/dev",
|
|
65
67
|
"!dist/**/*.tsbuildinfo"
|
|
66
68
|
],
|
|
67
69
|
"dependencies": {
|
|
68
|
-
"
|
|
69
|
-
"@ory/argus": "0.
|
|
70
|
+
"reova": "^0.7.0",
|
|
71
|
+
"@ory/argus": "1.0.0"
|
|
70
72
|
},
|
|
71
73
|
"engines": {
|
|
72
74
|
"node": ">=22"
|
|
@@ -76,7 +78,6 @@
|
|
|
76
78
|
"clean": "rm -rf dist *.tsbuildinfo",
|
|
77
79
|
"test": "vitest run",
|
|
78
80
|
"test:watch": "vitest",
|
|
79
|
-
"typecheck": "tsc --noEmit"
|
|
80
|
-
"dev": "node dist/dev/launcher.js"
|
|
81
|
+
"typecheck": "tsc --noEmit"
|
|
81
82
|
}
|
|
82
83
|
}
|