@ory/argus 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.
Files changed (65) hide show
  1. package/README.md +2 -1
  2. package/assets/commands/dashboard.md +34 -0
  3. package/assets/skills/ory-build-agent/SKILL.md +11 -13
  4. package/assets/skills/ory-e2b-sandbox/SKILL.md +0 -1
  5. package/assets/skills/ory-temporal-worker/SKILL.md +8 -10
  6. package/assets/skills/permissions-onboarding/SKILL.md +3 -3
  7. package/dist/adapters.d.ts +12 -5
  8. package/dist/adapters.js +59 -10
  9. package/dist/agent-auth.d.ts +34 -3
  10. package/dist/agent-auth.js +58 -8
  11. package/dist/auth.d.ts +7 -0
  12. package/dist/auth.js +90 -5
  13. package/dist/branding.d.ts +67 -0
  14. package/dist/branding.js +81 -0
  15. package/dist/build-info.json +4 -4
  16. package/dist/cli.d.ts +3 -3
  17. package/dist/cli.js +13 -52
  18. package/dist/config.d.ts +48 -19
  19. package/dist/config.js +31 -26
  20. package/dist/contract-suite.d.ts +5 -3
  21. package/dist/contract-suite.js +13 -22
  22. package/dist/dashboard-cli.d.ts +8 -0
  23. package/dist/dashboard-cli.js +70 -0
  24. package/dist/dev.js +3 -4
  25. package/dist/index.d.ts +11 -4
  26. package/dist/index.js +39 -3
  27. package/dist/interactive-setup.d.ts +144 -23
  28. package/dist/interactive-setup.js +412 -224
  29. package/dist/local/health.d.ts +14 -0
  30. package/dist/local/health.js +46 -0
  31. package/dist/local/manager.js +1 -3
  32. package/dist/local/seed.d.ts +9 -20
  33. package/dist/local/seed.js +26 -18
  34. package/dist/permissions-cli.js +1 -1
  35. package/dist/project-api-key.d.ts +69 -0
  36. package/dist/project-api-key.js +147 -0
  37. package/dist/registry/manager.js +62 -18
  38. package/dist/setup-actions.d.ts +232 -0
  39. package/dist/setup-actions.js +507 -0
  40. package/dist/setup.d.ts +19 -0
  41. package/dist/setup.js +44 -14
  42. package/dist/skills.js +7 -0
  43. package/dist/status-cli.d.ts +2 -2
  44. package/dist/status-cli.js +4 -30
  45. package/dist/status-data.d.ts +96 -0
  46. package/dist/status-data.js +250 -0
  47. package/dist/status-system.d.ts +24 -0
  48. package/dist/status-system.js +56 -0
  49. package/dist/uninstall.d.ts +33 -15
  50. package/dist/uninstall.js +65 -22
  51. package/dist/user-login.d.ts +16 -9
  52. package/dist/user-login.js +18 -28
  53. package/dist/web/api.d.ts +33 -0
  54. package/dist/web/api.js +294 -0
  55. package/dist/web/launch.d.ts +11 -0
  56. package/dist/web/launch.js +96 -0
  57. package/dist/web/server.d.ts +20 -0
  58. package/dist/web/server.js +233 -0
  59. package/dist/web/types.d.ts +65 -0
  60. package/dist/web/types.js +2 -0
  61. package/dist/webapp/assets/index-Wucl4SZs.css +1 -0
  62. package/dist/webapp/assets/index-m-GtEdq0.js +49 -0
  63. package/dist/webapp/favicon.ico +0 -0
  64. package/dist/webapp/index.html +15 -0
  65. package/package.json +17 -2
package/dist/auth.js CHANGED
@@ -12,6 +12,39 @@
12
12
  * package via dynamic import so the CJS-emitted core stays compatible
13
13
  * with its ESM-only export shape.
14
14
  */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || (function () {
32
+ var ownKeys = function(o) {
33
+ ownKeys = Object.getOwnPropertyNames || function (o) {
34
+ var ar = [];
35
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
+ return ar;
37
+ };
38
+ return ownKeys(o);
39
+ };
40
+ return function (mod) {
41
+ if (mod && mod.__esModule) return mod;
42
+ var result = {};
43
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
+ __setModuleDefault(result, mod);
45
+ return result;
46
+ };
47
+ })();
15
48
  Object.defineProperty(exports, "__esModule", { value: true });
16
49
  exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.LOOPBACK_PORTS = void 0;
17
50
  exports.detectHeadless = detectHeadless;
@@ -20,9 +53,12 @@ exports.generateCodeVerifier = generateCodeVerifier;
20
53
  exports.sha256Base64Url = sha256Base64Url;
21
54
  exports.buildAuthorizeUrl = buildAuthorizeUrl;
