@ory/codex 0.14.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -67
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.js +33 -18
- package/dist/cli/setup.d.ts +2 -1
- package/dist/cli/setup.js +93 -38
- package/dist/handlers.d.ts +3 -19
- package/dist/handlers.js +163 -279
- package/dist/hook.js +41 -16
- package/dist/session-state.d.ts +3 -0
- package/dist/session-state.js +61 -0
- package/dist/types.d.ts +1 -0
- package/marketplace/plugins/ory-codex/.codex-plugin/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 [Codex](https://github.com/openai/codex), powered by [Ory](https://ory.com).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Codex 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, a bundled Ory tool 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,134 +18,136 @@ Security and developer experience for [Codex](https://github.com/openai/codex),
|
|
|
15
18
|
|
|
16
19
|
## Get started
|
|
17
20
|
|
|
18
|
-
Run one command
|
|
21
|
+
Run one command:
|
|
19
22
|
|
|
20
23
|
```bash
|
|
21
24
|
npx -y -p @ory/codex ory-codex install
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
This registers the Ory plugin with Codex (hooks, skills, and a bundled Ory tool server)
|
|
25
|
-
|
|
26
|
-
- **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.
|
|
27
|
-
- **Local** — run a complete Ory on your laptop with Docker. No account, no signup, no keys. Great for trying it out.
|
|
28
|
-
- **Audit-only** — skip Ory entirely and just log what Codex does.
|
|
29
|
-
|
|
30
|
-
> No browser available (CI, SSH, headless)? The same walkthrough runs right in your terminal instead — or force it with `--no-web`.
|
|
31
|
-
|
|
32
|
-
That's it. Confirm everything landed with:
|
|
27
|
+
This registers the Ory plugin with Codex (hooks, skills, and a bundled Ory tool server). Confirm everything landed with:
|
|
33
28
|
|
|
34
29
|
```bash
|
|
35
30
|
npx -y -p @ory/codex ory-codex status
|
|
36
31
|
```
|
|
37
32
|
|
|
38
|
-
`status` is your one-stop check: what's configured, who's signed in, which tools are covered by permissions, and recent activity.
|
|
33
|
+
`status` is your one-stop check: what's configured, who's signed in, which tools are covered by permissions, and recent activity. Until you connect Agent Security, the identity and permission rows say so and name what's missing.
|
|
34
|
+
|
|
35
|
+
> **First launch: trust the Ory hooks.** Codex treats a freshly installed plugin's hooks as untrusted, so your first Codex session asks you to review and trust them. Activity logging starts once you do; sign-in and per-tool checks only run after you connect to Agent Security. In the TUI, that first check kicks in on your opening turn. If Codex consumed its one-shot session event before the plugin became trusted, the opening prompt starts authentication instead.
|
|
36
|
+
|
|
37
|
+
## Skills and commands
|
|
38
|
+
|
|
39
|
+
Installing the plugin drops the full Ory playbook catalog into Codex. **Skills** are model-invoked — say what you want in plain language, or pick one from the `/skills` menu.
|
|
40
|
+
|
|
41
|
+
| Skill | What it does for you |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `ory-auth-setup` | Adds a complete auth system to your app — login, registration, recovery, verification, settings — on [Ory Elements](https://github.com/ory/elements) |
|
|
44
|
+
| `ory-login-flow` | Builds just the pages, wired to Ory's self-service flows |
|
|
45
|
+
| `ory-social-login` | "Sign in with…" for Google, GitHub, Apple, Microsoft, Discord, Slack, GitLab, Facebook |
|
|
46
|
+
| `ory-local-dev` | Develops and tests login/permission flows against a local Ory — no project, no account, offline |
|
|
47
|
+
| `ory-permissions-onboarding` | Walks a fresh install from observe mode to enforced per-tool permissions without getting blocked |
|
|
48
|
+
| `ory-build-agent` | Drops `@ory/argus` into an agent *you* own — Claude Agent SDK, OpenAI Agents, Mastra, Vercel AI, LangGraph/PydanticAI |
|
|
49
|
+
| `ory-build-integration` | Wires Ory into your app: Action webhooks, JWT validation at a gateway, live event streams |
|
|
50
|
+
| `ory-contribute-integration` | Authors and submits an integration to the public `ory/integrates` registry |
|
|
51
|
+
| `ory-e2b-sandbox` | Scaffolds an E2B sandbox template that boots with this plugin preinstalled |
|
|
52
|
+
| `ory-temporal-worker` | Scaffolds a Temporal TypeScript worker where every Activity is authenticated, authorized, and audited |
|
|
53
|
+
|
|
54
|
+
The local stack has its own playbooks — ask for them by name:
|
|
39
55
|
|
|
40
|
-
|
|
56
|
+
| Command | What it does |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `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 |
|
|
59
|
+
| `ory-local-down` | Stops it, keeping your data volumes |
|
|
60
|
+
| `ory-temporal-up` | Starts a local Temporal dev server for the `ory-temporal-worker` scaffold |
|
|
41
61
|
|
|
42
|
-
|
|
62
|
+
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`.
|
|
63
|
+
|
|
64
|
+
A built-in **Ory tool server** rounds it out — Codex can manage identities, projects, and permissions straight from chat.
|
|
65
|
+
|
|
66
|
+
So: ask Codex *"add Ory login to this app"* and it scaffolds the pages, starts a local Ory, and wires them together.
|
|
43
67
|
|
|
44
68
|
## What you get
|
|
45
69
|
|
|
46
|
-
|
|
70
|
+
Out of the box, every tool Codex runs produces a privacy-safe structured activity event in the unified local log.
|
|
71
|
+
|
|
72
|
+
Once you connect to Ory Agent Security, two more things happen automatically:
|
|
47
73
|
|
|
48
|
-
- **Who's driving.** You sign in once in your browser (
|
|
49
|
-
- **What it's allowed to do.** Before a tool runs, Ory checks whether it's permitted. It starts in **
|
|
50
|
-
- **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.
|
|
74
|
+
- **Who's driving.** You sign in once in your browser; Codex (and any sub-agents it spawns) each get their own identity. No tokens to copy around, and the "who acted on whose behalf" trail stays queryable later.
|
|
75
|
+
- **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.
|
|
51
76
|
|
|
52
|
-
If Ory is ever unreachable, the plugin gets out of the way and lets Codex keep working — so it can't lock you out.
|
|
77
|
+
If Ory is ever unreachable, the plugin gets out of the way and lets Codex keep working — so it can't lock you out.
|
|
53
78
|
|
|
54
79
|
### See what's happening
|
|
55
80
|
|
|
56
|
-
Everything the plugin does is observable out of the box
|
|
81
|
+
Everything the plugin does is observable out of the box:
|
|
57
82
|
|
|
58
|
-
- **
|
|
59
|
-
- **Live dashboard.** `npx -y -p @ory/codex ory-codex 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.
|
|
60
|
-
- **Live traces.** Every tool call is recorded as an OpenTelemetry-style span. Watch them stream as the agent works:
|
|
83
|
+
- **Activity log.** Privacy-safe activity is always appended to `~/.config/ory-agent-plugins/codex/ory-agent-debug.log`. View events, decisions, and errors live with:
|
|
61
84
|
|
|
62
85
|
```bash
|
|
63
86
|
npx -y -p @ory/codex ory-codex watch
|
|
64
87
|
```
|
|
65
88
|
|
|
66
|
-
|
|
67
|
-
- **
|
|
89
|
+
Set `ORY_AGENT_LOG_FILE` to override the path; set it empty to disable file persistence.
|
|
90
|
+
- **Live debug.** Launch Codex 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.
|
|
68
91
|
|
|
69
92
|
### Ready to enforce?
|
|
70
93
|
|
|
71
|
-
|
|
94
|
+
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.
|
|
72
95
|
|
|
73
96
|
```bash
|
|
74
|
-
npx -y -p @ory/codex ory-codex permissions
|
|
97
|
+
npx -y -p @ory/codex ory-codex permissions # what the project grants, and the live mode
|
|
75
98
|
```
|
|
76
99
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
## Also: add login to your own app
|
|
80
|
-
|
|
81
|
-
Beyond securing Codex, the plugin helps you build Ory into whatever you're working on. Ask Codex *"add Ory login to this app"* — or pick `ory-auth-setup` from the `/skills` menu — and it scaffolds the login, registration, recovery, and settings pages (using [Ory Elements](https://github.com/ory/elements)) wired to a local Ory, so no signup or keys are needed. Start that local Ory with the `ory-local-up` skill (it prints a test email + password to sign in with) and tear it down with `ory-local-down`.
|
|
100
|
+
Then a denied tool is actually blocked and Codex shows why.
|
|
82
101
|
|
|
83
|
-
|
|
102
|
+
## Connect to Ory Agent Security
|
|
84
103
|
|
|
85
|
-
|
|
104
|
+
Copy the connection details from the [Ory Console](https://console.ory.sh) under **Agent Security**:
|
|
86
105
|
|
|
87
|
-
|
|
106
|
+
| Value | Flag | Environment variable |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| Project URL | `--project-url` | `ORY_PROJECT_URL` |
|
|
109
|
+
| Agent Security URL | `--agent-security-url` | `ORY_AGENT_SECURITY_URL` |
|
|
110
|
+
| Sign-in client id override (default `ory-agent-security-login`) | `--oauth2-client-id` | `ORY_OAUTH2_CLIENT_ID` |
|
|
88
111
|
|
|
89
112
|
```bash
|
|
90
113
|
npx -y -p @ory/codex ory-codex configure \
|
|
91
114
|
--project-url https://<slug>.projects.oryapis.com \
|
|
92
|
-
--
|
|
115
|
+
--agent-security-url https://agents.console.ory.com
|
|
93
116
|
```
|
|
94
117
|
|
|
95
|
-
|
|
118
|
+
`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`.
|
|
96
119
|
|
|
97
|
-
|
|
98
|
-
<summary>Create the sign-in client by hand</summary>
|
|
99
|
-
|
|
100
|
-
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 at runtime so sign-in survives a busy port, and Ory only accepts a callback on a URL you registered:
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
ory create oauth2-client --project <project-id> \
|
|
104
|
-
--name "Ory Agent Security · user login (PKCE)" \
|
|
105
|
-
--grant-type authorization_code,refresh_token \
|
|
106
|
-
--response-type code \
|
|
107
|
-
--scope openid,offline_access \
|
|
108
|
-
--token-endpoint-auth-method none \
|
|
109
|
-
--redirect-uri http://127.0.0.1:47823/callback \
|
|
110
|
-
--redirect-uri http://127.0.0.1:47824/callback \
|
|
111
|
-
--redirect-uri http://127.0.0.1:47825/callback \
|
|
112
|
-
--redirect-uri http://127.0.0.1:47826/callback
|
|
113
|
-
```
|
|
120
|
+
**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.
|
|
114
121
|
|
|
115
|
-
|
|
122
|
+
**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 Codex session registers its own identity automatically on first use.
|
|
116
123
|
|
|
117
|
-
|
|
124
|
+
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.
|
|
118
125
|
|
|
119
|
-
|
|
126
|
+
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.
|
|
120
127
|
|
|
121
128
|
## Commands
|
|
122
129
|
|
|
123
130
|
```
|
|
124
|
-
ory-codex install | uninstall Install
|
|
131
|
+
ory-codex install | uninstall Install (add --project-url to also connect Agent Security) / remove
|
|
125
132
|
ory-codex status Show configuration, identities, permission coverage, recent activity
|
|
126
|
-
ory-codex
|
|
127
|
-
ory-codex
|
|
128
|
-
ory-codex permissions <cmd> status | bootstrap | observe (watch) | enforce (block)
|
|
129
|
-
ory-codex configure <flags> Point at a project by hand (--project-url, --oauth2-client-id, --audit-only)
|
|
133
|
+
ory-codex permissions <cmd> status (read-only; grants + posture live in the Ory Console)
|
|
134
|
+
ory-codex configure <flags> Connect a project (--project-url) or --disconnect
|
|
130
135
|
ory-codex agent <status|unregister> Manage Codex's own auto-created identity
|
|
131
136
|
ory-codex local <up|down|status|…> Run / manage a local Ory in Docker
|
|
137
|
+
ory-codex version Print plugin, core, and Node versions (--json for machine-readable)
|
|
132
138
|
```
|
|
133
139
|
|
|
134
140
|
All prefixed with `npx -y -p @ory/codex`.
|
|
135
141
|
|
|
136
|
-
The local stack runs a complete Ory on your laptop: the Ory APIs at `http://localhost:4000`, a login UI on `:4455` (not :3000, to avoid Next.js port conflicts), the Ory Console on `:4100
|
|
142
|
+
The local stack runs a complete Ory on your laptop: the Ory APIs at `http://localhost:4000`, a login UI on `:4455` (not :3000, to avoid Next.js port conflicts), and the Ory Console on `:4100`.
|
|
137
143
|
|
|
138
144
|
## Troubleshooting
|
|
139
145
|
|
|
140
146
|
- **`local up` fails** — make sure Docker is running and ports `4000`, `4100`, `4455`, and `16686` are free.
|
|
141
|
-
- **Browser sign-in loops** — reset with `ory-codex agent unregister` and try again.
|
|
142
|
-
- **
|
|
147
|
+
- **Browser sign-in loops** (after connecting) — reset with `ory-codex agent unregister` and try again.
|
|
148
|
+
- **Running an older CLI than expected** — `npx -p @ory/codex` (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/codex ory-codex version`. To force the current release, clear the cache and reinstall: `rm -rf ~/.npm/_npx` then `npx -y -p @ory/codex ory-codex install`. Pinning an exact version (`@ory/codex@<version>`) also bypasses the cached copy.
|
|
143
149
|
- **`npm install … ENOVERSIONS`** — if your `~/.npmrc` sets `min-release-age`, npm hides versions newer than that. Override per-call: `npm_config_min_release_age=0 npx -y -p @ory/codex ory-codex install`.
|
|
144
150
|
- **`codex doctor` says `ory-mcp-server is not resolvable`** — the bundled tool server is fetched on demand via `npx`, so make sure `npm`/`npx` is on your PATH. The first session downloads it; later ones reuse the cache.
|
|
145
|
-
- **Want to see what's happening** — `npx -y -p @ory/codex ory-codex status` for a snapshot, `npx -y -p @ory/codex ory-codex 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/codex/` (see [See what's happening](#see-whats-happening)).
|
|
146
151
|
|
|
147
152
|
## Learn more
|
|
148
153
|
|
package/dist/cli/main.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* npx ory-codex uninstall Remove the plugin via `codex plugin remove`
|
|
8
8
|
* npx ory-codex configure Set or view Ory project URL and API key
|
|
9
9
|
* npx ory-codex agent <cmd> Manage the agent's OAuth2 identity
|
|
10
|
-
* npx ory-codex permissions
|
|
10
|
+
* npx ory-codex permissions Show permission mode and per-tool coverage
|
|
11
11
|
* npx ory-codex local <cmd> Manage local Ory dev environment
|
|
12
12
|
* npx ory-codex status Show plugin status and configuration
|
|
13
13
|
*/
|
package/dist/cli/main.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* npx ory-codex uninstall Remove the plugin via `codex plugin remove`
|
|
9
9
|
* npx ory-codex configure Set or view Ory project URL and API key
|
|
10
10
|
* npx ory-codex agent <cmd> Manage the agent's OAuth2 identity
|
|
11
|
-
* npx ory-codex permissions
|
|
11
|
+
* npx ory-codex permissions Show permission mode and per-tool coverage
|
|
12
12
|
* npx ory-codex local <cmd> Manage local Ory dev environment
|
|
13
13
|
* npx ory-codex status Show plugin status and configuration
|
|
14
14
|
*/
|
|
@@ -53,8 +53,17 @@ const setup_js_1 = require("./setup.js");
|
|
|
53
53
|
const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
|
|
54
54
|
function main() {
|
|
55
55
|
const [command, ...args] = process.argv.slice(2);
|
|
56
|
+
// `--help` after a matched subcommand: print usage, do nothing else.
|
|
57
|
+
// Without this the switch below ignores the flag and `install --help`
|
|
58
|
+
// performs a real install (#221).
|
|
59
|
+
if ((0, argus_1.shouldPrintHelp)(command, args))
|
|
60
|
+
return help();
|
|
56
61
|
switch (command) {
|
|
57
62
|
case "install":
|
|
63
|
+
if (args.includes("--print")) {
|
|
64
|
+
(0, setup_js_1.printInstallPlan)();
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
58
67
|
(0, argus_1.beginDeferNextSteps)();
|
|
59
68
|
(0, setup_js_1.install)(args);
|
|
60
69
|
(0, argus_1.runPostInstall)("ory-codex", "codex", args).then(() => process.exit(0), (err) => {
|
|
@@ -64,7 +73,10 @@ function main() {
|
|
|
64
73
|
break;
|
|
65
74
|
case "uninstall":
|
|
66
75
|
(0, setup_js_1.uninstall)(args);
|
|
67
|
-
(0, argus_1.clearCredentialsForUninstall)(
|
|
76
|
+
(0, argus_1.clearCredentialsForUninstall)({
|
|
77
|
+
harness: "codex",
|
|
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-codex", args);
|
|
74
86
|
break;
|
|
75
87
|
case "agent":
|
|
76
|
-
(0, argus_1.runAgentCommand)("ory-codex", args).then((code) => process.exit(code), (err) => {
|
|
88
|
+
(0, argus_1.runAgentCommand)("ory-codex", "codex", 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-codex", 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)("codex", args);
|
|
106
|
+
(0, argus_1.runWatchCommand)("ory-codex", "codex", 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-codex", args).catch((err) => {
|
|
104
110
|
console.error(err.message ?? err);
|
|
105
111
|
process.exit(1);
|
|
106
112
|
});
|
|
@@ -126,6 +132,15 @@ async function status() {
|
|
|
126
132
|
await (0, argus_1.runStatusCommand)("ory-codex", "codex", {
|
|
127
133
|
title: "Codex",
|
|
128
134
|
printPluginSection: () => {
|
|
135
|
+
// A wiped data dir leaves the harness pointing at a marketplace root
|
|
136
|
+
// that no longer exists, and its plugin surface then fails with an error
|
|
137
|
+
// that never mentions Ory. Say so here, with the repair (#206).
|
|
138
|
+
const dangling = (0, argus_1.findDanglingRegistration)("codex");
|
|
139
|
+
if (dangling) {
|
|
140
|
+
console.log("");
|
|
141
|
+
console.log(` ! ${(0, argus_1.describeDanglingRegistration)(dangling)}`);
|
|
142
|
+
console.log("");
|
|
143
|
+
}
|
|
129
144
|
console.log("Hooks & plugin:");
|
|
130
145
|
console.log(` Directory: ${PACKAGE_ROOT}`);
|
|
131
146
|
console.log(` Hook script: ${fs.existsSync(path.join(PACKAGE_ROOT, "dist", "hook.js")) ? "built" : "NOT BUILT (run pnpm build)"}`);
|
|
@@ -144,20 +159,20 @@ Commands:
|
|
|
144
159
|
uninstall Remove via \`codex plugin remove\` + \`codex plugin marketplace remove\`
|
|
145
160
|
configure Set or view Ory project URL and API key
|
|
146
161
|
agent <cmd> Manage the agent's OAuth2 identity (status, unregister)
|
|
147
|
-
permissions
|
|
148
|
-
(status, bootstrap, observe, enforce)
|
|
162
|
+
permissions Show the live permission mode and per-tool coverage
|
|
149
163
|
local <cmd> Manage local Ory dev environment
|
|
150
164
|
(up, down, status, seed, logs, env, configure, reset)
|
|
151
165
|
status Show plugin status, config, and recent log lines
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
watch [--json] [--lines <count>]
|
|
167
|
+
Follow the live activity/debug log
|
|
154
168
|
version Show version and the ory-agent-plugins build commit
|
|
155
169
|
|
|
156
170
|
Examples:
|
|
157
171
|
npx -y -p @ory/codex ory-codex install
|
|
158
172
|
npx -y -p @ory/codex ory-codex configure --project-url https://<slug>.projects.oryapis.com \\
|
|
159
|
-
--
|
|
160
|
-
|
|
173
|
+
--agent-security-url https://agents.console.ory.com \\
|
|
174
|
+
--oauth2-client-id <id>
|
|
175
|
+
npx -y -p @ory/codex ory-codex permissions
|
|
161
176
|
npx -y -p @ory/codex ory-codex status
|
|
162
177
|
npx -y -p @ory/codex ory-codex uninstall
|
|
163
178
|
|
package/dist/cli/setup.d.ts
CHANGED
|
@@ -24,5 +24,6 @@
|
|
|
24
24
|
* npx ory-codex-setup --uninstall Remove
|
|
25
25
|
* npx ory-codex-setup --help Show this help
|
|
26
26
|
*/
|
|
27
|
-
export declare function install(
|
|
27
|
+
export declare function install(args: string[]): void;
|
|
28
|
+
export declare function printInstallPlan(): void;
|
|
28
29
|
export declare function uninstall(_args: string[]): void;
|
package/dist/cli/setup.js
CHANGED
|
@@ -60,11 +60,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
60
60
|
})();
|
|
61
61
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
62
62
|
exports.install = install;
|
|
63
|
+
exports.printInstallPlan = printInstallPlan;
|
|
63
64
|
exports.uninstall = uninstall;
|
|
64
65
|
const node_child_process_1 = require("node:child_process");
|
|
65
66
|
const fs = __importStar(require("node:fs"));
|
|
66
67
|
const path = __importStar(require("node:path"));
|
|
67
68
|
const argus_1 = require("@ory/argus");
|
|
69
|
+
const session_state_js_1 = require("../session-state.js");
|
|
68
70
|
const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
|
|
69
71
|
const PACKAGE_VERSION = readPackageVersion();
|
|
70
72
|
const MARKETPLACE_NAME = "ory";
|
|
@@ -81,17 +83,16 @@ const RENDER_OPTS = {
|
|
|
81
83
|
*/
|
|
82
84
|
const MARKETPLACE_ROOT = path.join((0, argus_1.getHarnessDataDir)("codex"), "marketplace");
|
|
83
85
|
const PLUGIN_ROOT = path.join(MARKETPLACE_ROOT, "plugins", PLUGIN_NAME);
|
|
84
|
-
/** Hook command that resolves via the npm registry on every invocation. */
|
|
85
|
-
const HOOK_COMMAND = "npx -y -p @ory/codex ory-codex-hook";
|
|
86
86
|
/**
|
|
87
87
|
* Per-handler timeout (seconds). Codex kills a hook subprocess after this
|
|
88
88
|
* window (its built-in default is only 5s). SessionStart may run the
|
|
89
89
|
* interactive user login (PKCE browser flow), which needs a human in the
|
|
90
90
|
* loop, so it gets a generous window; the tool-lifecycle hooks only make a
|
|
91
|
-
* permission check, so a shorter window is plenty.
|
|
91
|
+
* permission check, so a shorter window is plenty. Derived in core so the
|
|
92
|
+
* session-start window cannot drift below the login timeout it must outlast.
|
|
92
93
|
*/
|
|
93
|
-
const SESSION_START_TIMEOUT_SEC =
|
|
94
|
-
const TOOL_HOOK_TIMEOUT_SEC =
|
|
94
|
+
const SESSION_START_TIMEOUT_SEC = (0, argus_1.sessionStartHookTimeout)("codex", "seconds");
|
|
95
|
+
const TOOL_HOOK_TIMEOUT_SEC = (0, argus_1.toolHookTimeout)("codex", "seconds");
|
|
95
96
|
function readPackageVersion() {
|
|
96
97
|
try {
|
|
97
98
|
const pj = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, "package.json"), "utf-8"));
|
|
@@ -180,45 +181,61 @@ function renderCommands() {
|
|
|
180
181
|
* occurrence. Emitting the handler flat (without the wrapping group) parses
|
|
181
182
|
* as a matcher group with zero handlers, so the hook silently never runs.
|
|
182
183
|
*/
|
|
183
|
-
function hookGroup(timeoutSec) {
|
|
184
|
+
function hookGroup(command, timeoutSec) {
|
|
184
185
|
return [
|
|
185
186
|
{
|
|
186
|
-
hooks: [{ type: "command", command
|
|
187
|
+
hooks: [{ type: "command", command, timeout: timeoutSec }],
|
|
187
188
|
},
|
|
188
189
|
];
|
|
189
190
|
}
|
|
190
191
|
/**
|
|
191
|
-
* Generate the hooks file.
|
|
192
|
-
*
|
|
192
|
+
* Generate the hooks file. Every event points at the runtime shim resolved at
|
|
193
|
+
* install time, so nothing is re-resolved per tool call.
|
|
193
194
|
*
|
|
194
195
|
* Codex only loads this file when `plugin.json` declares `hooks` (see the
|
|
195
196
|
* marketplace skeleton); it is not auto-discovered by filename. Fresh plugin
|
|
196
197
|
* hooks are also untrusted until the user reviews them in Codex's hook-trust
|
|
197
198
|
* UI — see `printNextSteps`.
|
|
198
199
|
*/
|
|
199
|
-
function writeHooks() {
|
|
200
|
+
function writeHooks(command) {
|
|
200
201
|
const hooksPath = path.join(PLUGIN_ROOT, "hooks.json");
|
|
201
202
|
fs.writeFileSync(hooksPath, JSON.stringify({
|
|
202
203
|
hooks: {
|
|
203
|
-
SessionStart: hookGroup(SESSION_START_TIMEOUT_SEC),
|
|
204
|
-
PreToolUse: hookGroup(TOOL_HOOK_TIMEOUT_SEC),
|
|
205
|
-
PostToolUse: hookGroup(TOOL_HOOK_TIMEOUT_SEC),
|
|
206
|
-
PermissionRequest: hookGroup(TOOL_HOOK_TIMEOUT_SEC),
|
|
207
|
-
UserPromptSubmit: hookGroup(
|
|
208
|
-
Stop: hookGroup(TOOL_HOOK_TIMEOUT_SEC),
|
|
204
|
+
SessionStart: hookGroup(command, SESSION_START_TIMEOUT_SEC),
|
|
205
|
+
PreToolUse: hookGroup(command, TOOL_HOOK_TIMEOUT_SEC),
|
|
206
|
+
PostToolUse: hookGroup(command, TOOL_HOOK_TIMEOUT_SEC),
|
|
207
|
+
PermissionRequest: hookGroup(command, TOOL_HOOK_TIMEOUT_SEC),
|
|
208
|
+
UserPromptSubmit: hookGroup(command, SESSION_START_TIMEOUT_SEC),
|
|
209
|
+
Stop: hookGroup(command, TOOL_HOOK_TIMEOUT_SEC),
|
|
209
210
|
},
|
|
210
211
|
}, null, 2) + "\n");
|
|
211
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Rewrite the marketplace's `.mcp.json` so the Ory server starts from the
|
|
215
|
+
* resolved runtime. The static skeleton ships an `npx` invocation; replacing it
|
|
216
|
+
* here keeps the registry off the runtime path. Removed outright when the
|
|
217
|
+
* runtime has no MCP server — better none than one that cannot start.
|
|
218
|
+
*/
|
|
219
|
+
function writeMcpConfig(server) {
|
|
220
|
+
const mcpPath = path.join(PLUGIN_ROOT, ".mcp.json");
|
|
221
|
+
if (!server) {
|
|
222
|
+
fs.rmSync(mcpPath, { force: true });
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
fs.writeFileSync(mcpPath, JSON.stringify({ mcpServers: { ory: server } }, null, 2) + "\n");
|
|
226
|
+
}
|
|
212
227
|
/**
|
|
213
228
|
* Assemble the full marketplace tree in the persistent location. Idempotent.
|
|
214
229
|
*/
|
|
215
|
-
function assembleMarketplace() {
|
|
230
|
+
function assembleMarketplace(runtime) {
|
|
231
|
+
(0, session_state_js_1.clearCodexSessionStarts)();
|
|
216
232
|
fs.mkdirSync(MARKETPLACE_ROOT, { recursive: true });
|
|
217
233
|
copyMarketplaceSkeleton();
|
|
218
234
|
updatePluginManifest();
|
|
219
235
|
renderSkills();
|
|
220
236
|
renderCommands();
|
|
221
|
-
writeHooks();
|
|
237
|
+
writeHooks((0, argus_1.requireHookCommand)(runtime));
|
|
238
|
+
writeMcpConfig(runtime.mcpServer);
|
|
222
239
|
}
|
|
223
240
|
/**
|
|
224
241
|
* Register (or refresh) the local marketplace with Codex and install the
|
|
@@ -245,20 +262,52 @@ function registerWithCodex() {
|
|
|
245
262
|
}
|
|
246
263
|
}
|
|
247
264
|
}
|
|
248
|
-
function install(
|
|
265
|
+
function install(args) {
|
|
249
266
|
if (!checkCodexCli()) {
|
|
250
267
|
console.error("Error: 'codex' CLI not found in PATH.");
|
|
251
268
|
console.error("Install Codex first: https://github.com/openai/codex");
|
|
252
269
|
process.exit(1);
|
|
253
270
|
}
|
|
271
|
+
const runtime = (0, argus_1.wireRuntime)({
|
|
272
|
+
harness: "codex",
|
|
273
|
+
packageName: "@ory/codex",
|
|
274
|
+
packageRoot: PACKAGE_ROOT,
|
|
275
|
+
installCommand: "npx -y -p @ory/codex ory-codex install",
|
|
276
|
+
args,
|
|
277
|
+
});
|
|
278
|
+
console.log(runtime.target.kind === "linked"
|
|
279
|
+
? `Runtime: linked to ${runtime.target.packageDir} (dev)`
|
|
280
|
+
: `Runtime: ${runtime.target.packageName}@${runtime.target.version} in ${runtime.target.storeDir}`);
|
|
281
|
+
for (const pruned of runtime.prunedStores) {
|
|
282
|
+
console.log(` Removed stale runtime: ${pruned}`);
|
|
283
|
+
}
|
|
254
284
|
console.log(`Assembling Ory plugin (skills, commands, hooks, MCP) at:`);
|
|
255
285
|
console.log(` ${PLUGIN_ROOT}`);
|
|
256
|
-
assembleMarketplace();
|
|
286
|
+
assembleMarketplace(runtime);
|
|
257
287
|
console.log(`Registering marketplace and installing ${PLUGIN_REF}...`);
|
|
258
288
|
registerWithCodex();
|
|
289
|
+
// Codex stores this path and re-reads it on every run, so a data-dir wipe
|
|
290
|
+
// that skips uninstall would break every `codex plugin` command. Record how
|
|
291
|
+
// to undo the registration so the destructive paths can replay it (#206).
|
|
292
|
+
(0, argus_1.recordExternalRegistration)({
|
|
293
|
+
harness: "codex",
|
|
294
|
+
tool: "codex",
|
|
295
|
+
description: `Codex marketplace "${MARKETPLACE_NAME}"`,
|
|
296
|
+
root: MARKETPLACE_ROOT,
|
|
297
|
+
remove: { command: "codex", args: ["plugin", "marketplace", "remove", MARKETPLACE_NAME] },
|
|
298
|
+
});
|
|
259
299
|
console.log(` Plugin installed.`);
|
|
260
300
|
printNextSteps();
|
|
261
301
|
}
|
|
302
|
+
function printInstallPlan() {
|
|
303
|
+
console.log(JSON.stringify({
|
|
304
|
+
marketplaceRoot: MARKETPLACE_ROOT,
|
|
305
|
+
plugin: PLUGIN_REF,
|
|
306
|
+
hooks: 'node "<runtime shim>"',
|
|
307
|
+
mcpServer: { command: "node", args: ["<MCP runtime shim>"] },
|
|
308
|
+
assets: ["skills/", "commands/"],
|
|
309
|
+
}, null, 2));
|
|
310
|
+
}
|
|
262
311
|
function uninstall(_args) {
|
|
263
312
|
if (!checkCodexCli()) {
|
|
264
313
|
console.error("Error: 'codex' CLI not found in PATH.");
|
|
@@ -283,6 +332,12 @@ function uninstall(_args) {
|
|
|
283
332
|
fs.rmSync(MARKETPLACE_ROOT, { recursive: true, force: true });
|
|
284
333
|
console.log(` Removed ${MARKETPLACE_ROOT}`);
|
|
285
334
|
}
|
|
335
|
+
// Deregistered above, so nothing is left to undo.
|
|
336
|
+
(0, argus_1.clearExternalRegistration)("codex");
|
|
337
|
+
(0, argus_1.removeRuntimeWiring)("codex");
|
|
338
|
+
for (const pruned of (0, argus_1.pruneRuntimeStores)()) {
|
|
339
|
+
console.log(` Removed runtime: ${pruned}`);
|
|
340
|
+
}
|
|
286
341
|
}
|
|
287
342
|
function printNextSteps() {
|
|
288
343
|
(0, argus_1.nextStepsSink)(({ configured }) => configured ? printConfiguredNextStepsNow() : printNextStepsNow());
|
|
@@ -301,19 +356,19 @@ function printConfiguredNextStepsNow() {
|
|
|
301
356
|
console.log(" review and trust the Ory hooks on first launch; the auth gate and");
|
|
302
357
|
console.log(" per-tool permission checks only run once they're trusted.");
|
|
303
358
|
console.log("");
|
|
304
|
-
if ((0, argus_1.
|
|
305
|
-
console.log("
|
|
359
|
+
if (!(0, argus_1.isSecurityConnected)()) {
|
|
360
|
+
console.log(" Agent Security not connected: tool activity is recorded locally — no checks, nothing blocked.");
|
|
306
361
|
console.log("");
|
|
307
|
-
console.log(` 1. See
|
|
308
|
-
console.log(" 2.
|
|
362
|
+
console.log(` 1. See recorded activity: ${npx} status`);
|
|
363
|
+
console.log(" 2. Stream activity live: export ORY_AGENT_DEBUG=true");
|
|
309
364
|
}
|
|
310
365
|
else {
|
|
311
|
-
console.log(" It starts in
|
|
366
|
+
console.log(" It starts in observe mode: every tool call is checked, nothing blocked yet.");
|
|
312
367
|
console.log("");
|
|
313
|
-
console.log(` 1. See what Ory is doing: ${npx} status
|
|
314
|
-
console.log(
|
|
315
|
-
console.log(` (
|
|
316
|
-
console.log(" 3.
|
|
368
|
+
console.log(` 1. See what Ory is doing: ${npx} status`);
|
|
369
|
+
console.log(" 2. Turn on enforcement: in the Ory Console (Agent Security)");
|
|
370
|
+
console.log(` (see the live mode: ${npx} permissions)`);
|
|
371
|
+
console.log(" 3. Stream activity live: export ORY_AGENT_DEBUG=true");
|
|
317
372
|
}
|
|
318
373
|
console.log("");
|
|
319
374
|
console.log(`To uninstall: ${npx} uninstall`);
|
|
@@ -323,18 +378,15 @@ function printNextStepsNow() {
|
|
|
323
378
|
console.log("Next steps:");
|
|
324
379
|
console.log(" 1. (Optional) Point at an Ory project — without this, the plugin");
|
|
325
380
|
console.log(" runs in pass-through mode (skills work, nothing is blocked):");
|
|
326
|
-
console.log(" npx -y -p @ory/codex ory-codex configure --project-url https://<slug>.projects.oryapis.com
|
|
327
|
-
console.log("
|
|
328
|
-
console.log("
|
|
329
|
-
console.log(" user PKCE browser flow needs a pre-registered public client. Add");
|
|
330
|
-
console.log(" `--api-key ory_pat_...` only to override the agent's auto-registered identity.)");
|
|
381
|
+
console.log(" npx -y -p @ory/codex ory-codex configure --project-url https://<slug>.projects.oryapis.com");
|
|
382
|
+
console.log(" The broker and public login client use their production defaults;");
|
|
383
|
+
console.log(" --agent-security-url and --oauth2-client-id override them.");
|
|
331
384
|
console.log("");
|
|
332
385
|
console.log(" 2. Or spin up the local Ory stack from inside Codex (`/skills` -> `ory-local-up`).");
|
|
333
386
|
console.log("");
|
|
334
|
-
console.log(" 3.
|
|
387
|
+
console.log(" 3. For a custom deployment, override the per-session login client:");
|
|
335
388
|
console.log(" export ORY_OAUTH2_CLIENT_ID=<public OAuth2 client id>");
|
|
336
|
-
console.log("
|
|
337
|
-
console.log(" human Ory identity attached and permission checks fall back to a session:<id> subject.");
|
|
389
|
+
console.log(" Otherwise user login uses the reserved ory-agent-security-login client.");
|
|
338
390
|
console.log("");
|
|
339
391
|
console.log(" 4. Start a Codex session. Codex treats freshly installed plugin");
|
|
340
392
|
console.log(" hooks as untrusted, so it will prompt you to review and trust");
|
|
@@ -371,7 +423,10 @@ refreshes Codex's cache copy on the next session.
|
|
|
371
423
|
uninstall(args);
|
|
372
424
|
// Direct `-setup --uninstall` path: also clear stored Ory credentials.
|
|
373
425
|
// (The `ory-codex uninstall` command handles this itself.)
|
|
374
|
-
(0, argus_1.clearCredentialsForUninstall)(
|
|
426
|
+
(0, argus_1.clearCredentialsForUninstall)({
|
|
427
|
+
harness: "codex",
|
|
428
|
+
purge: process.argv.includes("--purge"),
|
|
429
|
+
}).then(() => process.exit(0), (err) => {
|
|
375
430
|
console.error(err.message ?? err);
|
|
376
431
|
process.exit(1);
|
|
377
432
|
});
|