@ory/pi 0.13.9 → 0.14.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 CHANGED
@@ -27,12 +27,14 @@ Then run one command. It installs the plugin and walks you through connecting:
27
27
  npx -y -p @ory/pi ory-pi install
28
28
  ```
29
29
 
30
- The installer drops a tiny loader at `<project>/.pi/extensions/ory.js` so Pi discovers the plugin, adds the Ory skills under `<project>/.pi/skills`, and then asks how you want to connect — **press Enter for the default**:
30
+ The installer drops a tiny loader at `<project>/.pi/extensions/ory.js` so Pi discovers the plugin, adds the Ory skills under `<project>/.pi/skills`, and then opens a guided setup **in your browser** where you pick how to connect — the default takes just a click:
31
31
 
32
32
  - **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.
33
33
  - **Local** — run a complete Ory on your laptop with Docker. No account, no signup, no keys. Great for trying it out.
34
34
  - **Audit-only** — skip Ory entirely and just log what Pi does.
35
35
 
36
+ > No browser available (CI, SSH, headless)? The same walkthrough runs right in your terminal instead — or force it with `--no-web`.
37
+
36
38
  That's it. Confirm everything landed with:
37
39
 
38
40
  ```bash
@@ -73,6 +75,7 @@ If Ory is ever unreachable, the plugin gets out of the way and lets Pi keep work
73
75
  Everything the plugin does is observable out of the box — no configuration required:
74
76
 
75
77
  - **Status at a glance.** `npx -y -p @ory/pi ory-pi status` shows what's configured, who's signed in, how many built-in tools your permissions cover, and the most recent tool-call activity.
78
+ - **Live dashboard.** `npx -y -p @ory/pi ory-pi 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.
76
79
  - **Live traces.** Every tool call is recorded as an OpenTelemetry-style span. Watch them stream as the agent works:
77
80
 
78
81
  ```bash