22
55
  exports.refreshAccessToken = refreshAccessToken;
56
+ exports.displayNameFromIdToken = displayNameFromIdToken;
23
57
  const node_crypto_1 = require("node:crypto");
24
58
  const node_http_1 = require("node:http");
25
59
  const node_url_1 = require("node:url");
60
+ const fs = __importStar(require("node:fs"));
61
+ const path = __importStar(require("node:path"));
26
62
  /** Loopback ports tried in order. All must be registered as redirect URIs on the Ory OAuth2 client. */
27
63
  exports.LOOPBACK_PORTS = [47823, 47824, 47825, 47826];
28
64
  /** Hard timeout if the user never returns to the browser. */
@@ -201,6 +237,10 @@ function waitForCallback(server, opts) {
201
237
  return;
202
238
  }
203
239
  const url = new node_url_1.URL(req.url ?? "/", `http://127.0.0.1`);
240
+ if (url.pathname === "/favicon.ico") {
241
+ respondFavicon(res);
242
+ return;
243
+ }
204
244
  if (url.pathname !== "/callback") {
205
245
  respond(res, 404, "Not Found");
206
246
  return;
@@ -238,18 +278,41 @@ function respondHtml(res, status, html) {
238
278
  res.writeHead(status, { "content-type": "text/html; charset=utf-8" });
239
279
  res.end(html);
240
280
  }
281
+ /**
282
+ * Serve the shared Ory favicon (identical to console.ory.com's) so the sign-in
283
+ * result page carries the same tab icon as the Console. It ships alongside the
284
+ * built dashboard at `dist/webapp/favicon.ico`; if that file isn't present
285
+ * (e.g. the webapp wasn't built), fall back to a 404 — the page still renders,
286
+ * just without a favicon. Same-origin on the loopback server, so no external
287
+ * request is made.
288
+ */
289
+ function respondFavicon(res) {
290
+ // Compiled to dist/auth.js; the SPA (and its favicon) is built to dist/webapp.
291
+ const file = path.join(__dirname, "webapp", "favicon.ico");
292
+ try {
293
+ const buf = fs.readFileSync(file);
294
+ res.writeHead(200, {
295
+ "content-type": "image/x-icon",
296
+ "cache-control": "no-store",
297
+ });
298
+ res.end(buf);
299
+ }
300
+ catch {
301
+ respond(res, 404, "Not Found");
302
+ }
303
+ }
241
304
  /**
242
305
  * The page the browser lands on after the OAuth2 redirect. The whole point is
243
306
  * to make the next action unambiguous: on success it tells the user, in plain
244
307
  * words, that they can close the tab and return to the terminal (the #1
245
- * source of "is it done? do I close this?" confusion). Self-contained HTML
246
- * inline styles only, Ory-branded (Indigo #4F46E5), no external requests — so
247
- * it renders identically offline and on the loopback origin.
308
+ * source of "is it done? do I close this?" confusion). Inline styles only, no
309
+ * external requests — the only asset is the same-origin Ory favicon the
310
+ * loopback server serves so it renders identically offline.
248
311
  */
249
312
  function resultPage(kind) {
250
313
  const view = {
251
314
  success: {
252
- accent: "#4F46E5", // Ory Indigo
315
+ accent: "#22C55E", // green — a positive "done" check
253
316
  icon: "&#10003;", // ✓
254
317
  title: "Signed in to Ory",
255
318
  body: "You can <strong>close this tab</strong> and return to your terminal — setup continues automatically.",
@@ -272,6 +335,7 @@ function resultPage(kind) {
272
335
  <head>
273
336
  <meta charset="utf-8">
274
337
  <meta name="viewport" content="width=device-width, initial-scale=1">
338
+ <link rel="icon" href="/favicon.ico">
275
339
  <title>${view.title}</title>
276
340
  <style>
277
341
  :root { color-scheme: light dark; }
@@ -381,6 +445,10 @@ function tokensFromTokenResponse(json, clientId, fallbackRefreshToken) {
381
445
  }
382
446
  /** Best-effort sub-claim extraction from a JWT id_token. Returns undefined on any failure. */
383
447
  function subjectFromIdToken(idToken) {
448
+ return claimsFromIdToken(idToken)?.sub;
449
+ }
450
+ /** Best-effort JWT id_token payload decode. Returns undefined on any failure. */
451
+ function claimsFromIdToken(idToken) {
384
452
  if (!idToken)
385
453
  return undefined;
386
454
  const parts = idToken.split(".");
@@ -388,9 +456,26 @@ function subjectFromIdToken(idToken) {
388
456
  return undefined;
389
457
  try {
390
458
  const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
391
- return typeof payload.sub === "string" ? payload.sub : undefined;
459
+ return payload && typeof payload === "object" ? payload : undefined;
392
460
  }
393
461
  catch {
394
462
  return undefined;
395
463
  }
396
464
  }
465
+ /**
466
+ * Best-effort human-readable name for the signed-in user, pulled from the
467
+ * id_token's identity claims — `email`, then `name`, then `preferred_username`.
468
+ * Returns undefined when the token carries none of them (e.g. an `openid`-only
469
+ * token), so callers fall back to the opaque subject id.
470
+ */
471
+ function displayNameFromIdToken(idToken) {
472
+ const claims = claimsFromIdToken(idToken);
473
+ if (!claims)
474
+ return undefined;
475
+ for (const key of ["email", "name", "preferred_username"]) {
476
+ const v = claims[key];
477
+ if (typeof v === "string" && v.trim())
478
+ return v.trim();
479
+ }
480
+ return undefined;
481
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The umbrella brand and the names for every resource the installer creates in
3
+ * (or for) an Ory project. Centralized here so every install path — the web
4
+ * wizard, the TTY wizard, and the agent-identity gates — produces the same,
5
+ * self-describing names, and so the naming policy lives in one place.
6
+ *
7
+ * The policy has two tiers, because many users install these plugins against
8
+ * the **same** Ory project:
9
+ *
10
+ * - **Shared** resources (one per project, reused by every user/harness) get a
11
+ * **stable, identity-free** name so all installs find and reuse the one
12
+ * resource instead of duplicating it: {@link USER_LOGIN_CLIENT_NAME} and the
13
+ * permission namespace ({@link PERMISSION_NAMESPACE}).
14
+ * - **Per-installer** resources (many per project by design — confidential
15
+ * per-machine DCR credentials, write-once API keys) get an **attributable**
16
+ * name carrying *who* and *where*, so a shared project's resource list stays
17
+ * legible and prunable: {@link agentClientName}, {@link projectApiKeyName}.
18
+ *
19
+ * Everything shares the {@link PRODUCT_NAME} prefix so the plugin's resources
20
+ * group together and are instantly recognizable in a shared Ory Console.
21
+ */
22
+ /** Human-readable umbrella name for everything this product creates. */
23
+ export declare const PRODUCT_NAME = "Ory Agent Security";
24
+ /**
25
+ * The public PKCE client the human's browser sign-in uses. It is a *public*
26
+ * client (no secret), so every user on a project shares the one client — the
27
+ * installer dedupes by this exact name. Stable and identity-free on purpose.
28
+ */
29
+ export declare const USER_LOGIN_CLIENT_NAME = "Ory Agent Security \u00B7 user login (PKCE)";
30
+ /**
31
+ * Names an older installer may have given the shared user-login client. The
32
+ * reuse probe matches these too, so renaming the client never orphans one
33
+ * created by a previous install (which would then mint a duplicate).
34
+ */
35
+ export declare const LEGACY_USER_LOGIN_CLIENT_NAMES: string[];
36
+ /** All names the shared user-login client may carry, newest first. */
37
+ export declare const USER_LOGIN_CLIENT_NAMES: string[];
38
+ /** Default name for a project the installer creates. Harness-agnostic, since a
39
+ * team typically points several harnesses at one shared project. */
40
+ export declare const DEFAULT_PROJECT_NAME = "Ory Agent Security";
41
+ /** The shared permission-model namespace (an OPL class name, so it must stay a
42
+ * bare identifier — no spaces/branding — and stable across installs). */
43
+ export declare const PERMISSION_NAMESPACE = "AgentTools";
44
+ /**
45
+ * The client_name for an agent's (or sub-agent's) OAuth2 identity registered
46
+ * via DCR. These are confidential, per-machine credentials — many per shared
47
+ * project by design — so the name is attributable: the harness it belongs to
48
+ * and the host it was registered from (plus the sub-agent type, when it is one).
49
+ */
50
+ export declare function agentClientName(opts: {
51
+ harness?: string;
52
+ host: string;
53
+ subAgentType?: string;
54
+ }): string;
55
+ /**
56
+ * The name for a project API key minted for runtime permission checks. Ory only
57
+ * returns a key's secret at creation, so a key can't be reused across machines
58
+ * — each installer that mints one gets its own. The name therefore carries the
59
+ * signed-in *user* (the axis that matters on a shared project) plus the host, so
60
+ * a team admin can tell whose key is whose and prune stale ones. No timestamp:
61
+ * the Ory Console's key listing already shows a "Date Added" column. `user`
62
+ * falls back to the host alone when it isn't resolvable (e.g. login skipped).
63
+ */
64
+ export declare function projectApiKeyName(opts: {
65
+ host: string;
66
+ user?: string;
67
+ }): string;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * The umbrella brand and the names for every resource the installer creates in
4
+ * (or for) an Ory project. Centralized here so every install path — the web
5
+ * wizard, the TTY wizard, and the agent-identity gates — produces the same,
6
+ * self-describing names, and so the naming policy lives in one place.
7
+ *
8
+ * The policy has two tiers, because many users install these plugins against
9
+ * the **same** Ory project:
10
+ *
11
+ * - **Shared** resources (one per project, reused by every user/harness) get a
12
+ * **stable, identity-free** name so all installs find and reuse the one
13
+ * resource instead of duplicating it: {@link USER_LOGIN_CLIENT_NAME} and the
14
+ * permission namespace ({@link PERMISSION_NAMESPACE}).
15
+ * - **Per-installer** resources (many per project by design — confidential
16
+ * per-machine DCR credentials, write-once API keys) get an **attributable**
17
+ * name carrying *who* and *where*, so a shared project's resource list stays
18
+ * legible and prunable: {@link agentClientName}, {@link projectApiKeyName}.
19
+ *
20
+ * Everything shares the {@link PRODUCT_NAME} prefix so the plugin's resources
21
+ * group together and are instantly recognizable in a shared Ory Console.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.PERMISSION_NAMESPACE = exports.DEFAULT_PROJECT_NAME = exports.USER_LOGIN_CLIENT_NAMES = exports.LEGACY_USER_LOGIN_CLIENT_NAMES = exports.USER_LOGIN_CLIENT_NAME = exports.PRODUCT_NAME = void 0;
25
+ exports.agentClientName = agentClientName;
26
+ exports.projectApiKeyName = projectApiKeyName;
27
+ /** Human-readable umbrella name for everything this product creates. */
28
+ exports.PRODUCT_NAME = "Ory Agent Security";
29
+ /**
30
+ * The public PKCE client the human's browser sign-in uses. It is a *public*
31
+ * client (no secret), so every user on a project shares the one client — the
32
+ * installer dedupes by this exact name. Stable and identity-free on purpose.
33
+ */
34
+ exports.USER_LOGIN_CLIENT_NAME = `${exports.PRODUCT_NAME} · user login (PKCE)`;
35
+ /**
36
+ * Names an older installer may have given the shared user-login client. The
37
+ * reuse probe matches these too, so renaming the client never orphans one
38
+ * created by a previous install (which would then mint a duplicate).
39
+ */
40
+ exports.LEGACY_USER_LOGIN_CLIENT_NAMES = ["ory-agent-plugin"];
41
+ /** All names the shared user-login client may carry, newest first. */
42
+ exports.USER_LOGIN_CLIENT_NAMES = [
43
+ exports.USER_LOGIN_CLIENT_NAME,
44
+ ...exports.LEGACY_USER_LOGIN_CLIENT_NAMES,
45
+ ];
46
+ /** Default name for a project the installer creates. Harness-agnostic, since a
47
+ * team typically points several harnesses at one shared project. */
48
+ exports.DEFAULT_PROJECT_NAME = exports.PRODUCT_NAME;
49
+ /** The shared permission-model namespace (an OPL class name, so it must stay a
50
+ * bare identifier — no spaces/branding — and stable across installs). */
51
+ exports.PERMISSION_NAMESPACE = "AgentTools";
52
+ /**
53
+ * The client_name for an agent's (or sub-agent's) OAuth2 identity registered
54
+ * via DCR. These are confidential, per-machine credentials — many per shared
55
+ * project by design — so the name is attributable: the harness it belongs to
56
+ * and the host it was registered from (plus the sub-agent type, when it is one).
57
+ */
58
+ function agentClientName(opts) {
59
+ const { harness, host, subAgentType } = opts;
60
+ if (subAgentType) {
61
+ const scope = harness ? `${harness}/${subAgentType}` : subAgentType;
62
+ return `${exports.PRODUCT_NAME} · sub-agent · ${scope} @ ${host}`;
63
+ }
64
+ return harness
65
+ ? `${exports.PRODUCT_NAME} · agent · ${harness} @ ${host}`
66
+ : `${exports.PRODUCT_NAME} · agent @ ${host}`;
67
+ }
68
+ /**
69
+ * The name for a project API key minted for runtime permission checks. Ory only
70
+ * returns a key's secret at creation, so a key can't be reused across machines
71
+ * — each installer that mints one gets its own. The name therefore carries the
72
+ * signed-in *user* (the axis that matters on a shared project) plus the host, so
73
+ * a team admin can tell whose key is whose and prune stale ones. No timestamp:
74
+ * the Ory Console's key listing already shows a "Date Added" column. `user`
75
+ * falls back to the host alone when it isn't resolvable (e.g. login skipped).
76
+ */
77
+ function projectApiKeyName(opts) {
78
+ const who = opts.user && opts.user !== "agent:unknown" ? opts.user : null;
79
+ const where = who ? `${who} @ ${opts.host}` : opts.host;
80
+ return `${exports.PRODUCT_NAME}: Permission Checks - ${where}`;
81
+ }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "repo": "ory-agent-plugins",
3
- "commit": "f7663bf2a792378be5a94c7d6bb0d6671e1da6a9",
4
- "commitShort": "f7663bf",
3
+ "commit": "7568c163e59fba25d64ede49c092fcca108a43f2",
4
+ "commitShort": "7568c16",
5
5
  "branch": "main",
6
- "commitDate": "2026-07-15T15:56:35-07:00",
6
+ "commitDate": "2026-07-23T10:17:45-07:00",
7
7
  "dirty": false,
8
- "builtAt": "2026-07-15T23:00:39.070Z"
8
+ "builtAt": "2026-07-23T17:21:55.389Z"
9
9
  }
package/dist/cli.d.ts CHANGED
@@ -8,9 +8,9 @@
8
8
  * When `--project-url` is provided, requires the OAuth2 client id to be
9
9
  * resolvable from one of: the `--oauth2-client-id` flag, the
10
10
  * `ORY_OAUTH2_CLIENT_ID` env var, or an already-persisted value in the
11
- * shared config. The PKCE browser flow that runs when
12
- * `ORY_USER_LOGIN=true` can't self-register that client — surfacing the
13
- * requirement here keeps users from a silently-broken setup later.
11
+ * shared config. The PKCE browser flow (the user login runs every session)
12
+ * can't self-register that client — surfacing the requirement here keeps
13
+ * users from a silently-broken setup later.
14
14
  */
15
15
  export declare function runConfigureCommand(binName: string, args: string[]): void;
16
16
  /**
package/dist/cli.js CHANGED
@@ -62,9 +62,9 @@ const client_js_1 = require("./client.js");
62
62
  * When `--project-url` is provided, requires the OAuth2 client id to be
63
63
  * resolvable from one of: the `--oauth2-client-id` flag, the
64
64
  * `ORY_OAUTH2_CLIENT_ID` env var, or an already-persisted value in the
65
- * shared config. The PKCE browser flow that runs when
66
- * `ORY_USER_LOGIN=true` can't self-register that client — surfacing the
67
- * requirement here keeps users from a silently-broken setup later.
65
+ * shared config. The PKCE browser flow (the user login runs every session)
66
+ * can't self-register that client — surfacing the requirement here keeps
67
+ * users from a silently-broken setup later.
68
68
  */
69
69
  function runConfigureCommand(binName, args) {
70
70
  let projectUrl;
@@ -72,9 +72,6 @@ function runConfigureCommand(binName, args) {
72
72
  let apiKey;
73
73
  let oauth2ClientId;
74
74
  let auditOnly = false;
75
- // `undefined` = not specified (leave the persisted value alone);
76
- // true/false = explicit enable/disable of the interactive user login.
77
- let userLogin;
78
75
  // `undefined` = not specified; a string sets it; empty string ("") clears it
79
76
  // (via --no-user-subject-namespace) to fall back to direct SubjectID.
80
77
  let userSubjectNamespace;
@@ -98,12 +95,6 @@ function runConfigureCommand(binName, args) {
98
95
  case "--audit-only":
99
96
  auditOnly = true;
100
97
  break;
101
- case "--user-login":
102
- userLogin = true;
103
- break;
104
- case "--no-user-login":
105
- userLogin = false;
106
- break;
107
98
  case "--user-subject-namespace":
108
99
  userSubjectNamespace = args[++i];
109
100
  break;
@@ -117,28 +108,23 @@ function runConfigureCommand(binName, args) {
117
108
  !apiKey &&
118
109
  !oauth2ClientId &&
119
110
  !auditOnly &&
120
- userLogin === undefined &&
121
111
  userSubjectNamespace === undefined) {
122
112
  const resolved = (0, config_js_1.resolveConfig)();
123
113
  const configPath = (0, config_js_1.getConfigPath)();
124
114
  console.log("Ory Plugin Configuration");
125
115
  console.log("========================");
126
116
  console.log("");
127
- console.log(`Config file: ${configPath}`);
117
+ console.log(`Config file: ${configPath}${fs.existsSync(configPath) ? "" : " (not created yet)"}`);
128
118
  console.log(`Project URL: ${resolved.projectUrl ?? "(not set)"} [${resolved.projectUrlSource}]`);
129
119
  console.log(`Project ID: ${resolved.projectId ?? "(not set)"} [${resolved.projectIdSource}]`);
130
120
  console.log(`API Key: ${resolved.apiKey ? "(set)" : "(not set)"} [${resolved.apiKeySource}]`);
131
121
  console.log(`OAuth2 Client ID: ${resolved.oauth2ClientId ?? "(not set)"} [${resolved.oauth2ClientIdSource}]`);
132
122
  console.log(`Audit Only: ${resolved.auditOnly ? "yes" : "no"}`);
133
- console.log(`User Login: ${resolved.userLogin ? "on" : "off"} [${resolved.userLoginSource}]`);
134
123
  console.log(`User subject ns: ${resolved.userSubjectNamespace ?? "(direct subject id)"} [${resolved.userSubjectNamespaceSource}]`);
135
124
  console.log("");
136
125
  console.log("To configure:");
137
126
  console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --project-url <URL> --oauth2-client-id <CLIENT_ID> [--api-key <KEY>]`);
138
127
  console.log("");
139
- console.log("To enable the interactive user login (PKCE browser flow at session start):");
140
- console.log(` npx ${binName} configure --user-login (disable with --no-user-login)`);
141
- console.log("");
142
128
  console.log("To address the user as a SubjectSet in permission checks (must match your tuples):");
143
129
  console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --user-subject-namespace User (clear with --no-user-subject-namespace)`);
144
130
  console.log("");
@@ -151,20 +137,14 @@ function runConfigureCommand(binName, args) {
151
137
  console.log(" # ORY_PROJECT_ID=<project uuid> is stored for admin operations (not an SDK URL).");
152
138
  console.log(" export ORY_OAUTH2_CLIENT_ID=<public OAuth2 client id>");
153
139
  console.log(" export ORY_AGENT_API_KEY=ory_pat_...");
154
- console.log(" export ORY_USER_LOGIN=true");
155
140
  return;
156
141
  }
157
142
  if (auditOnly) {
158
- // Audit-only mode: set the kill switch. Persist an explicit user-login
159
- // choice too if one was passed, so it takes effect once audit-only is
160
- // later turned off; audit-only itself disables login regardless.
161
- (0, config_js_1.saveConfig)({ auditOnly: true, ...(userLogin !== undefined ? { userLogin } : {}) });
143
+ // Audit-only mode: set the kill switch (disables auth and checks entirely).
144
+ (0, config_js_1.saveConfig)({ auditOnly: true });
162
145
  const configPath = (0, config_js_1.getConfigPath)();
163
146
  console.log(`Configuration saved to ${configPath}`);
164
147
  console.log(" Mode: audit-only (logging enabled, auth and permission checks disabled)");
165
- if (userLogin !== undefined) {
166
- console.log(` User login: ${userLogin ? "on" : "off"} (takes effect when audit-only is disabled)`);
167
- }
168
148
  console.log("");
169
149
  console.log("This configuration is shared across all Ory agent plugins.");
170
150
  return;
@@ -207,34 +187,19 @@ function runConfigureCommand(binName, args) {
207
187
  process.exit(1);
208
188
  }
209
189
  }
210
- // Enabling user login needs a project URL and a public OAuth2 client id
211
- // to complete the PKCE flow. Warn (don't block) if either is missing —
212
- // the operator may supply them separately or via env before running.
213
- if (userLogin === true) {
214
- // resolveConfig() already folds in the ORY_SDK_URL alias and the config
215
- // file; OR in the URL being set on this same invocation.
216
- const nextProjectUrl = projectUrl ?? (0, config_js_1.resolveConfig)().projectUrl;
217
- const nextClientId = oauth2ClientId ?? process.env.ORY_OAUTH2_CLIENT_ID ?? (0, config_js_1.loadConfig)().oauth2ClientId;
218
- if (!nextProjectUrl || !nextClientId) {
219
- const missing = [
220
- !nextProjectUrl ? "a project URL (--project-url / --sdk-url / ORY_PROJECT_URL)" : null,
221
- !nextClientId ? "an OAuth2 client id (--oauth2-client-id / ORY_OAUTH2_CLIENT_ID)" : null,
222
- ].filter(Boolean);
223
- console.warn(`Warning: user login is enabled but still missing ${missing.join(" and ")}.\n` +
224
- "The PKCE browser flow can't complete until both are configured.");
225
- }
226
- }
227
190
  const update = {};
228
191
  if (projectUrl)
229
192
  update.projectUrl = projectUrl;
230
193
  if (projectId)
231
194
  update.projectId = projectId;
232
- if (apiKey)
195
+ if (apiKey) {
233
196
  update.apiKey = apiKey;
197
+ // A hand-supplied key has no known token id; drop any stale id so uninstall
198
+ // never tries to delete a different token by an id that no longer matches.
199
+ update.apiKeyId = null;
200
+ }
234
201
  if (oauth2ClientId)
235
202
  update.oauth2ClientId = oauth2ClientId;
236
- if (userLogin !== undefined)
237
- update.userLogin = userLogin;
238
203
  // A non-empty namespace sets the SubjectSet namespace; the empty string
239
204
  // (from --no-user-subject-namespace) clears it (null ⇒ delete the key).
240
205
  if (userSubjectNamespace !== undefined) {
@@ -243,7 +208,7 @@ function runConfigureCommand(binName, args) {
243
208
  // Configuring an actual connection (a slug-based URL, api key, or client id)
244
209
  // implies leaving audit-only mode. A bare project id is only an admin
245
210
  // identifier — it doesn't connect anything on its own — so it doesn't flip
246
- // the flag; nor does a standalone user-login toggle.
211
+ // the flag.
247
212
  if (projectUrl || apiKey || oauth2ClientId)
248
213
  update.auditOnly = false;
249
214
  (0, config_js_1.saveConfig)(update);
@@ -257,13 +222,11 @@ function runConfigureCommand(binName, args) {
257
222
  console.log(` API Key: (set)`);
258
223
  if (oauth2ClientId)
259
224
  console.log(` OAuth2 Client ID: ${oauth2ClientId}`);
260
- if (userLogin !== undefined)
261
- console.log(` User Login: ${userLogin ? "on" : "off"}`);
262
225
  if (userSubjectNamespace !== undefined)
263
226
  console.log(` User subject namespace: ${userSubjectNamespace === "" ? "(cleared — direct subject id)" : userSubjectNamespace}`);
264
227
  console.log("");
265
228
  console.log("This configuration is shared across all Ory agent plugins.");
266
- console.log("Environment variables (ORY_PROJECT_URL, ORY_AGENT_API_KEY, ORY_OAUTH2_CLIENT_ID, ORY_USER_LOGIN) take precedence when set.");
229
+ console.log("Environment variables (ORY_PROJECT_URL, ORY_AGENT_API_KEY, ORY_OAUTH2_CLIENT_ID) take precedence when set.");
267
230
  }
268
231
  /**
269
232
  * Print the "Configuration:" block showing Ory project URL and API key status.
@@ -280,7 +243,6 @@ function printOryConfig() {
280
243
  console.log(` API Key: ${resolved.apiKey ? "(set)" : "NOT SET"} [source: ${resolved.apiKeySource}]`);
281
244
  console.log(` OAuth2 Client: ${resolved.oauth2ClientId ?? "NOT SET"} [source: ${resolved.oauth2ClientIdSource}]`);
282
245
  console.log(` Permission mode: ${resolved.permissionMode} [source: ${resolved.permissionModeSource}]`);
283
- console.log(` User login: ${resolved.userLogin ? "on" : "off"} [source: ${resolved.userLoginSource}]`);
284
246
  console.log(` Namespace: ${namespace}`);
285
247
  console.log(` User subject ns: ${resolved.userSubjectNamespace ?? "(direct subject id)"} [source: ${resolved.userSubjectNamespaceSource}]`);
286
248
  }
@@ -294,7 +256,6 @@ function printEnvironment() {
294
256
  ["ORY_PROJECT_URL", process.env.ORY_PROJECT_URL, false],
295
257
  ["ORY_SDK_URL", process.env.ORY_SDK_URL, false],
296
258
  ["ORY_PROJECT_ID", process.env.ORY_PROJECT_ID, false],
297
- ["ORY_USER_LOGIN", process.env.ORY_USER_LOGIN, false],
298
259
  [
299
260
  "ORY_AGENT_API_KEY",
300
261
  process.env.ORY_AGENT_API_KEY ? "(set)" : undefined,
package/dist/config.d.ts CHANGED
@@ -30,6 +30,27 @@ export interface OryUserCredentials {
30
30
  * restarts re-use the same agent identity instead of re-registering on
31
31
  * every session.
32
32
  */
33
+ /**
34
+ * The delegation edge recorded on a dynamically-registered OAuth2 client's
35
+ * `metadata` at registration time (see {@link OryAgentDynamicCredentials.delegation}).
36
+ *
37
+ * This is the **integrity anchor** for the delegation chain: it is bound to
38
+ * the OAuth2 client identity durably owned by Hydra / Ory Network and mirrored
39
+ * into local config, so the delegator can be resolved — and the derived Keto
40
+ * tuple rebuilt — even if the tuple is lost, corrupted, or never written.
41
+ */
42
+ export interface OryDelegationRecord {
43
+ /** The delegator, as a namespaced subject: `user:<sub>` or `agent:<sub>`. */
44
+ delegatedBy: string;
45
+ /** Which edge of the chain this client sits on. */
46
+ delegationType: "user-to-agent" | "agent-to-subagent";
47
+ /** Harness the delegation was established under (audit aid). */
48
+ harness?: string;
49
+ /** Sub-agent type, present only for `agent-to-subagent`. */
50
+ subAgentType?: string;
51
+ /** ISO-8601 timestamp the delegation was stamped. */
52
+ delegatedAt: string;
53
+ }
33
54
  export interface OryAgentDynamicCredentials {
34
55
  /** Issued client_id. */
35
56
  clientId: string;
@@ -45,6 +66,14 @@ export interface OryAgentDynamicCredentials {
45
66
  projectUrl: string;
46
67
  /** Harness name baked into the client_name (audit aid). */
47
68
  harness?: string;
69
+ /**
70
+ * The delegation edge recorded for this client at registration. Persisted
71
+ * here in local config only — Ory's public DCR endpoint rejects a `metadata`
72
+ * field, so it is never stored server-side. Absent when the delegator wasn't
73
+ * known at registration time (e.g. DCR bootstrapped from an out-of-band
74
+ * initial access token with no user/agent principal).
75
+ */
76
+ delegation?: OryDelegationRecord;
48
77
  }
49
78
  /** Credentials for the AI agent principal (machine identity). */
50
79
  export interface OryAgentCredentialsBlock {
@@ -88,10 +117,26 @@ export interface OryPluginConfig {
88
117
  * never be substituted for a slug when building it.
89
118
  */
90
119
  projectId?: string;
120
+ /**
121
+ * Human-readable project and workspace names, captured at install time for
122
+ * display only (e.g. the dashboard's connected-stack card). Not used to
123
+ * address any API — {@link projectUrl} / {@link projectId} do that.
124
+ */
125
+ projectName?: string;
126
+ workspaceName?: string;
91
127
  apiKey?: string;
128
+ /**
129
+ * Token id of the project API key stored in {@link apiKey}, captured when the
130
+ * installer mints the key via the Ory Console API. Ory only returns a key's
131
+ * secret at creation and deletion addresses the token by id (not by its
132
+ * secret value), so the id is persisted here purely so `uninstall` can delete
133
+ * the key server-side. Absent for keys minted before id-tracking, or supplied
134
+ * by hand via `configure --api-key`.
135
+ */
136
+ apiKeyId?: string;
92
137
  /**
93
138
  * Public OAuth2 client id used by the user PKCE browser flow when
94
- * `ORY_USER_LOGIN` is on. The client must be registered ahead of time
139
+ * the interactive user login runs (every session). The client must be registered ahead of time
95
140
  * in the Ory project with all four loopback redirect URIs
96
141
  * (`http://127.0.0.1:47823..47826/callback`) and
97
142
  * `token_endpoint_auth_method=none`. The local stack provisions one
@@ -107,14 +152,6 @@ export interface OryPluginConfig {
107
152
  * tuple set is correct. See {@link PermissionMode}.
108
153
  */
109
154
  permissionMode?: PermissionMode;
110
- /**
111
- * Whether the interactive user PKCE login runs at session start. When
112
- * true, every session runs `ensureUserAuthenticated`; when unset the
113
- * flow is a no-op. Set via `configure --user-login` / `--no-user-login`.
114
- * The `ORY_USER_LOGIN` env var overrides this when set. Requires an
115
- * OAuth2 client id ({@link oauth2ClientId}) to actually complete a login.
116
- */
117
- userLogin?: boolean;
118
155
  /**
119
156
  * Permission-check subject namespace for the human user. When set, the
120
157
  * user is addressed as a SubjectSet `<namespace>:<subject>` in permission
@@ -159,14 +196,6 @@ export declare function getConfigPath(): string;
159
196
  * does not exist or is invalid.
160
197
  */
161
198
  export declare function loadConfig(): OryPluginConfig;
162
- /**
163
- * Read `ORY_USER_LOGIN` from the environment. Returns `true`/`false` when
164
- * the var is set (any recognized truthy value enables it; anything else
165
- * disables it), or `undefined` when the var is absent/empty so callers
166
- * fall back to the config file. Centralized here so the user gate, status
167
- * CLI, and configure command resolve it identically.
168
- */
169
- export declare function parseUserLoginEnv(): boolean | undefined;
170
199
  /**
171
200
  * Save config to the config file. Merges with existing values — only
172
201
  * provided fields are overwritten. Concurrent processes serialize via a
@@ -209,13 +238,13 @@ export declare function looksLikeProjectId(value: string): boolean;
209
238
  export declare function resolveConfig(): {
210
239
  projectUrl?: string;
211
240
  projectId?: string;
241
+ projectName?: string;
242
+ workspaceName?: string;
212
243
  apiKey?: string;
213
244
  oauth2ClientId?: string;
214
245
  auditOnly: boolean;
215
246
  permissionMode: PermissionMode;
216
247
  permissionModeSource: "env" | "config" | "default";
217
- userLogin: boolean;
218
- userLoginSource: "env" | "config" | "default";
219
248
  userSubjectNamespace?: string;
220
249
  userSubjectNamespaceSource: "env" | "config" | "none";
221
250
  projectUrlSource: "env" | "config" | "none";