@ory/argus 0.13.9 → 1.0.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 (133) hide show
  1. package/README.md +31 -45
  2. package/assets/commands/temporal-up.md +1 -1
  3. package/assets/skills/auth-setup/SKILL.md +1 -1
  4. package/assets/skills/local-dev/SKILL.md +17 -7
  5. package/assets/skills/ory-build-agent/SKILL.md +43 -97
  6. package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -18
  7. package/assets/skills/ory-temporal-worker/SKILL.md +38 -42
  8. package/assets/skills/permissions-onboarding/SKILL.md +131 -104
  9. package/dist/adapters.d.ts +93 -30
  10. package/dist/adapters.js +464 -136
  11. package/dist/agent-auth.d.ts +258 -68
  12. package/dist/agent-auth.js +998 -202
  13. package/dist/auth-store.d.ts +37 -2
  14. package/dist/auth-store.js +37 -3
  15. package/dist/auth.d.ts +40 -4
  16. package/dist/auth.js +247 -19
  17. package/dist/bash-parser.d.ts +98 -0
  18. package/dist/bash-parser.js +396 -0
  19. package/dist/branding.d.ts +128 -0
  20. package/dist/branding.js +151 -0
  21. package/dist/build-info.json +4 -4
  22. package/dist/cli-invocation.d.ts +1 -1
  23. package/dist/cli-invocation.js +2 -1
  24. package/dist/cli.d.ts +20 -29
  25. package/dist/cli.js +271 -278
  26. package/dist/client.d.ts +175 -138
  27. package/dist/client.js +672 -391
  28. package/dist/config.d.ts +249 -57
  29. package/dist/config.js +486 -62
  30. package/dist/context.d.ts +10 -0
  31. package/dist/context.js +21 -0
  32. package/dist/contract-suite.d.ts +8 -8
  33. package/dist/contract-suite.js +88 -69
  34. package/dist/denial.d.ts +36 -3
  35. package/dist/denial.js +79 -10
  36. package/dist/event-reporter.d.ts +77 -0
  37. package/dist/event-reporter.js +776 -0
  38. package/dist/external-registrations-main.d.ts +10 -0
  39. package/dist/external-registrations-main.js +38 -0
  40. package/dist/external-registrations.d.ts +79 -0
  41. package/dist/external-registrations.js +188 -0
  42. package/dist/help-cli.d.ts +39 -0
  43. package/dist/help-cli.js +55 -0
  44. package/dist/hook-timeout.d.ts +64 -0
  45. package/dist/hook-timeout.js +88 -0
  46. package/dist/index.d.ts +31 -19
  47. package/dist/index.js +182 -31
  48. package/dist/lifecycle.d.ts +3 -3
  49. package/dist/lifecycle.js +38 -6
  50. package/dist/local/cli.js +11 -6
  51. package/dist/local/configs.d.ts +74 -18
  52. package/dist/local/configs.js +291 -84
  53. package/dist/local/health.d.ts +14 -0
  54. package/dist/local/health.js +50 -4
  55. package/dist/local/index.d.ts +2 -2
  56. package/dist/local/index.js +24 -10
  57. package/dist/local/manager.d.ts +20 -1
  58. package/dist/local/manager.js +160 -39
  59. package/dist/local/ports.d.ts +158 -0
  60. package/dist/local/ports.js +443 -0
  61. package/dist/local/seed.d.ts +22 -25
  62. package/dist/local/seed.js +88 -56
  63. package/dist/logger.d.ts +54 -25
  64. package/dist/logger.js +329 -63
  65. package/dist/mcp.d.ts +2 -2
  66. package/dist/mcp.js +10 -5
  67. package/dist/mirror-bootstrap.d.ts +48 -0
  68. package/dist/mirror-bootstrap.js +254 -0
  69. package/dist/opl.d.ts +289 -0
  70. package/dist/opl.js +446 -0
  71. package/dist/permission-mode.d.ts +87 -0
  72. package/dist/permission-mode.js +307 -0
  73. package/dist/permissions-cli.d.ts +13 -49
  74. package/dist/permissions-cli.js +154 -348
  75. package/dist/permissions.d.ts +148 -38
  76. package/dist/permissions.js +591 -45
  77. package/dist/post-install.d.ts +33 -0
  78. package/dist/post-install.js +127 -0
  79. package/dist/read-credential.d.ts +65 -0
  80. package/dist/read-credential.js +86 -0
  81. package/dist/registry/cli.js +5 -2
  82. package/dist/registry/config.d.ts +0 -17
  83. package/dist/registry/config.js +0 -23
  84. package/dist/registry/index.d.ts +1 -1
  85. package/dist/registry/index.js +2 -2
  86. package/dist/registry/manager.d.ts +4 -21
  87. package/dist/registry/manager.js +83 -55
  88. package/dist/runtime-credential.d.ts +140 -0
  89. package/dist/runtime-credential.js +572 -0
  90. package/dist/runtime.d.ts +408 -0
  91. package/dist/runtime.js +748 -0
  92. package/dist/setup.d.ts +23 -28
  93. package/dist/setup.js +57 -84
  94. package/dist/status-cli.d.ts +29 -13
  95. package/dist/status-cli.js +124 -144
  96. package/dist/status-data.d.ts +195 -0
  97. package/dist/status-data.js +333 -0
  98. package/dist/status-system.d.ts +24 -0
  99. package/dist/status-system.js +56 -0
  100. package/dist/subject.d.ts +126 -20
  101. package/dist/subject.js +215 -30
  102. package/dist/testing.d.ts +74 -38
  103. package/dist/testing.js +185 -68
  104. package/dist/tool-catalog.d.ts +53 -11
  105. package/dist/tool-catalog.js +164 -13
  106. package/dist/tool-metadata.d.ts +7 -6
  107. package/dist/tool-metadata.js +6 -5
  108. package/dist/types.d.ts +11 -1
  109. package/dist/uninstall.d.ts +74 -19
  110. package/dist/uninstall.js +224 -49
  111. package/dist/user-login.d.ts +22 -16
  112. package/dist/user-login.js +67 -96
  113. package/dist/watch-cli.d.ts +6 -0
  114. package/dist/watch-cli.js +217 -0
  115. package/package.json +3 -11
  116. package/dist/dev.d.ts +0 -103
  117. package/dist/dev.js +0 -584
  118. package/dist/interactive-setup.d.ts +0 -165
  119. package/dist/interactive-setup.js +0 -1546
  120. package/dist/local/jaeger-main.d.ts +0 -13
  121. package/dist/local/jaeger-main.js +0 -85
  122. package/dist/local/jaeger.d.ts +0 -50
  123. package/dist/local/jaeger.js +0 -162
  124. package/dist/otel/exporter.d.ts +0 -17
  125. package/dist/otel/exporter.js +0 -12
  126. package/dist/otel/index.d.ts +0 -2
  127. package/dist/otel/index.js +0 -8
  128. package/dist/otel/otlp.d.ts +0 -103
  129. package/dist/otel/otlp.js +0 -385
  130. package/dist/tracer.d.ts +0 -190
  131. package/dist/tracer.js +0 -481
  132. package/dist/watch-sandbox.d.ts +0 -9
  133. package/dist/watch-sandbox.js +0 -81
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * 1. Resolve config (env + ~/.config/ory-agent-plugins/config.json).
7
7
  * 2. If no project URL, prompt for one when a TTY is available;
