@ory/claude-code 0.1.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.
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "ory-plugins",
3
+ "owner": {
4
+ "name": "Ory"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "ory-claude",
9
+ "source": "./",
10
+ "category": "development"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "ory-claude",
3
+ "version": "0.1.0",
4
+ "description": "Ory authentication and authorization for Claude Code — session auth, tool permissions, and audit logging",
5
+ "author": {
6
+ "name": "Ory",
7
+ "url": "https://ory.com"
8
+ },
9
+ "homepage": "https://github.com/ory/claude-plugins"
10
+ }
package/.mcp.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "description": "Ory Claude Code MCP Server",
3
+ "mcpServers": {
4
+ "ory-claude-mcp": {
5
+ "command": "npx",
6
+ "args": [
7
+ "-y",
8
+ "@ory/mcp-server"
9
+ ]
10
+ }
11
+ }
12
+ }
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # Ory Agent Plugin: Claude Code
2
+
3
+ [Ory](https://ory.com) bundled into [Claude Code](https://docs.anthropic.com/en/docs/claude-code): skills and slash commands that scaffold Ory authentication into your codebase, a local Ory stack you can spin up in one command, and (when pointed at an Ory project) authentication, authorization, and audit for every tool Claude runs.
4
+
5
+ ## Install
6
+
7
+ From inside Claude Code. Try these in order; the first that works is the simplest path:
8
+
9
+ **1. Anthropic's public plugin marketplace.** Find **Ory Agent Plugin** and install:
10
+
11
+ ```
12
+ /plugin install ory-agent-plugin
13
+ ```
14
+
15
+ **2. The Ory-hosted marketplace:**
16
+
17
+ ```
18
+ /plugin marketplace add ory/claude-plugins
19
+ /plugin install ory-claude@ory-plugins
20
+ ```
21
+
22
+ **3. The Ory installer.** No prior `npm install` required:
23
+
24
+ ```bash
25
+ npx @ory/claude-code install # current project
26
+ npx @ory/claude-code install --global # all projects (user scope)
27
+ npx @ory/claude-code uninstall
28
+ ```
29
+
30
+ Every flow registers the same plugin: skills, slash commands, hooks, and the Ory MCP server.
31
+
32
+ ## Developer experience
33
+
34
+ This plugin is a productivity layer for Ory itself. You don't need a real Ory project, an account, or any prior Ory experience to start using it.
35
+
36
+ ### Skills for scaffolding Ory into your application
37
+
38
+ Ask Claude to add Ory auth to your codebase, or invoke the slash commands directly. Each skill is a vetted, end-to-end playbook:
39
+
40
+ - **`/ory:auth-setup`**: full project setup. Install the Ory CLI, create an Ory Network project, add Ory Elements, configure the SDK, build the auth pages, wire session middleware.
41
+ - **`/ory:login-flow`**: login, registration, recovery, verification, and settings pages with Ory Elements. Next.js App Router and React SPA variants.
42
+ - **`/ory:social-login`**: Google, GitHub, Apple, Microsoft, Discord, and other OIDC providers with Jsonnet data mappers.
43
+ - **`/ory:local-dev`**: drive the local Ory stack (below) from within Claude to prototype and test against without a remote project.
44
+
45
+ Skills are versioned with the plugin so guidance stays in sync as Ory APIs evolve.
46
+
47
+ ### Ory MCP server
48
+
49
+ Bundled and registered automatically. It exposes the Ory CLI and the Ory Network REST API as MCP tools so Claude can manage identities, OAuth2 clients, projects, permission tuples, and configuration without ever leaving the chat. Useful for seeding test data, verifying a scaffolded integration, or running one-off admin tasks.
50
+
51
+ ### Local Ory stack in one command
52
+
53
+ ```
54
+ /ory:local-up # start a local Ory instance in Docker
55
+ /ory:local-down # tear it all down
56
+ ```
57
+
58
+ `local up` runs a local Ory instance in Docker, covering everything the plugin and your scaffolded application need. It also brings up a login UI on `:3000` and Jaeger on `:16686`, all reachable through `http://localhost:4000`. A test user identity is seeded and the credentials are printed for you. Use it to:
59
+
60
+ - **Learn Ory hands-on** without signing up for a hosted project.
61
+ - **Prototype** flows (login, social, MFA, recovery, permission tuples) against a real Ory backend in your local dev loop.
62
+ - **Test** an auth integration end-to-end before pushing anything to a real environment.
63
+ - **Develop** your application against the same identity, OAuth2, and permission surfaces you'll ship with.
64
+
65
+ Point `ORY_PROJECT_URL` at `http://localhost:4000` (or run `npx ory-claude configure`) and the security features below run against the local stack.
66
+
67
+ ## Configure
68
+
69
+ ```bash
70
+ npx ory-claude configure --project-url https://<id>.projects.oryapis.com --api-key ory_pat_...
71
+ ```
72
+
73
+ Config is saved to `~/.config/ory-agent-plugins/config.json` and shared across every Ory agent plugin on the machine. Without it the plugin still loads cleanly and runs in **pass-through mode**: skills and commands work, but nothing is blocked.
74
+
75
+ ## Agent security (Argus)
76
+
77
+ Once the plugin is pointed at an Ory project (local or hosted), Claude's session and every tool call are governed by Ory.
78
+
79
+ - **Authentication.** Two identities. The human at the keyboard (the **user**) authenticates interactively via Ory Identities when `ORY_AUTH_GATE=1`. The Claude process (the **agent**) gets its own OAuth2 identity, self-registered via Dynamic Client Registration on first run. Sub-agents launched by the `Task` tool each receive their own typed identity.
80
+ - **Authorization.** Before any tool runs, the plugin checks Ory Permissions against the user's subject and blocks the call on `deny`. MCP tool calls additionally get a server-level check.
81
+ - **Audit.** Every decision (allow, deny, fallback) is recorded as a structured trace span: NDJSON file output and/or OTLP/HTTP export to Jaeger, Honeycomb, Grafana, and similar collectors. The user-to-agent (and agent-to-subagent) delegation chain is written to Ory as Zanzibar tuples so "agent X acting on behalf of user Y" stays queryable after tokens expire.
82
+
83
+ The plugin is **fail-open** on its own infrastructure failures (network errors, rate limits, missing config), so enforcement is only as strong as your tuples; grant explicit `invoke` relations for the tools each user should be able to run.
84
+
85
+ ## CLI
86
+
87
+ ```
88
+ npx ory-claude install | uninstall [--global]
89
+ npx ory-claude configure [--project-url <url>] [--api-key <key>] [--audit-only]
90
+ npx ory-claude agent <status|unregister> Manage the agent's OAuth2 identity
91
+ npx ory-claude local <up|down|status|seed|logs|env|configure|reset>
92
+ npx ory-claude status
93
+ ```
94
+
95
+ ## Links
96
+
97
+ - [ory.com](https://ory.com)
98
+
99
+ ## License
100
+
101
+ Apache-2.0
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Main CLI for @ory/claude-code.
4
+ *
5
+ * Usage:
6
+ * npx ory-claude install [--global] Install plugin via claude CLI marketplace
7
+ * npx ory-claude uninstall [--global] Remove plugin via claude CLI marketplace
8
+ * npx ory-claude configure Set or view Ory project URL and API key
9
+ * npx ory-claude status Show plugin status
10
+ * npx ory-claude local <cmd> Manage local Ory dev environment
11
+ */
12
+ export {};
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Main CLI for @ory/claude-code.
5
+ *
6
+ * Usage:
7
+ * npx ory-claude install [--global] Install plugin via claude CLI marketplace
8
+ * npx ory-claude uninstall [--global] Remove plugin via claude CLI marketplace
9
+ * npx ory-claude configure Set or view Ory project URL and API key
10
+ * npx ory-claude status Show plugin status
11
+ * npx ory-claude local <cmd> Manage local Ory dev environment
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ const path = __importStar(require("node:path"));
48
+ const fs = __importStar(require("node:fs"));
49
+ const argus_1 = require("@ory/argus");
50
+ const setup_js_1 = require("./setup.js");
51
+ const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
52
+ const PERSISTENT_DIR = (0, argus_1.getHarnessDataDir)("claude-code");
53
+ function main() {
54
+ const [command, ...args] = process.argv.slice(2);
55
+ switch (command) {
56
+ case "install":
57
+ (0, setup_js_1.install)(args);
58
+ break;
59
+ case "uninstall":
60
+ (0, setup_js_1.uninstall)(args);
61
+ break;
62
+ case "configure":
63
+ (0, argus_1.runConfigureCommand)("ory-claude", args);
64
+ break;
65
+ case "agent":
66
+ (0, argus_1.runAgentCommand)("ory-claude", args).then((code) => process.exit(code), (err) => {
67
+ console.error(err.message ?? err);
68
+ process.exit(1);
69
+ });
70
+ break;
71
+ case "status":
72
+ status();
73
+ break;
74
+ case "local":
75
+ (0, argus_1.runLocalCommand)("ory-claude", args).catch((err) => {
76
+ console.error(err.message ?? err);
77
+ process.exit(1);
78
+ });
79
+ break;
80
+ case "help":
81
+ case "--help":
82
+ case "-h":
83
+ case undefined:
84
+ help();
85
+ break;
86
+ default:
87
+ console.error(`Unknown command: ${command}`);
88
+ help();
89
+ process.exit(1);
90
+ }
91
+ }
92
+ function status() {
93
+ console.log("Ory Agent Plugin Status (Claude Code)");
94
+ console.log("======================================");
95
+ console.log("");
96
+ (0, argus_1.printOryConfig)();
97
+ (0, argus_1.printEnvironment)();
98
+ // Plugin-specific status
99
+ console.log("");
100
+ console.log("Plugin:");
101
+ const assembled = fs.existsSync(PERSISTENT_DIR);
102
+ console.log(` Plugin directory: ${assembled ? PERSISTENT_DIR : "(not installed — run: npx ory-claude install)"}`);
103
+ console.log(` Skills: ${assembled && fs.existsSync(path.join(PERSISTENT_DIR, "skills")) ? "installed" : "not installed"}`);
104
+ console.log(` Hook script: ${fs.existsSync(path.join(PACKAGE_ROOT, "dist", "hook.js")) ? "built" : "NOT BUILT (run pnpm build)"}`);
105
+ (0, argus_1.printLogTail)();
106
+ }
107
+ function help() {
108
+ console.log(`
109
+ ory-claude — Ory plugin for Claude Code
110
+
111
+ Usage:
112
+ npx @ory/claude-code <command> [options]
113
+ npx ory-claude <command> [options]
114
+
115
+ Commands:
116
+ install [--global] Install Ory plugin via claude CLI marketplace
117
+ uninstall [--global] Remove Ory plugin and marketplace
118
+ configure Set or view Ory project URL and API key
119
+ status Show plugin status and configuration
120
+ local <cmd> Manage local Ory dev environment (up, down, status, seed, ...)
121
+
122
+ Examples:
123
+ npx @ory/claude-code install # Install remotely (no prior npm install needed)
124
+ npx @ory/claude-code install --global # Install globally (user scope)
125
+ npx ory-claude install # Install from local/global npm installation
126
+ npx ory-claude configure --project-url https://your-project.projects.oryapis.com --api-key ory_pat_...
127
+ npx ory-claude status # Check configuration
128
+ npx ory-claude uninstall # Remove plugin
129
+ `);
130
+ }
131
+ main();
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Setup CLI for the Ory Claude Code plugin.
4
+ *
5
+ * Uses the `claude` CLI to manage plugin installation via the marketplace:
6
+ * npx ory-claude-setup # Install plugin (project scope)
7
+ * npx ory-claude-setup --global # Install plugin (user scope)
8
+ * npx ory-claude-setup --uninstall # Remove plugin
9
+ */
10
+ /**
11
+ * Install the Ory plugin via the `claude` CLI.
12
+ *
13
+ * 1. Assembles the plugin directory (manifest, skills, commands, hooks, MCP)
14
+ * 2. Adds the Ory marketplace (pointing to that directory)
15
+ * 3. Installs the plugin from that marketplace
16
+ *
17
+ * Hooks, skills, commands, and the MCP server are picked up automatically
18
+ * from the assembled directory by the Claude Code plugin system.
19
+ */
20
+ export declare function install(args: string[]): void;
21
+ /**
22
+ * Uninstall the Ory plugin via the `claude` CLI.
23
+ *
24
+ * 1. Uninstalls the plugin
25
+ * 2. Removes the Ory marketplace
26
+ * 3. Cleans up the assembled plugin directory
27
+ */
28
+ export declare function uninstall(args: string[]): void;
@@ -0,0 +1,297 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Setup CLI for the Ory Claude Code plugin.
5
+ *
6
+ * Uses the `claude` CLI to manage plugin installation via the marketplace:
7
+ * npx ory-claude-setup # Install plugin (project scope)
8
+ * npx ory-claude-setup --global # Install plugin (user scope)
9
+ * npx ory-claude-setup --uninstall # Remove plugin
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.install = install;
46
+ exports.uninstall = uninstall;
47
+ const node_child_process_1 = require("node:child_process");
48
+ const fs = __importStar(require("node:fs"));
49
+ const path = __importStar(require("node:path"));
50
+ const argus_1 = require("@ory/argus");
51
+ const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
52
+ const MARKETPLACE_NAME = "ory-plugins";
53
+ const PLUGIN_NAME = "ory-claude";
54
+ const RENDER_OPTS = {
55
+ binName: "ory-claude",
56
+ packageName: "@ory/claude-code",
57
+ };
58
+ /**
59
+ * Persistent install location used as the marketplace root. Lives under the
60
+ * shared OS-agnostic data dir so all plugin state — config, DCR creds, harness
61
+ * assets — sits in one place per platform. The plugin directory is assembled
62
+ * here for both local and remote installs so the marketplace never points at
63
+ * (or writes into) the package source tree.
64
+ */
65
+ const PERSISTENT_DIR = (0, argus_1.getHarnessDataDir)("claude-code");
66
+ /** Hook command that resolves the binary via the npm registry. */
67
+ const HOOK_CMD_REMOTE = "npx -y -p @ory/claude-code ory-claude-hook";
68
+ /**
69
+ * Detect if we're running from a temporary npx/pnpm-dlx cache directory
70
+ * rather than a proper local or global npm installation.
71
+ */
72
+ function isRemoteContext() {
73
+ const normalized = PACKAGE_ROOT.replace(/\\/g, "/");
74
+ return normalized.includes("/_npx/") || normalized.includes("/dlx-");
75
+ }
76
+ /** Hook command for a local/global install — runs the built hook directly. */
77
+ function localHookCommand() {
78
+ return `node ${path.join(PACKAGE_ROOT, "dist", "hook.js")}`;
79
+ }
80
+ /**
81
+ * Assemble the Claude Code plugin directory in the persistent location and
82
+ * return its path (used as the marketplace root).
83
+ *
84
+ * The plugin manifest (`.claude-plugin/`) and MCP config (`.mcp.json`) are
85
+ * copied from the package; the skills, commands, and hooks are generated:
86
+ * skills/commands are materialized from the shared `@ory/argus` templates (the
87
+ * single source of truth across every harness), and `hooks.json` is written
88
+ * with a hook command appropriate for the install context.
89
+ */
90
+ function assemblePluginDir(hookCommand) {
91
+ fs.mkdirSync(PERSISTENT_DIR, { recursive: true });
92
+ // Static manifests copied straight from the package.
93
+ for (const asset of [".claude-plugin", ".mcp.json"]) {
94
+ const src = path.join(PACKAGE_ROOT, asset);
95
+ if (fs.existsSync(src)) {
96
+ fs.cpSync(src, path.join(PERSISTENT_DIR, asset), {
97
+ recursive: true,
98
+ force: true,
99
+ });
100
+ }
101
+ }
102
+ // Skills — materialized fresh from the shared core templates.
103
+ const skillsDir = path.join(PERSISTENT_DIR, "skills");
104
+ fs.rmSync(skillsDir, { recursive: true, force: true });
105
+ (0, argus_1.writeSkillTree)(skillsDir, (0, argus_1.renderOrySkills)("claude-code", RENDER_OPTS));
106
+ // Commands — plain markdown command files (Claude Code's `/ory:<name>`).
107
+ const commandsDir = path.join(PERSISTENT_DIR, "commands");
108
+ fs.rmSync(commandsDir, { recursive: true, force: true });
109
+ fs.mkdirSync(commandsDir, { recursive: true });
110
+ for (const cmd of (0, argus_1.renderOryCommands)("claude-code", RENDER_OPTS)) {
111
+ fs.writeFileSync(path.join(commandsDir, `${cmd.slug}.md`), (0, argus_1.commandToPlainMarkdown)(cmd));
112
+ }
113
+ // Hooks — generated with a command appropriate for the install context.
114
+ const hooksDir = path.join(PERSISTENT_DIR, "hooks");
115
+ fs.mkdirSync(hooksDir, { recursive: true });
116
+ const entry = [
117
+ { matcher: "", hooks: [{ type: "command", command: hookCommand }] },
118
+ ];
119
+ fs.writeFileSync(path.join(hooksDir, "hooks.json"), JSON.stringify({
120
+ description: "Ory Claude Code Hooks",
121
+ hooks: {
122
+ SessionStart: entry,
123
+ SessionEnd: entry,
124
+ UserPromptSubmit: entry,
125
+ PreToolUse: entry,
126
+ PostToolUse: entry,
127
+ PostToolUseFailure: entry,
128
+ SubagentStart: entry,
129
+ SubagentStop: entry,
130
+ PermissionRequest: entry,
131
+ },
132
+ }, null, 2) + "\n");
133
+ return PERSISTENT_DIR;
134
+ }
135
+ /** Remove the persistent install directory if it exists. */
136
+ function cleanPersistentDir() {
137
+ if (fs.existsSync(PERSISTENT_DIR)) {
138
+ fs.rmSync(PERSISTENT_DIR, { recursive: true, force: true });
139
+ console.log(` Removed ${PERSISTENT_DIR}`);
140
+ }
141
+ }
142
+ /** Map --global flag to the claude CLI's scope values. */
143
+ function claudeScope(isGlobal) {
144
+ return isGlobal ? "user" : "project";
145
+ }
146
+ /** Run a `claude` CLI command and capture output. */
147
+ function runClaude(args) {
148
+ const result = (0, node_child_process_1.spawnSync)("claude", args, {
149
+ encoding: "utf-8",
150
+ stdio: ["pipe", "pipe", "pipe"],
151
+ });
152
+ const output = ((result.stdout ?? "") + (result.stderr ?? "")).trim();
153
+ return { ok: result.status === 0, output };
154
+ }
155
+ /** Check that the `claude` CLI is available. */
156
+ function checkClaudeCli() {
157
+ const result = (0, node_child_process_1.spawnSync)("claude", ["--version"], {
158
+ encoding: "utf-8",
159
+ stdio: ["pipe", "pipe", "pipe"],
160
+ });
161
+ return result.status === 0;
162
+ }
163
+ /**
164
+ * Install the Ory plugin via the `claude` CLI.
165
+ *
166
+ * 1. Assembles the plugin directory (manifest, skills, commands, hooks, MCP)
167
+ * 2. Adds the Ory marketplace (pointing to that directory)
168
+ * 3. Installs the plugin from that marketplace
169
+ *
170
+ * Hooks, skills, commands, and the MCP server are picked up automatically
171
+ * from the assembled directory by the Claude Code plugin system.
172
+ */
173
+ function install(args) {
174
+ const isGlobal = args.includes("--global");
175
+ const scope = claudeScope(isGlobal);
176
+ if (!checkClaudeCli()) {
177
+ console.error("Error: 'claude' CLI not found in PATH.");
178
+ console.error("Install Claude Code first: https://docs.anthropic.com/en/docs/claude-code");
179
+ process.exit(1);
180
+ }
181
+ const remote = isRemoteContext();
182
+ console.log("Assembling Ory plugin (skills, commands, hooks, MCP) at:");
183
+ console.log(` ${PERSISTENT_DIR}`);
184
+ const pluginRoot = assemblePluginDir(remote ? HOOK_CMD_REMOTE : localHookCommand());
185
+ // Step 1: Add the Ory marketplace
186
+ console.log("Adding Ory plugin marketplace...");
187
+ const addResult = runClaude([
188
+ "plugin",
189
+ "marketplace",
190
+ "add",
191
+ pluginRoot,
192
+ "--scope",
193
+ scope,
194
+ ]);
195
+ if (!addResult.ok) {
196
+ if (addResult.output.toLowerCase().includes("already")) {
197
+ console.log(" Marketplace already registered, updating...");
198
+ runClaude(["plugin", "marketplace", "update", MARKETPLACE_NAME]);
199
+ }
200
+ else {
201
+ console.error(`Failed to add marketplace: ${addResult.output}`);
202
+ process.exit(1);
203
+ }
204
+ }
205
+ else {
206
+ console.log(" Marketplace added.");
207
+ }
208
+ // Step 2: Install the plugin from the marketplace
209
+ console.log("Installing ory-claude plugin...");
210
+ const installResult = runClaude([
211
+ "plugin",
212
+ "install",
213
+ `${PLUGIN_NAME}@${MARKETPLACE_NAME}`,
214
+ "--scope",
215
+ scope,
216
+ ]);
217
+ if (!installResult.ok) {
218
+ console.error(`Failed to install plugin: ${installResult.output}`);
219
+ process.exit(1);
220
+ }
221
+ console.log(" Plugin installed.");
222
+ (0, argus_1.printNextSteps)("Claude Code", remote ? "npx @ory/claude-code uninstall" : "npx ory-claude uninstall");
223
+ }
224
+ /**
225
+ * Uninstall the Ory plugin via the `claude` CLI.
226
+ *
227
+ * 1. Uninstalls the plugin
228
+ * 2. Removes the Ory marketplace
229
+ * 3. Cleans up the assembled plugin directory
230
+ */
231
+ function uninstall(args) {
232
+ const isGlobal = args.includes("--global");
233
+ const scope = claudeScope(isGlobal);
234
+ if (!checkClaudeCli()) {
235
+ console.error("Error: 'claude' CLI not found in PATH.");
236
+ process.exit(1);
237
+ }
238
+ // Step 1: Uninstall the plugin
239
+ console.log("Uninstalling ory-claude plugin...");
240
+ const uninstallResult = runClaude([
241
+ "plugin",
242
+ "uninstall",
243
+ PLUGIN_NAME,
244
+ "--scope",
245
+ scope,
246
+ ]);
247
+ if (!uninstallResult.ok) {
248
+ console.warn(` Warning: ${uninstallResult.output}`);
249
+ }
250
+ else {
251
+ console.log(" Plugin uninstalled.");
252
+ }
253
+ // Step 2: Remove the marketplace
254
+ console.log("Removing Ory plugin marketplace...");
255
+ const removeResult = runClaude([
256
+ "plugin",
257
+ "marketplace",
258
+ "remove",
259
+ MARKETPLACE_NAME,
260
+ ]);
261
+ if (!removeResult.ok) {
262
+ console.warn(` Warning: ${removeResult.output}`);
263
+ }
264
+ else {
265
+ console.log(" Marketplace removed.");
266
+ }
267
+ // Step 3: Clean up the assembled plugin directory.
268
+ cleanPersistentDir();
269
+ }
270
+ // --- Standalone binary entry point (ory-claude-setup) ---
271
+ if (require.main === module) {
272
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
273
+ console.log(`
274
+ ory-claude-setup — Install or remove the Ory plugin for Claude Code
275
+
276
+ Usage:
277
+ npx ory-claude-setup [options]
278
+
279
+ Options:
280
+ --global Install to user scope (default: project scope)
281
+ --uninstall Remove the Ory plugin and marketplace
282
+ -h, --help Show this help
283
+
284
+ Uses the 'claude' CLI to manage plugins via the marketplace system.
285
+ The plugin's skills, commands, hooks, and MCP server are configured
286
+ automatically.
287
+ `);
288
+ process.exit(0);
289
+ }
290
+ const args = process.argv.slice(2);
291
+ if (args.includes("--uninstall")) {
292
+ uninstall(args);
293
+ }
294
+ else {
295
+ install(args);
296
+ }
297
+ }
@@ -0,0 +1,14 @@
1
+ import { OryAgentClient, ensureUserAuthenticated, ensureAgentIdentity, ensureSubAgentIdentity } from "@ory/argus";
2
+ import type { ClaudeCodeHookInput, ClaudeCodeHookOutput } from "./types.js";
3
+ export interface HandleHookEventDeps {
4
+ /** Test injection point for the user auth gate. */
5
+ authGate?: typeof ensureUserAuthenticated;
6
+ /** Test injection point for the agent identity gate. */
7
+ agentGate?: typeof ensureAgentIdentity;
8
+ /** Test injection point for the sub-agent identity resolver. */
9
+ subAgentGate?: typeof ensureSubAgentIdentity;
10
+ }
11
+ /**
12
+ * Route a Claude Code hook event to the appropriate Ory integration.
13
+ */
14
+ export declare function handleHookEvent(input: ClaudeCodeHookInput, client: OryAgentClient, deps?: HandleHookEventDeps): Promise<ClaudeCodeHookOutput>;