@ory/amp 0.10.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 ADDED
@@ -0,0 +1,120 @@
1
+ # Ory Agent Plugin: Amp
2
+
3
+ [Ory](https://ory.com) bundled into [Amp](https://ampcode.com) (Sourcegraph's coding agent): skills 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 Amp runs.
4
+
5
+ You don't need an Ory account or any prior Ory experience to start.
6
+
7
+ ## New to Ory?
8
+
9
+ [Ory](https://www.ory.com/docs/) is an open-source identity and access platform — login, registration, sessions, social sign-in, multi-factor auth, and fine-grained permissions, so you don't have to build any of that yourself. Two things make it easy to try with no prior experience:
10
+
11
+ - **Ory Elements** are prebuilt, themeable UI components for the auth pages. The scaffolding skills wire them into your app for you.
12
+ - **The local Ory stack** is a complete Ory running on your laptop in Docker — no account, no signup, no API key.
13
+
14
+ ## What this plugin does
15
+
16
+ Two independent things, and you can use either on its own:
17
+
18
+ 1. **Build auth into your app.** Have Amp scaffold Ory login, registration, social sign-in, and permissions into the project you're working on, backed by the local stack. This needs nothing but Docker.
19
+ 2. **Govern the agent itself.** Authenticate Amp's own session and authorize every tool it runs against Ory Permissions, with a full audit trail. See [Agent security](#agent-security).
20
+
21
+ ## Prerequisites
22
+
23
+ - [Amp](https://ampcode.com) installed
24
+ - Node.js **≥ 22**
25
+ - [Docker](https://docs.docker.com/get-docker/) (only needed for the local Ory stack)
26
+ - macOS or Linux. Windows works via WSL2.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ npx -y -p @ory/amp ory-amp install
32
+ ```
33
+
34
+ `install` performs two registrations and materializes the Ory skills:
35
+
36
+ 1. Registers the Ory **permission delegate** in Amp's settings (`~/.config/amp/settings.json`) under the flat top-level `amp.permissions` key as `{ tool: "*", action: "delegate", to: "ory-amp-permission" }` — this is the blocking gate.
37
+ 2. Writes the **in-process plugin** loader at `<project>/.amp/plugins/ory.ts` so Amp's Bun TypeScript runtime discovers it for session auth and audit tracing.
38
+
39
+ The Ory skill playbooks land under `<project>/.agents/skills/` (Amp's project skills directory).
40
+
41
+ ```bash
42
+ npx -y -p @ory/amp ory-amp status # confirm delegate + plugin registration
43
+ npx -y -p @ory/amp ory-amp uninstall # remove the delegate, plugin, and skills
44
+ ```
45
+
46
+ `status` prints configuration, user and agent identity, per-tool permission coverage, whether the delegate and in-process plugin are registered, and a tail of recent debug logs.
47
+
48
+ ## Quickstart (≈ 3 minutes)
49
+
50
+ From any project where you'd like Ory authentication, inside Amp:
51
+
52
+ 1. **Start a local Ory instance.** Ask Amp *"start the local Ory stack"* or run `/local-up`. A banner prints the seeded test user's email and password — note them.
53
+ 2. **Scaffold Ory into your project.** Ask Amp *"add Ory auth to this app"* (the `ory-auth-setup` skill). It installs Ory Elements, wires the SDK, and generates the login / registration / recovery / settings pages, all targeting the local stack.
54
+ 3. **Sign in.** Start your app, visit the login page, and sign in with the seeded credentials. You now have a real Ory session backed by a real Ory stack — locally, offline, zero configuration.
55
+
56
+ Continue to [Agent security](#agent-security) when you're ready to enforce.
57
+
58
+ ## How the integration works
59
+
60
+ Amp's Ory integration is a **hybrid** of two mechanisms:
61
+
62
+ - **Blocking gate — a permission delegate helper (`ory-amp-permission`).** Registered in `amp.permissions`, Amp invokes it per tool call with the tool params on stdin and decides by **exit code**: `0` = allow, `1` = ask, `≥2` = reject (stderr is surfaced to the model). This is the only part that can block. Amp enforces a 10-second delegate timeout, so the Ory check fails open (allows) on slow or unreachable backends.
63
+ - **Advisory in-process plugin (`.amp/plugins/ory.ts`).** Discovered by Amp's Bun runtime, it handles session-start auth (advisory — it cannot hard-block at session start) and post-tool audit tracing.
64
+
65
+ The phases map as:
66
+
67
+ - **Session start** (in-process plugin) — run the user and agent auth gates; advisory.
68
+ - **Per-tool decision** (delegate) — check the tool against Ory Permissions; in enforce mode a deny exits `2` (reject), in observe mode it records a `permission.observe_deny` span and allows (exit `0`).
69
+ - **Post-tool** (in-process plugin) — trace-only audit spans.
70
+
71
+ The plugin is **fail-open** on its own infrastructure failures (network errors, rate limits, missing config): the agent always starts, and enforcement is only as strong as your permission grants.
72
+
73
+ ## Agent security
74
+
75
+ Once pointed at an Ory project (local or hosted), Amp's session and every tool call can be governed by Ory.
76
+
77
+ - **Authentication.** The human at the keyboard (the **user**) authenticates interactively via Ory Identities when user login is on (`ORY_USER_LOGIN=true`, off by default — browser PKCE flow on first session, persisted thereafter). The Amp process (the **agent**) gets its own OAuth2 identity via [Dynamic Client Registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591) on first run.
78
+ - **Authorization.** Before any tool runs, the delegate checks [Ory Permissions](https://www.ory.com/docs/keto) (Zanzibar-style relations) against the user's subject and rejects on `deny`.
79
+ - **Audit.** Every decision is recorded as a structured trace span (NDJSON file and/or OTLP export).
80
+
81
+ ### Permission modes: observe → enforce
82
+
83
+ After install the integration runs in **observe mode**: every tool call is checked, but a deny is recorded as a `permission.observe_deny` audit span and the tool runs anyway.
84
+
85
+ ```bash
86
+ # Grant the current user `use` on every built-in tool (idempotent):
87
+ npx -y -p @ory/amp ory-amp permissions bootstrap
88
+
89
+ # See allowed/denied per tool:
90
+ npx -y -p @ory/amp ory-amp permissions status
91
+
92
+ # Turn on hard blocking once the observe-mode logs look right:
93
+ npx -y -p @ory/amp ory-amp permissions enforce
94
+ ```
95
+
96
+ Switch back any time with `permissions observe`. To disable Ory entirely (audit logging only), run `ory-amp configure --audit-only`.
97
+
98
+ ## Pointing at a real Ory project
99
+
100
+ The Quickstart uses the local stack. To point at a hosted [Ory Network](https://console.ory.sh) project:
101
+
102
+ ```bash
103
+ npx -y -p @ory/amp ory-amp configure \
104
+ --project-url https://<id>.projects.oryapis.com \
105
+ --oauth2-client-id <public OAuth2 client id>
106
+ ```
107
+
108
+ `--oauth2-client-id` is required whenever `--project-url` is set — the user PKCE flow needs a public OAuth2 client registered with the four loopback redirect URIs (`http://127.0.0.1:47823..47826/callback`). See the [repo README](../../README.md) and [`AGENTS.md`](../../AGENTS.md) for the full environment-variable reference and permission-mode semantics. Config is shared across every Ory agent plugin at `~/.config/ory-agent-plugins/config.json`.
109
+
110
+ Without configuration the plugin still loads cleanly and runs in **pass-through mode**: skills work, but nothing is blocked.
111
+
112
+ ## Links
113
+
114
+ - [Ory documentation](https://www.ory.com/docs/)
115
+ - [Amp documentation](https://ampcode.com)
116
+ - [Repo README](../../README.md) and [AGENTS.md](../../AGENTS.md) — full env-var and permission-mode reference
117
+
118
+ ## License
119
+
120
+ Apache-2.0
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Materialize / clean the Ory skill catalog and command playbooks for the
3
+ * Amp plugin.
4
+ *
5
+ * Amp discovers project skills under `<projectDir>/.agents/skills/<name>/SKILL.md`
6
+ * (note `.agents`, not `.amp`; the amp-specific path is the user-global
7
+ * `~/.config/amp/skills/`). It has no project-scoped slash-command system, so
8
+ * the local-stack commands (local-up, local-down, temporal-up) are wrapped
9
+ * with `commandToSkill` and written alongside the guide skills as
10
+ * user-invocable skills — the same approach Codex and OpenClaw use.
11
+ */
12
+ /**
13
+ * Write all Ory guide skills plus the command playbooks (wrapped as
14
+ * skills) under `<projectDir>/.agents/skills/`.
15
+ */
16
+ export declare function installAmpOryAssets(projectDir: string): void;
17
+ /** Remove every skill + command-skill this plugin installed. */
18
+ export declare function uninstallAmpOryAssets(projectDir: string): void;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * Materialize / clean the Ory skill catalog and command playbooks for the
4
+ * Amp plugin.
5
+ *
6
+ * Amp discovers project skills under `<projectDir>/.agents/skills/<name>/SKILL.md`
7
+ * (note `.agents`, not `.amp`; the amp-specific path is the user-global
8
+ * `~/.config/amp/skills/`). It has no project-scoped slash-command system, so
9
+ * the local-stack commands (local-up, local-down, temporal-up) are wrapped
10
+ * with `commandToSkill` and written alongside the guide skills as
11
+ * user-invocable skills — the same approach Codex and OpenClaw use.
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
+ exports.installAmpOryAssets = installAmpOryAssets;
48
+ exports.uninstallAmpOryAssets = uninstallAmpOryAssets;
49
+ const fs = __importStar(require("node:fs"));
50
+ const path = __importStar(require("node:path"));
51
+ const argus_1 = require("@ory/argus");
52
+ const RENDER_OPTS = {
53
+ binName: "ory-amp",
54
+ packageName: "@ory/amp",
55
+ };
56
+ /** Amp's project skills discovery directory: `<projectDir>/.agents/skills`. */
57
+ function skillsRoot(projectDir) {
58
+ return path.join(projectDir, ".agents", "skills");
59
+ }
60
+ /**
61
+ * Write all Ory guide skills plus the command playbooks (wrapped as
62
+ * skills) under `<projectDir>/.agents/skills/`.
63
+ */
64
+ function installAmpOryAssets(projectDir) {
65
+ const skillsDir = skillsRoot(projectDir);
66
+ fs.mkdirSync(skillsDir, { recursive: true });
67
+ const guideSkills = (0, argus_1.renderOrySkills)("amp", RENDER_OPTS);
68
+ const commandSkills = (0, argus_1.renderOryCommands)("amp", RENDER_OPTS).map(argus_1.commandToSkill);
69
+ (0, argus_1.writeSkillTree)(skillsDir, [...guideSkills, ...commandSkills]);
70
+ }
71
+ function safeRmEmpty(dir) {
72
+ try {
73
+ if (fs.existsSync(dir) && fs.readdirSync(dir).length === 0) {
74
+ fs.rmdirSync(dir);
75
+ }
76
+ }
77
+ catch {
78
+ /* ignore — leave the dir if removal fails. */
79
+ }
80
+ }
81
+ /** Remove every skill + command-skill this plugin installed. */
82
+ function uninstallAmpOryAssets(projectDir) {
83
+ const skillsDir = skillsRoot(projectDir);
84
+ if (!fs.existsSync(skillsDir))
85
+ return;
86
+ (0, argus_1.removeSkillDirs)(skillsDir, argus_1.ORY_SKILL_NAMES);
87
+ (0, argus_1.removeSkillDirs)(skillsDir, argus_1.ORY_COMMAND_SKILL_NAMES);
88
+ safeRmEmpty(skillsDir);
89
+ // Clean up the parent `.agents` dir if we emptied it.
90
+ safeRmEmpty(path.dirname(skillsDir));
91
+ }
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Main CLI for @ory/amp.
4
+ *
5
+ * Usage:
6
+ * npx ory-amp install [--project-dir <path>] Register delegate + in-process plugin
7
+ * npx ory-amp uninstall [--project-dir <path>] Remove Ory entries
8
+ * npx ory-amp configure Set or view Ory credentials
9
+ * npx ory-amp setup [--project-dir <path>] Write config directly (fallback)
10
+ * npx ory-amp status Show plugin status
11
+ */
12
+ export {};
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Main CLI for @ory/amp.
5
+ *
6
+ * Usage:
7
+ * npx ory-amp install [--project-dir <path>] Register delegate + in-process plugin
8
+ * npx ory-amp uninstall [--project-dir <path>] Remove Ory entries
9
+ * npx ory-amp configure Set or view Ory credentials
10
+ * npx ory-amp setup [--project-dir <path>] Write config directly (fallback)
11
+ * npx ory-amp status Show plugin status
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 os = __importStar(require("node:os"));
49
+ const fs = __importStar(require("node:fs"));
50
+ const argus_1 = require("@ory/argus");
51
+ function main() {
52
+ const [command, ...args] = process.argv.slice(2);
53
+ switch (command) {
54
+ case "install":
55
+ install(args);
56
+ postInstallPermissions("ory-amp", "amp").then(() => process.exit(0), (err) => {
57
+ console.error(err.message ?? err);
58
+ process.exit(1);
59
+ });
60
+ break;
61
+ case "uninstall":
62
+ uninstall(args);
63
+ break;
64
+ case "configure":
65
+ (0, argus_1.runConfigureCommand)("ory-amp", args);
66
+ break;
67
+ case "agent":
68
+ (0, argus_1.runAgentCommand)("ory-amp", args).then((code) => process.exit(code), (err) => {
69
+ console.error(err.message ?? err);
70
+ process.exit(1);
71
+ });
72
+ break;
73
+ case "permissions":
74
+ (0, argus_1.runPermissionsCommand)("ory-amp", "amp", args).then((code) => process.exit(code), (err) => {
75
+ console.error(err.message ?? err);
76
+ process.exit(1);
77
+ });
78
+ break;
79
+ case "setup":
80
+ require("./setup.js");
81
+ break;
82
+ case "status":
83
+ status(args).then(() => process.exit(0), (err) => {
84
+ console.error(err.message ?? err);
85
+ process.exit(1);
86
+ });
87
+ break;
88
+ case "local":
89
+ (0, argus_1.runLocalCommand)("ory-amp", args).catch((err) => {
90
+ console.error(err.message ?? err);
91
+ process.exit(1);
92
+ });
93
+ break;
94
+ case "help":
95
+ case "--help":
96
+ case "-h":
97
+ case undefined:
98
+ help();
99
+ break;
100
+ default:
101
+ console.error(`Unknown command: ${command}`);
102
+ help();
103
+ process.exit(1);
104
+ }
105
+ }
106
+ /**
107
+ * Amp has no native plugin-registration CLI, so install delegates to the
108
+ * setup writer, which registers the permission delegate in Amp's settings
109
+ * and writes the in-process plugin loader at `.amp/plugins/ory.ts`.
110
+ */
111
+ function install(args) {
112
+ process.argv = ["node", "setup.js", ...args];
113
+ require("./setup.js");
114
+ (0, argus_1.printEnvHelp)("ory-amp");
115
+ }
116
+ function uninstall(args) {
117
+ process.argv = ["node", "setup.js", "--uninstall", ...args];
118
+ require("./setup.js");
119
+ }
120
+ async function postInstallPermissions(binName, harness) {
121
+ const bootstrapped = await (0, argus_1.maybeAutoBootstrap)(binName, harness);
122
+ (0, argus_1.printPermissionsOnboardingHelp)(binName, harness, {
123
+ bootstrappedAutomatically: bootstrapped,
124
+ });
125
+ }
126
+ function parseProjectDir(args) {
127
+ const idx = args.indexOf("--project-dir");
128
+ if (idx !== -1 && args[idx + 1])
129
+ return args[idx + 1];
130
+ return process.cwd();
131
+ }
132
+ async function status(args) {
133
+ const projectDir = parseProjectDir(args);
134
+ // Setup writes the delegate to Amp's user-global settings file (the
135
+ // `--settings-file` default); the in-process loader lives under the
136
+ // project's `.amp/plugins/`.
137
+ const settingsPath = path.join(os.homedir(), ".config", "amp", "settings.json");
138
+ const pluginFile = path.join(projectDir, ".amp", "plugins", "ory.ts");
139
+ await (0, argus_1.runStatusCommand)("ory-amp", "amp", {
140
+ title: "Amp",
141
+ printPluginSection: () => {
142
+ console.log("Permission delegate & plugin:");
143
+ console.log(` Settings file: ${settingsPath}`);
144
+ let delegateRegistered = false;
145
+ try {
146
+ if (fs.existsSync(settingsPath)) {
147
+ const raw = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
148
+ const perms = Array.isArray(raw["amp.permissions"])
149
+ ? raw["amp.permissions"]
150
+ : [];
151
+ delegateRegistered = perms.some((p) => p?.to === "ory-amp-permission");
152
+ }
153
+ }
154
+ catch {
155
+ /* ignore parse errors */
156
+ }
157
+ console.log(` Delegate: ${delegateRegistered ? "registered (ory-amp-permission)" : "NOT registered"}`);
158
+ console.log(` In-process plugin: ${fs.existsSync(pluginFile) ? `installed (${pluginFile})` : "not installed"}`);
159
+ },
160
+ });
161
+ }
162
+ function help() {
163
+ console.log(`
164
+ ory-amp — Ory plugin for Amp (Sourcegraph's coding agent)
165
+
166
+ Usage:
167
+ npx -y -p @ory/amp ory-amp <command> [options]
168
+
169
+ Commands:
170
+ install [--project-dir <path>] Register the permission delegate and in-process plugin
171
+ uninstall [--project-dir <path>] Remove the Ory delegate, plugin, and skills
172
+ configure Set or view Ory project URL and API key
173
+ agent <status|unregister> Manage the agent's OAuth2 (DCR) identity
174
+ permissions <cmd> Manage permission mode and tool permissions
175
+ (status, bootstrap, observe, enforce)
176
+ setup [--project-dir <path>] Write config directly (fallback)
177
+ status [--project-dir <path>] Show plugin configuration and status
178
+ local <cmd> Manage local Ory dev environment
179
+ (up, down, status, seed, logs, env, configure, reset)
180
+
181
+ After installing, the Ory integration runs in two parts:
182
+ Permission delegate (ory-amp-permission) Authorize each tool call (blocking)
183
+ In-process plugin (.amp/plugins/ory.ts) Session auth + audit tracing
184
+
185
+ Examples:
186
+ npx -y -p @ory/amp ory-amp install
187
+ npx -y -p @ory/amp ory-amp configure --project-url https://<id>.projects.oryapis.com
188
+ npx -y -p @ory/amp ory-amp permissions bootstrap
189
+ npx -y -p @ory/amp ory-amp status
190
+ `);
191
+ }
192
+ main();
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Setup CLI for the Ory Amp plugin.
4
+ *
5
+ * Performs two installs:
6
+ * (a) Registers the permission delegate in Amp's settings under
7
+ * `amp.permissions` as `{ tool: "*", action: "delegate",
8
+ * to: "ory-amp-permission" }` — this is the blocking gate.
9
+ * (b) Writes the in-process plugin loader at
10
+ * `<projectDir>/.amp/plugins/ory.ts` so Amp's Bun TypeScript runtime
11
+ * discovers it for session auth + audit tracing.
12
+ *
13
+ * Usage:
14
+ * npx ory-amp-setup # Auto-detect and configure
15
+ * npx ory-amp-setup --project-dir /path/to/repo
16
+ * npx ory-amp-setup --print # Print config to stdout without writing
17
+ * npx ory-amp-setup --uninstall # Remove Ory entries from settings + plugins
18
+ *
19
+ * Verified against the installed `amp` binary: the default settings file is
20
+ * `~/.config/amp/settings.json` (the `--settings-file` default), with a flat
21
+ * top-level `amp.permissions` array of `{ tool, action, to }`. Amp also ships
22
+ * a native `amp permissions add <action> <tool> --to <program>` command (with
23
+ * `-w/--workspace` for project scope); the equivalent registration is:
24
+ *
25
+ * amp permissions add delegate '*' --to ory-amp-permission
26
+ *
27
+ * This setup writes the same entry into settings.json directly so the flow
28
+ * works without shelling out. In-process plugins are discovered as direct
29
+ * `*.ts` files under `.amp/plugins/` (project) or `~/.config/amp/plugins/`
30
+ * (system), executed by Bun's TypeScript runtime.
31
+ */
32
+ export {};
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Setup CLI for the Ory Amp plugin.
5
+ *
6
+ * Performs two installs:
7
+ * (a) Registers the permission delegate in Amp's settings under
8
+ * `amp.permissions` as `{ tool: "*", action: "delegate",
9
+ * to: "ory-amp-permission" }` — this is the blocking gate.
10
+ * (b) Writes the in-process plugin loader at
11
+ * `<projectDir>/.amp/plugins/ory.ts` so Amp's Bun TypeScript runtime
12
+ * discovers it for session auth + audit tracing.
13
+ *
14
+ * Usage:
15
+ * npx ory-amp-setup # Auto-detect and configure
16
+ * npx ory-amp-setup --project-dir /path/to/repo
17
+ * npx ory-amp-setup --print # Print config to stdout without writing
18
+ * npx ory-amp-setup --uninstall # Remove Ory entries from settings + plugins
19
+ *
20
+ * Verified against the installed `amp` binary: the default settings file is
21
+ * `~/.config/amp/settings.json` (the `--settings-file` default), with a flat
22
+ * top-level `amp.permissions` array of `{ tool, action, to }`. Amp also ships
23
+ * a native `amp permissions add <action> <tool> --to <program>` command (with
24
+ * `-w/--workspace` for project scope); the equivalent registration is:
25
+ *
26
+ * amp permissions add delegate '*' --to ory-amp-permission
27
+ *
28
+ * This setup writes the same entry into settings.json directly so the flow
29
+ * works without shelling out. In-process plugins are discovered as direct
30
+ * `*.ts` files under `.amp/plugins/` (project) or `~/.config/amp/plugins/`
31
+ * (system), executed by Bun's TypeScript runtime.
32
+ */
33
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
34
+ if (k2 === undefined) k2 = k;
35
+ var desc = Object.getOwnPropertyDescriptor(m, k);
36
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
37
+ desc = { enumerable: true, get: function() { return m[k]; } };
38
+ }
39
+ Object.defineProperty(o, k2, desc);
40
+ }) : (function(o, m, k, k2) {
41
+ if (k2 === undefined) k2 = k;
42
+ o[k2] = m[k];
43
+ }));
44
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
45
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
46
+ }) : function(o, v) {
47
+ o["default"] = v;
48
+ });
49
+ var __importStar = (this && this.__importStar) || (function () {
50
+ var ownKeys = function(o) {
51
+ ownKeys = Object.getOwnPropertyNames || function (o) {
52
+ var ar = [];
53
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
54
+ return ar;
55
+ };
56
+ return ownKeys(o);
57
+ };
58
+ return function (mod) {
59
+ if (mod && mod.__esModule) return mod;
60
+ var result = {};
61
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
62
+ __setModuleDefault(result, mod);
63
+ return result;
64
+ };
65
+ })();
66
+ Object.defineProperty(exports, "__esModule", { value: true });
67
+ const fs = __importStar(require("node:fs"));
68
+ const os = __importStar(require("node:os"));
69
+ const path = __importStar(require("node:path"));
70
+ const argus_1 = require("@ory/argus");
71
+ const assets_js_1 = require("./assets.js");
72
+ const PACKAGE_NAME = "@ory/amp";
73
+ const DELEGATE_BIN = "ory-amp-permission";
74
+ /** Direct *.ts loader Amp's Bun runtime discovers under .amp/plugins/. */
75
+ const PLUGIN_FILE = "ory.ts";
76
+ /**
77
+ * Read the plugin's own version, walking up from dist/cli to the package
78
+ * root. Used to version-pin the npx invocation written into the in-process
79
+ * plugin loader and any delegate references.
80
+ */
81
+ function readPackageVersion() {
82
+ const pkgPath = path.resolve(__dirname, "..", "..", "package.json");
83
+ const raw = fs.readFileSync(pkgPath, "utf-8");
84
+ const parsed = JSON.parse(raw);
85
+ if (!parsed.version) {
86
+ throw new Error(`Could not read version from ${pkgPath}`);
87
+ }
88
+ return parsed.version;
89
+ }
90
+ function getSettingsPath(_args) {
91
+ // Verified: Amp's default settings file is the user-global
92
+ // ~/.config/amp/settings.json (the `--settings-file` default). Amp's own
93
+ // permission entries are global by default; `-w/--workspace` would scope
94
+ // them to the project. We follow the verified default.
95
+ return path.join(os.homedir(), ".config", "amp", "settings.json");
96
+ }
97
+ /**
98
+ * The `amp.permissions` delegate entry that routes every tool ("*") through
99
+ * the Ory permission helper. Amp invokes the named program with the tool
100
+ * params on stdin and reads the decision from the exit code.
101
+ *
102
+ * Verified against the binary: a flat top-level `amp.permissions` array of
103
+ * `{ tool, action, to }` entries.
104
+ */
105
+ function delegateEntry() {
106
+ return { tool: "*", action: "delegate", to: DELEGATE_BIN };
107
+ }
108
+ function isOryDelegate(entry) {
109
+ return (typeof entry === "object" &&
110
+ entry !== null &&
111
+ entry.action === "delegate" &&
112
+ entry.to === DELEGATE_BIN);
113
+ }
114
+ function mergePermissions(existing) {
115
+ const merged = { ...existing };
116
+ const perms = (Array.isArray(merged["amp.permissions"])
117
+ ? merged["amp.permissions"]
118
+ : []).filter((e) => !isOryDelegate(e));
119
+ perms.push(delegateEntry());
120
+ merged["amp.permissions"] = perms;
121
+ return merged;
122
+ }
123
+ function removePermissions(existing) {
124
+ const merged = { ...existing };
125
+ const perms = (Array.isArray(merged["amp.permissions"])
126
+ ? merged["amp.permissions"]
127
+ : []).filter((e) => !isOryDelegate(e));
128
+ if (perms.length === 0) {
129
+ delete merged["amp.permissions"];
130
+ }
131
+ else {
132
+ merged["amp.permissions"] = perms;
133
+ }
134
+ return merged;
135
+ }
136
+ /**
137
+ * The in-process plugin loader written at `.amp/plugins/ory.ts`. Amp's Bun
138
+ * TypeScript runtime discovers direct `*.ts` files under `.amp/plugins/`, so
139
+ * this re-exports the installed `@ory/amp` package's default-exported plugin
140
+ * factory. Version-pinned in the header so the on-disk loader is traceable to
141
+ * the package the settings were written against.
142
+ */
143
+ function pluginLoaderSource(version) {
144
+ return (`// Generated by ${PACKAGE_NAME}@${version} — do not edit by hand.\n` +
145
+ `// Re-exports the Ory in-process plugin for Amp's .amp/plugins/ loader.\n` +
146
+ `export { default } from "${PACKAGE_NAME}";\n`);
147
+ }
148
+ function getPluginFile(args) {
149
+ return path.join(args.projectDir, ".amp", "plugins", PLUGIN_FILE);
150
+ }
151
+ function main() {
152
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
153
+ (0, argus_1.printSetupHelp)("ory-amp-setup", "Amp");
154
+ process.exit(0);
155
+ }
156
+ const args = (0, argus_1.parseSetupArgs)();
157
+ const version = readPackageVersion();
158
+ if (args.print) {
159
+ console.log(JSON.stringify({ "amp.permissions": [delegateEntry()] }, null, 2));
160
+ return;
161
+ }
162
+ const settingsPath = getSettingsPath(args);
163
+ const pluginFile = getPluginFile(args);
164
+ const skillsDir = path.join(args.projectDir, ".agents", "skills");
165
+ const existing = (0, argus_1.readJsonFile)(settingsPath);
166
+ if (args.uninstall) {
167
+ if (fs.existsSync(settingsPath)) {
168
+ const updated = removePermissions(existing);
169
+ (0, argus_1.writeJsonFile)(settingsPath, updated);
170
+ console.log(`Removed Ory permission delegate from ${settingsPath}`);
171
+ }
172
+ else {
173
+ console.log("No Amp settings file found. Nothing to remove from settings.");
174
+ }
175
+ if (fs.existsSync(pluginFile)) {
176
+ fs.rmSync(pluginFile, { force: true });
177
+ console.log(`Removed Ory in-process plugin from ${pluginFile}`);
178
+ }
179
+ (0, assets_js_1.uninstallAmpOryAssets)(args.projectDir);
180
+ console.log(`Removed Ory skills from ${skillsDir}`);
181
+ return;
182
+ }
183
+ // (a) Register the permission delegate (blocking gate).
184
+ const merged = mergePermissions(existing);
185
+ (0, argus_1.writeJsonFile)(settingsPath, merged);
186
+ // (b) Write the in-process plugin loader (auth + tracing).
187
+ fs.mkdirSync(path.dirname(pluginFile), { recursive: true });
188
+ fs.writeFileSync(pluginFile, pluginLoaderSource(version));
189
+ // (c) Materialize the Ory skill catalog.
190
+ (0, assets_js_1.installAmpOryAssets)(args.projectDir);
191
+ console.log(`Ory permission delegate registered in ${settingsPath}`);
192
+ console.log(` Delegate: ${DELEGATE_BIN} (tool: "*", action: delegate)`);
193
+ console.log(`Ory in-process plugin written to ${pluginFile}`);
194
+ console.log(`Ory skills installed under ${skillsDir}`);
195
+ (0, argus_1.printNextSteps)("Amp", "npx ory-amp-setup --uninstall");
196
+ }
197
+ main();
@@ -0,0 +1,7 @@
1
+ import { createOryPlugin } from "./plugin.js";
2
+ export { createOryPlugin };
3
+ export type { CreateOryPluginDeps } from "./plugin.js";
4
+ export { decideToolPermission, extractToolName, type DelegateDecision } from "./permission.js";
5
+ export type { AmpPlugin, AmpPluginApi, AmpPluginEventContext, AmpEvent, AmpEventMap, AmpDelegateInput, AmpToolCallResult, AmpSessionStartEvent, AmpToolResultEvent, } from "./types.js";
6
+ declare const _default: import("./types.js").AmpPlugin;
7
+ export default _default;