8
- * otherwise skip with an audit span.
8
+ * otherwise skip with an audit event.
9
9
  * 3. If a session/oauth2 token is already in env, short-circuit ok.
10
10
  * 4. If persisted tokens are valid, return ok.
11
11
  * 5. If they are expired with a refresh_token, refresh.
@@ -15,14 +15,20 @@
15
15
  * paste the URL into any browser that can reach 127.0.0.1. Only
16
16
  * truly unattended (CI=true) environments short-circuit early.
17
17
  *
18
- * Every terminal path emits exactly one `user.auth` trace span so that
18
+ * Every terminal path emits exactly one `user.auth` activity event so that
19
19
  * the audit trail is complete regardless of outcome.
20
20
  *
21
- * The whole flow is a no-op (mode `disabled`) unless user login is
22
- * enabled either via the `ORY_USER_LOGIN` env var (values `1`, `true`,
23
- * `yes`, `on`) or persisted in the shared config file (`userLogin: true`,
24
- * set with `configure --user-login`). The env var overrides the config
25
- * file when set.
21
+ * The flow runs on **every** session and is **never** blocking: it
22
+ * establishes or refreshes the user identity for attribution, delegation,
23
+ * and permission-subject resolution, but a failure to authenticate never
24
+ * stops the session. Enforcement is governed solely by `permissionMode`
25
+ * (observe/enforce) at tool-call time — see `checkAndDecide`. The one
26
+ * exception is Agent Security not being connected at all (no project URL
27
+ * and OAuth2 client id), in which case there is nothing to sign in to and
28
+ * the flow no-ops with mode `not_connected`. When the user can't be
29
+ * authenticated the session still
30
+ * proceeds; under `enforce` a missing user identity naturally denies at
31
+ * the tool (no matching tuples), and under `observe` it is audited.
26
32
  *