@@ -90,7 +93,7 @@ When the watch-mode logs look right, turn on blocking with one command (setup al
90
93
  npx -y -p @ory/pi ory-pi permissions enforce
91
94
  ```
92
95
 
93
- Now a denied tool is actually blocked and Pi shows why (the plugin returns `{ block: true, reason }` on Pi's `tool_call` event). Go back to watch mode anytime with `permissions observe`. Use `permissions status` to see what's covered and `permissions bootstrap` to (re-)grant the built-in tools.
96
+ Now a denied tool is actually blocked and Pi shows why (the plugin returns `{ block: true, reason }` on Pi's `tool_call` event). Go back to watch mode anytime with `permissions observe`. Prefer clicking? The dashboard has the same **Enforce** switch — flip it on, or back to watch mode, without touching the CLI. Use `permissions status` to see what's covered and `permissions bootstrap` to (re-)grant the built-in tools.
94
97
 
95
98
  ## Also: add login to your own app
96
99
 
@@ -105,22 +108,22 @@ The guided setup covers most people. For scripted or CI setups, or to point at a
105
108
  ```bash
106
109
  npx -y -p @ory/pi ory-pi configure \
107
110
  --project-url https://<slug>.projects.oryapis.com \
108
- --oauth2-client-id <sign-in client id> \
109
- --user-login
111
+ --oauth2-client-id <sign-in client id>
110
112
  ```
111
113
 
112
- Pi's own identity registers itself automatically on first run — nothing to create. The `--oauth2-client-id` is the one piece browser sign-in needs — the public sign-in client, registered with the four loopback URLs `http://127.0.0.1:47823..47826/callback`; the guided setup makes it for you. For logging-only with no checks, use `--audit-only`. The equivalent env vars are `ORY_PROJECT_URL`, `ORY_OAUTH2_CLIENT_ID`, and `ORY_USER_LOGIN`.
114
+ Pi's own identity registers itself automatically on first run — nothing to create. The `--oauth2-client-id` is the one piece browser sign-in needs — the public sign-in client, registered with the four loopback URLs `http://127.0.0.1:47823..47826/callback`; the guided setup makes it for you. For logging-only with no checks, use `--audit-only`. The interactive user login runs every session (always on, non-blocking) and only needs `ORY_OAUTH2_CLIENT_ID` to complete the browser flow. The equivalent env vars are `ORY_PROJECT_URL` and `ORY_OAUTH2_CLIENT_ID`.
113
115
 
114
116
  With nothing configured, the plugin still loads and runs in **pass-through mode**: skills and logging work, but no checks run and nothing is blocked. Perfectly fine if you only want the app-building features.
115
117
 
116
118
  ## Commands
117
119
 
118
120
  ```
119
- ory-pi install | uninstall Install/remove; --reconfigure re-runs setup, --no-configure skips it, --global for all projects
121
+ ory-pi install | uninstall Install/remove; --reconfigure re-runs setup, --no-web forces the terminal wizard, --no-configure skips it
120
122
  ory-pi status Show configuration, identities, permission coverage, recent activity
123
+ ory-pi dashboard Open the live browser dashboard (status + service health + Change stack)
121
124
  ory-pi watch Tail the live trace stream (OTel spans)
122
125
  ory-pi permissions <cmd> status | bootstrap | observe (watch) | enforce (block)
123
- ory-pi configure <flags> Point at a project by hand (--project-url, --oauth2-client-id, --user-login, --audit-only)
126
+ ory-pi configure <flags> Point at a project by hand (--project-url, --oauth2-client-id, --audit-only)
124
127
  ory-pi agent <status|unregister> Manage Pi's own auto-created identity
125
128
  ```
126
129
 
package/dist/cli/main.js CHANGED
@@ -97,6 +97,12 @@ function main() {
97
97
  case "watch":
98
98
  (0, argus_1.runWatchCommand)("pi", args);
99
99
  break;
100
+ case "dashboard":
101
+ (0, argus_1.runDashboardCommand)("ory-pi", "pi", args).then((code) => process.exit(code), (err) => {
102
+ console.error(err.message ?? err);
103
+ process.exit(1);
104
+ });
105
+ break;
100
106
  case "version":
101
107
  case "--version":
102
108
  case "-v":
@@ -182,6 +188,7 @@ Commands:
182
188
  local <cmd> Manage local Ory dev environment
183
189
  (up, down, status, seed, logs, env, configure, reset)
184
190
  status [--project-dir <path>] Show plugin configuration and status
191
+ dashboard Open the Ory Agent dashboard (system health + configuration)
185
192
  watch [trace-file] Watch live trace output
186
193
  version Show version and the ory-agent-plugins build commit
187
194
 
package/dist/plugin.d.ts CHANGED
@@ -4,8 +4,9 @@
4
4
  * Pi loads a default-exported factory `(pi) => void | Promise<void>` from a
5
5
  * TypeScript extension module (via jiti) and awaits it before startup
6
6
  * continues. We treat the factory body as the session-start hook: it runs the
7
- * user gate (advisory — there is no block channel for the session itself), the
8
- * agent gate, and writes the user→agent delegation tuple.
7
+ * user gate (which runs every session and never blocks — enforcement is
8
+ * governed solely by permissionMode at tool-call time), the agent gate, and
9
+ * writes the user→agent delegation tuple.
9
10
  *
10
11
  * The blocking permission decision lives in the `tool_call` hook, which CAN
11
12
  * block by returning `{ block: true, reason }` (like OpenClaw's
package/dist/plugin.js CHANGED
@@ -5,8 +5,9 @@
5
5
  * Pi loads a default-exported factory `(pi) => void | Promise<void>` from a
6
6
  * TypeScript extension module (via jiti) and awaits it before startup
7
7
  * continues. We treat the factory body as the session-start hook: it runs the
8
- * user gate (advisory — there is no block channel for the session itself), the
9
- * agent gate, and writes the user→agent delegation tuple.
8
+ * user gate (which runs every session and never blocks — enforcement is
9
+ * governed solely by permissionMode at tool-call time), the agent gate, and
10
+ * writes the user→agent delegation tuple.
10
11
  *
11
12
  * The blocking permission decision lives in the `tool_call` hook, which CAN
12
13
  * block by returning `{ block: true, reason }` (like OpenClaw's
@@ -54,16 +55,14 @@ async function runSessionStart(client, deps) {
54
55
  client.logger.info("lifecycle.session_start", { harness: "pi" });
55
56
  client.tracer.setContext({ traceId: (0, argus_1.deriveTraceId)("pi"), sessionId: "pi" });
56
57
  client.tracer.record("session.start", "ok", { attributes: {} });
57
- // Run the user login. Pi's factory body has no return-value channel to
58
- // block the session, so allowBlock is false — the flow emits the user.auth
59
- // audit span, refreshes tokens, and may prompt when interactive, but never
60
- // prevents the session from starting. When ORY_USER_LOGIN is unset it is a
61
- // no-op (mode === "disabled") and we fall through to legacy verification.
58
+ // Run the user login. It runs every session and never blocks the session
59
+ // from starting — the flow emits the user.auth audit span, refreshes tokens,
60
+ // and may prompt when interactive. Enforcement is governed solely by
61
+ // permissionMode at tool-call time.
62
62
  const userGate = deps.userLogin ?? argus_1.ensureUserAuthenticated;
63
- const decision = await userGate(client, {
63
+ await userGate(client, {
64
64
  binName: "ory-pi",
65
65
  harness: "pi",
66
- allowBlock: false,
67
66
  });
68
67
  // Resolve the agent identity (machine credentials). Never blocks; attaches
69
68
  // the agent's bearer token to outgoing Ory API calls.
@@ -72,74 +71,6 @@ async function runSessionStart(client, deps) {
72
71
  // Once both principals are populated, write the user→agent delegation tuple.
73
72
  // Written at most once per install + fail-open: audit-trail data only.
74
73
  await (0, argus_1.writeUserDelegatesAgent)(client);
75
- if (decision.mode !== "disabled") {
76
- return;
77
- }
78
- const resolved = (0, argus_1.resolveConfig)();
79
- if (resolved.auditOnly) {
80
- client.logger.info("config.audit_only", {
81
- message: "Audit-only mode enabled. Auth and permission checks are disabled.",
82
- });
83
- return;
84
- }
85
- if (!resolved.projectUrl) {
86
- client.logger.warn("config.not_configured", {
87
- message: "Ory plugin is not configured. Auth and permission checks are disabled. " +
88
- "Run 'npx ory-pi configure' to connect to an Ory project.",
89
- });
90
- return;
91
- }
92
- const sessionToken = process.env.ORY_SESSION_TOKEN;
93
- const oauth2Token = process.env.ORY_OAUTH2_TOKEN;
94
- if (sessionToken) {
95
- await verifySessionToken(client, sessionToken);
96
- return;
97
- }
98
- if (oauth2Token) {
99
- await verifyOAuth2Token(client, oauth2Token);
100
- return;
101
- }
102
- client.logger.warn("session.no_credentials", {
103
- message: "Neither ORY_SESSION_TOKEN nor ORY_OAUTH2_TOKEN is set. " +
104
- "Skipping authentication.",
105
- });
106
- }
107
- async function verifySessionToken(client, token) {
108
- try {
109
- const session = await client.verifySession(token);
110
- if (!session.active) {
111
- client.logger.warn("session.inactive", {
112
- message: "Ory session is not active. Re-authenticate to enable auth checks.",
113
- });
114
- }
115
- }
116
- catch (err) {
117
- client.logger.warn("session.verify_failed", {
118
- code: isOryError(err) ? err.code : "unknown",
119
- message: err instanceof Error ? err.message : String(err),
120
- });
121
- }
122
- }
123
- async function verifyOAuth2Token(client, token) {
124
- try {
125
- const tokenInfo = await client.introspectToken(token);
126
- if (!tokenInfo.active) {
127
- client.logger.warn("oauth2.token_inactive", {
128
- message: "Ory OAuth2 token is not active. Obtain a new token to enable auth checks.",
129
- });
130
- return;
131
- }
132
- client.logger.info("oauth2.session_authenticated", {
133
- clientId: tokenInfo.clientId,
134
- subject: tokenInfo.subject,
135
- });
136
- }
137
- catch (err) {
138
- client.logger.warn("oauth2.introspect_failed", {
139
- code: isOryError(err) ? err.code : "unknown",
140
- message: err instanceof Error ? err.message : String(err),
141
- });
142
- }
143
74
  }
144
75
  // ─── tool_call (pre-execution, blocking) ───────────────────────────
145
76
  function createToolCallHandler(client) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ory/pi",
3
- "version": "0.13.9",
3
+ "version": "0.14.0",
4
4
  "description": "Ory plugin for Pi (the minimal coding agent): scaffolding skills, a local Ory instance, and authentication, authorization, and audit for every tool call",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ory.com",
@@ -73,7 +73,7 @@
73
73
  ],
74
74
  "dependencies": {
75
75
  "reo-census": "^1.2.8",
76
- "@ory/argus": "0.13.9"
76
+ "@ory/argus": "0.14.0"
77
77
  },
78
78
  "devDependencies": {
79
79
  "typescript": "^6.0.2",