27
33
  * This authenticates the *user* (the human at the keyboard). The
28
34
  * separate agent identity (the AI process making the calls) is resolved
@@ -34,22 +40,15 @@ exports.ensureAuthenticated = void 0;
34
40
  exports.ensureUserAuthenticated = ensureUserAuthenticated;
35
41
  const config_js_1 = require("./config.js");
36
42
  const cli_js_1 = require("./cli.js");
37
- const cli_invocation_js_1 = require("./cli-invocation.js");
38
43
  const auth_store_js_1 = require("./auth-store.js");
39
44
  const auth_js_1 = require("./auth.js");
40
- function isUserLoginEnabled() {
41
- // Resolves ORY_USER_LOGIN (env, when set) over the persisted
42
- // `userLogin` config flag. Centralized in resolveConfig so the gate,
43
- // status CLI, and configure command stay in lockstep.
44
- return (0, config_js_1.resolveConfig)().userLogin;
45
- }
46
45
  function clientId() {
47
46
  // resolveConfig already merges env (ORY_OAUTH2_CLIENT_ID) with the
48
47
  // persisted value, env winning. Centralizing here keeps the user gate,
49
48
  // status CLI, and configure command in lockstep on resolution order.
50
49
  return (0, config_js_1.resolveConfig)().oauth2ClientId;
51
50
  }
52
- function recordAuthSpan(client, decision) {
51
+ function recordAuthActivity(client, decision) {
53
52
  const status = decision.mode === "ok" || decision.mode === "refreshed" || decision.mode === "env_token"
54
53
  ? "ok"
55
54
  : decision.mode === "declined"
@@ -57,7 +56,7 @@ function recordAuthSpan(client, decision) {
57
56
  : decision.mode === "error"
58
57
  ? "error"
59
58
  : "skipped";
60
- client.tracer.record("user.auth", status, {
59
+ client.logger.activity("user.auth", status, {
61
60
  attributes: {
62
61
  mode: decision.mode,
63
62
  reason: decision.reason,
@@ -71,34 +70,25 @@ function recordAuthSpan(client, decision) {
71
70
  * to authenticate the human user. Always returns a decision; never throws.
72
71
  */
73
72
  async function ensureUserAuthenticated(client, options) {
74
- if (!isUserLoginEnabled()) {
75
- const decision = {
76
- proceed: true,
77
- mode: "disabled",
78
- reason: "User login is not enabled (ORY_USER_LOGIN env / userLogin config)",
79
- };
80
- recordAuthSpan(client, decision);
81
- return decision;
82
- }
83
73
  try {
84
74
  const decision = await runUserLogin(client, options);
85
75
  attachUserPrincipal(client, decision);
86
- recordAuthSpan(client, decision);
76
+ recordAuthActivity(client, decision);
87
77
  return decision;
88
78
  }
89
79
  catch (err) {
90
80
  const decision = {
91
- proceed: !options.allowBlock,
81
+ proceed: true,
92
82
  mode: "error",
93
83
  reason: err instanceof Error ? err.message : String(err),
94
84
  };
95
- recordAuthSpan(client, decision);
85
+ recordAuthActivity(client, decision);
96
86
  return decision;
97
87
  }
98
88
  }
99
89
  /**
100
90
  * Attach the resolved user identity to the client so downstream
101
- * permission checks and trace spans can reference it. Only fires for
91
+ * permission checks and activity events can reference it. Only fires for
102
92
  * modes that actually authenticated a user — declined/skipped/error
103
93
  * leave the principal alone.
104
94
  */
@@ -120,69 +110,43 @@ function attachUserPrincipal(client, decision) {
120
110
  return;
121
111
  }
122
112
  if (decision.mode === "env_token") {
123
- const subject = process.env.ORY_USER_SUBJECT_ID;
124
- const token = process.env.ORY_USER_SESSION_TOKEN ??
125
- process.env.ORY_USER_OAUTH2_TOKEN ??
126
- process.env.ORY_SESSION_TOKEN ??
127
- process.env.ORY_OAUTH2_TOKEN;
128
- client.setUserPrincipal({
129
- ...(subject ? { subject } : {}),
130
- ...(token ? { token } : {}),
131
- });
113
+ // Same reader the per-client rehydration uses, so the credential this gate
114
+ // attaches is exactly the one later lifecycle events will pick up.
115
+ client.setUserPrincipal((0, auth_store_js_1.readEnvUserCredential)());
132
116
  }
133
117
  }
134
118
  async function runUserLogin(client, options) {
135
119
  const ttyCheck = options.isTtyAvailableFn ?? cli_js_1.isTtyAvailable;
136
120
  const tty = ttyCheck();
137
121
  let resolved = (0, config_js_1.resolveConfig)();
138
- if (resolved.auditOnly) {
122
+ // Agent Security isn't connected, so there is no project to sign in to.
123
+ // Nothing is lost: the plugin's developer-experience half doesn't need an
124
+ // identity.
125
+ if (!resolved.security.connected) {
139
126
  return {
140
127
  proceed: true,
141
- mode: "audit_only",
142
- reason: "Configured for audit-only mode; user login is a no-op",
128
+ mode: "not_connected",
129
+ reason: `Ory Agent Security is not connected (${(0, config_js_1.describeSecurityGap)(resolved.security)}); user login is a no-op`,
143
130
  };
144
131
  }
145
- // 1. Project URL.
146
- if (!resolved.projectUrl) {
147
- if (!tty) {
148
- return {
149
- proceed: !options.allowBlock,
150
- mode: "skipped",
151
- reason: "No ORY_PROJECT_URL configured and no TTY to prompt",
152
- };
153
- }
154
- const promptFn = options.promptForProjectUrlFn ?? cli_js_1.promptForProjectUrl;
155
- const url = await promptFn(options.binName);
156
- if (!url) {
157
- return {
158
- proceed: !options.allowBlock,
159
- mode: "declined",
160
- reason: "User declined to enter an Ory project URL",
161
- };
162
- }
163
- resolved = (0, config_js_1.resolveConfig)();
164
- if (!resolved.projectUrl) {
165
- return {
166
- proceed: !options.allowBlock,
167
- mode: "error",
168
- reason: "Project URL was entered but config did not persist",
169
- };
170
- }
171
- }
172
- // 2. Pre-supplied env tokens short-circuit the browser flow (CI, scripted
173
- // runs). ORY_USER_* are the documented names; the legacy single-identity
174
- // ORY_SESSION_TOKEN / ORY_OAUTH2_TOKEN are still honored.
175
- if (process.env.ORY_USER_SESSION_TOKEN ||
176
- process.env.ORY_USER_OAUTH2_TOKEN ||
177
- process.env.ORY_SESSION_TOKEN ||
178
- process.env.ORY_OAUTH2_TOKEN) {
132
+ // `security.connected` guarantees both values are non-empty; narrow once
133
+ // here so the rest of the flow doesn't re-check what the gate established.
134
+ const projectUrl = resolved.projectUrl;
135
+ // Past this point both connection values are present, which is why there is
136
+ // no "prompt for a project URL" or "missing client id" branch here: either
137
+ // one absent means not connected, and that is handled above as a normal
138
+ // state rather than something to interrupt the user about.
139
+ // 1. A pre-supplied OAuth2 access token short-circuits the browser flow
140
+ // (CI, scripted runs). `ORY_USER_OAUTH2_TOKEN` is the only accepted
141
+ // variable see `readEnvUserCredential`.
142
+ if ((0, auth_store_js_1.readEnvUserCredential)().token) {
179
143
  return {
180
144
  proceed: true,
181
145
  mode: "env_token",
182
- reason: "Session/OAuth2 token supplied via environment",
146
+ reason: "OAuth2 access token supplied via environment",
183
147
  };
184
148
  }
185
- // 3. Persisted tokens.
149
+ // 2. Persisted tokens.
186
150
  const existing = (0, auth_store_js_1.loadTokens)();
187
151
  if (existing && !(0, auth_store_js_1.isExpired)(existing)) {
188
152
  return {
@@ -197,7 +161,7 @@ async function runUserLogin(client, options) {
197
161
  if (cid) {
198
162
  try {
199
163
  const refreshed = await (0, auth_store_js_1.refreshAndSave)({
200
- projectUrl: resolved.projectUrl,
164
+ projectUrl,
201
165
  clientId: cid,
202
166
  current: existing,
203
167
  });
@@ -216,19 +180,9 @@ async function runUserLogin(client, options) {
216
180
  }
217
181
  }
218
182
  }
219
- // 4. Browser flow. Requires a registered OAuth2 client id.
183
+ // 3. Browser flow. The client id is guaranteed present — it is half of what
184
+ // "connected" means, checked at the top of this function.
220
185
  const cid = clientId();
221
- if (!cid) {
222
- return {
223
- proceed: !options.allowBlock,
224
- mode: "skipped",
225
- reason: "ORY_OAUTH2_CLIENT_ID is not set; cannot start browser login (run `" +
226
- (0, cli_invocation_js_1.oryNpx)(options.binName) +
227
- " configure --oauth2-client-id <id>` after registering a public OAuth2 client " +
228
- "in your Ory project with all four loopback redirect URIs: " +
229
- "http://127.0.0.1:47823..47826/callback)",
230
- };
231
- }
232
186
  // No TTY check here on purpose: PKCE only needs a browser that can reach
233
187
  // the loopback callback port, not stdin. `pkceLogin` prints the
234
188
  // authorize URL to stderr so users in non-TTY environments (SSH without
@@ -236,7 +190,8 @@ async function runUserLogin(client, options) {
236
190
  // complete sign-in by pasting the URL into any browser that can reach
237
191
  // 127.0.0.1. Truly unattended runs (CI=true) are short-circuited by
238
192
  // `pkceLogin` itself via `detectHeadless`, and operators can bypass
239
- // login entirely with `ORY_USER_SESSION_TOKEN` or `ORY_USER_LOGIN=false`.
193
+ // login entirely by supplying `ORY_USER_OAUTH2_TOKEN`, and enforcement
194
+ // consequences are governed by `permissionMode`, not by this gate.
240
195
  // PKCE-flight lock so concurrent processes share a single browser flow.
241
196
  const lock = (0, auth_store_js_1.tryAcquirePkceFlightLock)();
242
197
  if (!lock) {
@@ -251,7 +206,7 @@ async function runUserLogin(client, options) {
251
206
  };
252
207
  }
253
208
  return {
254
- proceed: !options.allowBlock,
209
+ proceed: true,
255
210
  mode: "skipped",
256
211
  reason: "Another agent process is mid-login; gave up waiting",
257
212
  };
@@ -259,7 +214,7 @@ async function runUserLogin(client, options) {
259
214
  try {
260
215
  const loginFn = options.loginFn ?? auth_js_1.pkceLogin;
261
216
  const outcome = await loginFn({
262
- projectUrl: resolved.projectUrl,
217
+ projectUrl,
263
218
  clientId: cid,
264
219
  });
265
220
  if (outcome.kind === "ok") {
@@ -272,15 +227,19 @@ async function runUserLogin(client, options) {
272
227
  };
273
228
  }
274
229
  return {
275
- proceed: !options.allowBlock,
230
+ proceed: true,
276
231
  mode: declineToMode(outcome.reason),
277
- reason: declineMessage(outcome.reason),
232
+ reason: appendDetail(declineMessage(outcome.reason), outcome.detail),
278
233
  };
279
234
  }
280
235
  finally {
281
236
  lock.release();
282
237
  }
283
238
  }
239
+ /** Append a secret-free diagnostic to a decline message when one is present. */
240
+ function appendDetail(message, detail) {
241
+ return detail ? `${message} — ${detail}` : message;
242
+ }
284
243
  function declineToMode(reason) {
285
244
  switch (reason) {
286
245
  case "user_denied":
@@ -293,6 +252,8 @@ function declineToMode(reason) {
293
252
  return "skipped";
294
253
  case "state_mismatch":
295
254
  case "token_exchange_failed":
255
+ case "invalid_scope":
256
+ case "oauth_error":
296
257
  return "error";
297
258
  }
298
259
  }
@@ -301,7 +262,13 @@ function declineMessage(reason) {
301
262
  case "headless":
302
263
  return "Browser login skipped: environment is headless (CI/SSH/no DISPLAY)";
303
264
  case "timeout":
304
- return "Browser login timed out before the user completed sign-in";
265
+ // Name the consequence, not just the event. This is the one decline the
266
+ // user can fix by simply retrying, and under `enforce` its after-effect
267
+ // (every tool denied, for want of a user identity) is otherwise
268
+ // unattributable to a sign-in that quietly ran out of time (#220).
269
+ return (`Browser login timed out after ${Math.round(auth_js_1.DEFAULT_LOGIN_TIMEOUT_MS / 1000)}s ` +
270
+ "before sign-in completed — the session has no Ory user identity. " +
271
+ "Start a new session to sign in again");
305
272
  case "user_denied":
306
273
  return "User declined the OAuth2 consent screen";
307
274
  case "state_mismatch":
@@ -314,6 +281,10 @@ function declineMessage(reason) {
314
281
  return "Login was aborted by the caller";
315
282
  case "token_exchange_failed":
316
283
  return "Authorization code exchange failed at /oauth2/token";
284
+ case "invalid_scope":
285
+ return "Ory rejected the requested OAuth2 scope (invalid_scope) — the login client isn't allowed it";
286
+ case "oauth_error":
287
+ return "Ory returned an OAuth2 error on the login redirect";
317
288
  }
318
289
  }
319
290
  /**
@@ -0,0 +1,6 @@
1
+ export interface WatchCommandOptions {
2
+ signal?: AbortSignal;
3
+ pollIntervalMs?: number;
4
+ }
5
+ /** Follow one harness's unified activity/debug log until interrupted. */
6
+ export declare function runWatchCommand(binName: string, harness: string, args: readonly string[], options?: WatchCommandOptions): Promise<number>;
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runWatchCommand = runWatchCommand;
37
+ const fs = __importStar(require("node:fs"));
38
+ const client_js_1 = require("./client.js");
39
+ const logger_js_1 = require("./logger.js");
40
+ const ui_js_1 = require("./ui.js");
41
+ const DEFAULT_HISTORY_LINES = 10;
42
+ const DEFAULT_POLL_INTERVAL_MS = 250;
43
+ const MAX_HISTORY_BYTES = 64 * 1024;
44
+ function parseWatchArgs(binName, args) {
45
+ let json = false;
46
+ let lines = DEFAULT_HISTORY_LINES;
47
+ for (let index = 0; index < args.length; index++) {
48
+ const arg = args[index];
49
+ if (arg === "--json") {
50
+ json = true;
51
+ continue;
52
+ }
53
+ if (arg === "--lines") {
54
+ const value = Number(args[++index]);
55
+ if (Number.isInteger(value) && value >= 0) {
56
+ lines = value;
57
+ continue;
58
+ }
59
+ }
60
+ console.error(`Usage: ${binName} watch [--json] [--lines <count>]`);
61
+ return undefined;
62
+ }
63
+ return { json, lines };
64
+ }
65
+ const WATCH_LABEL_WIDTH = 13;
66
+ const WATCH_EVENT_WIDTH = 30;
67
+ function colorLabel(label) {
68
+ if (label === "ALLOW" || label === "OK")
69
+ return ui_js_1.brand.green(label);
70
+ if (label === "DENY" || label === "DENIED" || label === "ERROR")
71
+ return ui_js_1.brand.rose(label);
72
+ if (label === "OBSERVE" || label === "FAIL OPEN" || label === "WARN") {
73
+ return ui_js_1.brand.yellow(label);
74
+ }
75
+ return ui_js_1.style.gray(label);
76
+ }
77
+ function detailLabel(detail) {
78
+ const separator = detail.indexOf("=");
79
+ if (separator < 0)
80
+ return detail;
81
+ return `${ui_js_1.style.gray(detail.slice(0, separator))}=${detail.slice(separator + 1)}`;
82
+ }
83
+ function renderEntry(entry) {
84
+ const { time, event, marker, details } = (0, logger_js_1.formatLogEntryParts)(entry);
85
+ const decision = details.find((detail) => detail.startsWith("decision="))?.slice(9);
86
+ const status = details.find((detail) => detail.startsWith("status="))?.slice(7);
87
+ const label = (decision ?? status ?? marker.replaceAll(/[\[\]]/g, "")).replaceAll("_", " ").toUpperCase();
88
+ const remaining = details.filter((detail) => !detail.startsWith("decision=") && !detail.startsWith("status="));
89
+ const labelPadding = " ".repeat(Math.max(1, WATCH_LABEL_WIDTH - label.length));
90
+ const eventPadding = " ".repeat(Math.max(1, WATCH_EVENT_WIDTH - event.length));
91
+ const metadata = remaining.length > 0
92
+ ? remaining.map(detailLabel).join(ui_js_1.style.dim(" | "))
93
+ : "";
94
+ console.log(`${ui_js_1.style.dim(time)} ${colorLabel(label)}${labelPadding}${ui_js_1.style.bold(event)}` +
95
+ `${eventPadding}${metadata}`);
96
+ }
97
+ function renderLine(line, json) {
98
+ if (json) {
99
+ console.log(line);
100
+ return;
101
+ }
102
+ try {
103
+ renderEntry(JSON.parse(line));
104
+ }
105
+ catch {
106
+ console.log(ui_js_1.brand.rose("INVALID") + ` ${line.slice(0, 160)}`);
107
+ }
108
+ }
109
+ function readHistory(logFile, lines, json) {
110
+ const stat = fs.statSync(logFile);
111
+ if (lines === 0 || stat.size === 0)
112
+ return stat.size;
113
+ const start = Math.max(0, stat.size - MAX_HISTORY_BYTES);
114
+ const length = stat.size - start;
115
+ const buffer = Buffer.alloc(length);
116
+ const fd = fs.openSync(logFile, "r");
117
+ try {
118
+ fs.readSync(fd, buffer, 0, length, start);
119
+ }
120
+ finally {
121
+ fs.closeSync(fd);
122
+ }
123
+ let history = buffer.toString("utf8").split("\n");
124
+ if (start > 0)
125
+ history = history.slice(1);
126
+ for (const line of history.filter(Boolean).slice(-lines))
127
+ renderLine(line, json);
128
+ return stat.size;
129
+ }
130
+ function readRange(logFile, start, end) {
131
+ const length = end - start;
132
+ const buffer = Buffer.alloc(length);
133
+ const fd = fs.openSync(logFile, "r");
134
+ try {
135
+ fs.readSync(fd, buffer, 0, length, start);
136
+ }
137
+ finally {
138
+ fs.closeSync(fd);
139
+ }
140
+ return buffer.toString("utf8");
141
+ }
142
+ function delay(ms) {
143
+ return new Promise((resolve) => setTimeout(resolve, ms));
144
+ }
145
+ /** Follow one harness's unified activity/debug log until interrupted. */
146
+ async function runWatchCommand(binName, harness, args, options = {}) {
147
+ const parsed = parseWatchArgs(binName, args);
148
+ if (!parsed)
149
+ return 1;
150
+ const logFile = (0, client_js_1.resolveDebugLogPath)(harness);
151
+ if (!logFile) {
152
+ console.error("Activity/debug logging is disabled because ORY_AGENT_LOG_FILE is empty.");
153
+ return 1;
154
+ }
155
+ const controller = options.signal ? undefined : new AbortController();
156
+ const signal = options.signal ?? controller?.signal;
157
+ const stop = () => controller?.abort();
158
+ if (controller) {
159
+ process.once("SIGINT", stop);
160
+ process.once("SIGTERM", stop);
161
+ }
162
+ if (parsed.json) {
163
+ console.log(`Watching ${logFile} (Ctrl-C to stop)`);
164
+ }
165
+ else {
166
+ console.log(ui_js_1.style.bold("Watching plugin activity"));
167
+ console.log(`${ui_js_1.style.gray("file")} ${logFile}`);
168
+ console.log(`${ui_js_1.style.gray("stop")} Ctrl-C`);
169
+ console.log("");
170
+ }
171
+ let offset = 0;
172
+ let fileIdentity;
173
+ let remainder = "";
174
+ try {
175
+ try {
176
+ const stat = fs.statSync(logFile);
177
+ fileIdentity = `${stat.dev}:${stat.ino}`;
178
+ offset = readHistory(logFile, parsed.lines, parsed.json);
179
+ }
180
+ catch {
181
+ console.log("Waiting for the first plugin event...");
182
+ }
183
+ while (!signal?.aborted) {
184
+ await delay(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
185
+ if (signal?.aborted || !fs.existsSync(logFile))
186
+ continue;
187
+ try {
188
+ const stat = fs.statSync(logFile);
189
+ const nextIdentity = `${stat.dev}:${stat.ino}`;
190
+ if (fileIdentity !== nextIdentity || stat.size < offset) {
191
+ offset = 0;
192
+ remainder = "";
193
+ fileIdentity = nextIdentity;
194
+ }
195
+ if (stat.size === offset)
196
+ continue;
197
+ const chunk = remainder + readRange(logFile, offset, stat.size);
198
+ offset = stat.size;
199
+ const complete = chunk.split("\n");
200
+ remainder = complete.pop() ?? "";
201
+ for (const line of complete)
202
+ if (line)
203
+ renderLine(line, parsed.json);
204
+ }
205
+ catch {
206
+ // The writer may replace the file between stat and read; retry next poll.
207
+ }
208
+ }
209
+ return 0;
210
+ }
211
+ finally {
212
+ if (controller) {
213
+ process.off("SIGINT", stop);
214
+ process.off("SIGTERM", stop);
215
+ }
216
+ }
217
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ory/argus",
3
- "version": "0.13.9",
3
+ "version": "1.0.0",
4
4
  "description": "Ory Argus: the core API for building authentication, authorization, and audit into AI agent harness plugins, extensions, and custom integrations",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ory.com",
@@ -36,8 +36,6 @@
36
36
  "agent-security",
37
37
  "guardrails",
38
38
  "llm",
39
- "tracing",
40
- "distributed-tracing",
41
39
  "observability",
42
40
  "kratos",
43
41
  "keto",
@@ -61,19 +59,13 @@
61
59
  "files": [
62
60
  "dist",
63
61
  "assets",
64
- "!dist/dev",
65
62
  "!dist/**/*.tsbuildinfo"
66
63
  ],
67
64
  "dependencies": {
68
- "@opentelemetry/api": "^1.9.0",
69
- "@opentelemetry/core": "^2.8.0",
70
- "@opentelemetry/exporter-trace-otlp-http": "^0.219.0",
71
- "@opentelemetry/exporter-trace-otlp-proto": "^0.219.0",
72
- "@opentelemetry/resources": "^2.8.0",
73
- "@opentelemetry/sdk-trace-base": "^2.8.0",
74
65
  "@ory/client": "^1.22.37",
66
+ "@vscode/tree-sitter-wasm": "^0.3.1",
75
67
  "open": "^11.0.0",
76
- "reo-census": "^1.2.8"
68
+ "web-tree-sitter": "^0.26.11"
77
69
  },
78
70
  "engines": {
79
71
  "node": ">=22"