@ory/argus 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +134 -0
  2. package/assets/commands/local-down.md +19 -0
  3. package/assets/commands/local-up.md +27 -0
  4. package/assets/skills/auth-setup/SKILL.md +279 -0
  5. package/assets/skills/local-dev/SKILL.md +206 -0
  6. package/assets/skills/login-flow/SKILL.md +383 -0
  7. package/assets/skills/social-login/SKILL.md +312 -0
  8. package/dist/agent-auth.d.ts +204 -0
  9. package/dist/agent-auth.js +553 -0
  10. package/dist/auth-gate.d.ts +71 -0
  11. package/dist/auth-gate.js +308 -0
  12. package/dist/auth-store.d.ts +75 -0
  13. package/dist/auth-store.js +261 -0
  14. package/dist/auth.d.ts +93 -0
  15. package/dist/auth.js +323 -0
  16. package/dist/cli.d.ts +73 -0
  17. package/dist/cli.js +484 -0
  18. package/dist/client.d.ts +158 -0
  19. package/dist/client.js +679 -0
  20. package/dist/config.d.ts +135 -0
  21. package/dist/config.js +344 -0
  22. package/dist/denial.d.ts +79 -0
  23. package/dist/denial.js +103 -0
  24. package/dist/dev.d.ts +95 -0
  25. package/dist/dev.js +514 -0
  26. package/dist/index.d.ts +20 -0
  27. package/dist/index.js +137 -0
  28. package/dist/local/cli.d.ts +12 -0
  29. package/dist/local/cli.js +95 -0
  30. package/dist/local/configs.d.ts +89 -0
  31. package/dist/local/configs.js +634 -0
  32. package/dist/local/health.d.ts +32 -0
  33. package/dist/local/health.js +65 -0
  34. package/dist/local/index.d.ts +6 -0
  35. package/dist/local/index.js +38 -0
  36. package/dist/local/jaeger-main.d.ts +13 -0
  37. package/dist/local/jaeger-main.js +85 -0
  38. package/dist/local/jaeger.d.ts +50 -0
  39. package/dist/local/jaeger.js +162 -0
  40. package/dist/local/main.d.ts +7 -0
  41. package/dist/local/main.js +14 -0
  42. package/dist/local/manager.d.ts +45 -0
  43. package/dist/local/manager.js +676 -0
  44. package/dist/local/seed.d.ts +71 -0
  45. package/dist/local/seed.js +237 -0
  46. package/dist/logger.d.ts +29 -0
  47. package/dist/logger.js +139 -0
  48. package/dist/mcp.d.ts +76 -0
  49. package/dist/mcp.js +122 -0
  50. package/dist/otel/exporter.d.ts +17 -0
  51. package/dist/otel/exporter.js +12 -0
  52. package/dist/otel/index.d.ts +2 -0
  53. package/dist/otel/index.js +8 -0
  54. package/dist/otel/otlp-http.d.ts +116 -0
  55. package/dist/otel/otlp-http.js +322 -0
  56. package/dist/registry/cli.d.ts +12 -0
  57. package/dist/registry/cli.js +76 -0
  58. package/dist/registry/config.d.ts +23 -0
  59. package/dist/registry/config.js +80 -0
  60. package/dist/registry/index.d.ts +3 -0
  61. package/dist/registry/index.js +21 -0
  62. package/dist/registry/main.d.ts +7 -0
  63. package/dist/registry/main.js +14 -0
  64. package/dist/registry/manager.d.ts +38 -0
  65. package/dist/registry/manager.js +674 -0
  66. package/dist/setup.d.ts +118 -0
  67. package/dist/setup.js +398 -0
  68. package/dist/skills.d.ts +78 -0
  69. package/dist/skills.js +264 -0
  70. package/dist/subject.d.ts +43 -0
  71. package/dist/subject.js +55 -0
  72. package/dist/tool-metadata.d.ts +41 -0
  73. package/dist/tool-metadata.js +127 -0
  74. package/dist/tracer.d.ts +172 -0
  75. package/dist/tracer.js +452 -0
  76. package/dist/types.d.ts +57 -0
  77. package/dist/types.js +3 -0
  78. package/dist/watch-sandbox.d.ts +9 -0
  79. package/dist/watch-sandbox.js +81 -0
  80. package/package.json +79 -0
package/dist/dev.d.ts ADDED
@@ -0,0 +1,95 @@
1
+ import { type SeedResult } from "./local/seed.js";
2
+ export interface InstallContext {
3
+ /** Absolute path to the sandbox directory used as install/launch cwd. */
4
+ sandboxDir: string;
5
+ /**
6
+ * Run `npm install <package>` inside the sandbox against the local registry.
7
+ * Defaults the package name to `@ory/<harnessName>`.
8
+ */
9
+ npmInstall(packageName?: string): void;
10
+ /**
11
+ * Run `npx --package=<pkg> <bin> ...args` from the sandbox cwd against the
12
+ * local registry. Defaults the package to `@ory/<harnessName>`
13
+ * and the binary to the launcher's configured `binaryName` (or
14
+ * `ory-<harnessName>` if not set).
15
+ */
16
+ npxCli(args: string[], opts?: {
17
+ packageName?: string;
18
+ binaryName?: string;
19
+ }): void;
20
+ }
21
+ export interface DevLauncherConfig {
22
+ /** Harness identifier — used for sandbox dir name and default package name, e.g. "claude-code" */
23
+ harnessName: string;
24
+ /** CLI command to launch, e.g. "claude", "codex", "gemini", "opencode" */
25
+ command: string;
26
+ /** Absolute path to the plugin package root (used to locate the workspace root) */
27
+ packageRoot: string;
28
+ /**
29
+ * Default binary name for `npxCli` calls. Defaults to `ory-<harnessName>`.
30
+ * Override when the plugin's published binary doesn't match the harness
31
+ * directory name (e.g. claude-code exposes `ory-claude`, gemini-cli exposes
32
+ * `ory-gemini`).
33
+ */
34
+ binaryName?: string;
35
+ /**
36
+ * Run the harness's documented install flow (the README's `npx ory-<harness> install`
37
+ * commands) against the local registry. Each launcher invokes the install steps
38
+ * appropriate for its harness — the launcher itself never hand-writes config files.
39
+ */
40
+ install(ctx: InstallContext): void;
41
+ /** Extra tip lines to print before launch */
42
+ extraTips?: string[];
43
+ }
44
+ /**
45
+ * Parse the dev-launcher CLI args, splitting out launcher-only flags from the
46
+ * args that should be forwarded to the harness binary.
47
+ *
48
+ * Launcher-only flags:
49
+ * --no-local Opt out of the auto-managed local Ory stack (local Ory is
50
+ * the default so multiple plugins can share one stack).
51
+ * --fresh Wipe runtime state before launching: stop and remove the
52
+ * local Ory stack, Verdaccio registry, and Jaeger container
53
+ * (including their volumes and on-disk state), remove this
54
+ * harness's sandbox dir, and delete the shared user config
55
+ * dir. Build artifacts and node_modules are not touched —
56
+ * use `pnpm clean:all` followed by `pnpm install` for that.
57
+ */
58
+ export declare function parseDevLauncherArgs(argv: readonly string[]): {
59
+ noLocalFlag: boolean;
60
+ freshFlag: boolean;
61
+ forwardedArgs: string[];
62
+ };
63
+ /**
64
+ * Decide whether the dev launcher should bring up a local Ory stack and seed
65
+ * it for the harness to authenticate against. Local Ory is the default so
66
+ * multiple harness plugins can share a single stack while developing — that
67
+ * mimics the production case of many harnesses sharing one Ory deployment.
68
+ *
69
+ * Returns `false` only when the run was explicitly opted out, either via the
70
+ * `--no-local` CLI flag or by setting `ORY_DEV_LOCAL` to a falsy value
71
+ * (`0`, `false`, `no`, `off`).
72
+ */
73
+ export declare function isLocalOryEnabled(noLocalFlagPresent: boolean, envValue: string | undefined): boolean;
74
+ /**
75
+ * Run a dev launcher with the given configuration.
76
+ *
77
+ * Auto-starts the local Verdaccio registry, publishes the harness plugin
78
+ * (with its workspace dependency closure) and `@ory/mcp-server`
79
+ * to it, then invokes each plugin's documented install commands (the same
80
+ * `npx ory-<harness> install` steps from the README) against the local
81
+ * registry. The launcher itself never hand-writes harness config — the
82
+ * plugin's own install logic is the source of truth.
83
+ */
84
+ export declare function runDevLauncher(config: DevLauncherConfig): Promise<void>;
85
+ /**
86
+ * Compose the harness env when local Ory is active. Wires up both
87
+ * principals' credentials so the user gate runs real PKCE against local
88
+ * Hydra and the agent gate runs RFC 7591 dynamic registration.
89
+ *
90
+ * The launcher always demonstrates the full UX — no opt-out into
91
+ * env-token short-circuits. The user gate is forced on and the browser
92
+ * flow fires every session against the seeded identity. Any pre-supplied
93
+ * tokens leaking from the parent shell are explicitly cleared.
94
+ */
95
+ export declare function buildLocalOryEnv(gatewayUrl: string, seed: SeedResult): Record<string, string | undefined>;
package/dist/dev.js ADDED
@@ -0,0 +1,514 @@
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.parseDevLauncherArgs = parseDevLauncherArgs;
37
+ exports.isLocalOryEnabled = isLocalOryEnabled;
38
+ exports.runDevLauncher = runDevLauncher;
39
+ exports.buildLocalOryEnv = buildLocalOryEnv;
40
+ const crypto = __importStar(require("node:crypto"));
41
+ const fs = __importStar(require("node:fs"));
42
+ const path = __importStar(require("node:path"));
43
+ const node_child_process_1 = require("node:child_process");
44
+ const config_js_1 = require("./registry/config.js");
45
+ const manager_js_1 = require("./registry/manager.js");
46
+ const jaeger_js_1 = require("./local/jaeger.js");
47
+ const manager_js_2 = require("./local/manager.js");
48
+ const configs_js_1 = require("./local/configs.js");
49
+ const seed_js_1 = require("./local/seed.js");
50
+ const auth_store_js_1 = require("./auth-store.js");
51
+ const config_js_2 = require("./config.js");
52
+ const tracer_js_1 = require("./tracer.js");
53
+ function ensureDir(dir) {
54
+ if (!fs.existsSync(dir)) {
55
+ fs.mkdirSync(dir, { recursive: true });
56
+ }
57
+ }
58
+ function ensureSandboxManifest(sandboxDir, harnessName) {
59
+ const manifestPath = path.join(sandboxDir, "package.json");
60
+ if (fs.existsSync(manifestPath))
61
+ return;
62
+ fs.writeFileSync(manifestPath, JSON.stringify({ name: `ory-sandbox-${harnessName}`, private: true, version: "0.0.0" }, null, 2) + "\n");
63
+ }
64
+ function assertNpmAvailable() {
65
+ const result = (0, node_child_process_1.spawnSync)("npm", ["--version"], { stdio: "ignore" });
66
+ if (result.error || result.status !== 0) {
67
+ throw new Error("`npm` is not on PATH. The dev launcher uses npm/npx to run each plugin's documented install commands.");
68
+ }
69
+ }
70
+ function defaultBinaryName(harnessName) {
71
+ return `ory-${harnessName}`;
72
+ }
73
+ /**
74
+ * Parse the dev-launcher CLI args, splitting out launcher-only flags from the
75
+ * args that should be forwarded to the harness binary.
76
+ *
77
+ * Launcher-only flags:
78
+ * --no-local Opt out of the auto-managed local Ory stack (local Ory is
79
+ * the default so multiple plugins can share one stack).
80
+ * --fresh Wipe runtime state before launching: stop and remove the
81
+ * local Ory stack, Verdaccio registry, and Jaeger container
82
+ * (including their volumes and on-disk state), remove this
83
+ * harness's sandbox dir, and delete the shared user config
84
+ * dir. Build artifacts and node_modules are not touched —
85
+ * use `pnpm clean:all` followed by `pnpm install` for that.
86
+ */
87
+ function parseDevLauncherArgs(argv) {
88
+ let noLocalFlag = false;
89
+ let freshFlag = false;
90
+ const forwardedArgs = [];
91
+ for (const arg of argv) {
92
+ if (arg === "--no-local") {
93
+ noLocalFlag = true;
94
+ continue;
95
+ }
96
+ if (arg === "--fresh") {
97
+ freshFlag = true;
98
+ continue;
99
+ }
100
+ forwardedArgs.push(arg);
101
+ }
102
+ return { noLocalFlag, freshFlag, forwardedArgs };
103
+ }
104
+ /**
105
+ * Decide whether the dev launcher should bring up a local Ory stack and seed
106
+ * it for the harness to authenticate against. Local Ory is the default so
107
+ * multiple harness plugins can share a single stack while developing — that
108
+ * mimics the production case of many harnesses sharing one Ory deployment.
109
+ *
110
+ * Returns `false` only when the run was explicitly opted out, either via the
111
+ * `--no-local` CLI flag or by setting `ORY_DEV_LOCAL` to a falsy value
112
+ * (`0`, `false`, `no`, `off`).
113
+ */
114
+ function isLocalOryEnabled(noLocalFlagPresent, envValue) {
115
+ if (noLocalFlagPresent)
116
+ return false;
117
+ if (envValue === undefined)
118
+ return true;
119
+ const v = envValue.trim().toLowerCase();
120
+ if (v === "" || v === "0" || v === "false" || v === "no" || v === "off") {
121
+ return false;
122
+ }
123
+ return true;
124
+ }
125
+ function npmEnv() {
126
+ // Env shared by every install/runtime subprocess so npm/npx pulls from
127
+ // the local registry through an isolated pacote cache, with the user's
128
+ // supply-chain freshness gate disabled (otherwise just-published tarballs
129
+ // get filtered out as `ENOVERSIONS — No versions available`).
130
+ return {
131
+ ...process.env,
132
+ npm_config_registry: config_js_1.REGISTRY_URL,
133
+ npm_config_cache: (0, manager_js_1.getLocalRegistryNpmCacheDir)(),
134
+ npm_config_min_release_age: "0",
135
+ };
136
+ }
137
+ function buildInstallContext(harnessName, sandboxDir, binaryName) {
138
+ const defaultPackage = `@ory/${harnessName}`;
139
+ const defaultBin = binaryName ?? defaultBinaryName(harnessName);
140
+ return {
141
+ sandboxDir,
142
+ npmInstall(packageName = defaultPackage) {
143
+ // npm 11's arborist crashes (`Cannot read properties of null (reading
144
+ // 'matches')`) when running `npm install <pkg>` in a cwd that has no
145
+ // `package.json`, so seed a minimal manifest before installing.
146
+ ensureSandboxManifest(sandboxDir, harnessName);
147
+ console.log(`[ory-dev] npm install ${packageName} (sandbox: ${sandboxDir})`);
148
+ // `--min-release-age=0` must come from the CLI flag — config-file values
149
+ // can't override a user-level `min-release-age` setting in npm 11.
150
+ const result = (0, node_child_process_1.spawnSync)("npm", [
151
+ "install",
152
+ packageName,
153
+ "--no-audit",
154
+ "--no-fund",
155
+ "--loglevel=error",
156
+ "--min-release-age=0",
157
+ "--save=false",
158
+ ], { cwd: sandboxDir, stdio: "inherit", env: npmEnv() });
159
+ if (result.status !== 0) {
160
+ throw new Error(`npm install ${packageName} failed (exit ${result.status}).`);
161
+ }
162
+ },
163
+ npxCli(args, opts = {}) {
164
+ const packageName = opts.packageName ?? defaultPackage;
165
+ const binaryName = opts.binaryName ?? defaultBin;
166
+ console.log(`[ory-dev] npx --package=${packageName} ${binaryName} ${args.join(" ")}`);
167
+ const result = (0, node_child_process_1.spawnSync)("npx", [
168
+ "--yes",
169
+ `--package=${packageName}`,
170
+ binaryName,
171
+ ...args,
172
+ ], { cwd: sandboxDir, stdio: "inherit", env: npmEnv() });
173
+ if (result.status !== 0) {
174
+ throw new Error(`npx --package=${packageName} ${binaryName} ${args.join(" ")} failed (exit ${result.status}).`);
175
+ }
176
+ },
177
+ };
178
+ }
179
+ /**
180
+ * Wipe all runtime state the launcher can safely reset without breaking the
181
+ * running process: docker containers + volumes for the local Ory stack,
182
+ * Verdaccio registry, and Jaeger; the on-disk `.sandbox/<harness>` and
183
+ * `.ory-dev/` directories; and the shared user config dir. Build artifacts
184
+ * and node_modules are out of scope — those require a separate
185
+ * `pnpm clean:all && pnpm install`.
186
+ *
187
+ * Every step is best-effort: any failure is logged as a warning and the
188
+ * reset continues. The launcher then re-bootstraps everything from scratch.
189
+ */
190
+ async function performFreshReset(sandbox) {
191
+ console.log("[ory-dev] --fresh: wiping runtime state...");
192
+ try {
193
+ await (0, manager_js_2.localReset)();
194
+ }
195
+ catch (err) {
196
+ const msg = err instanceof Error ? err.message : String(err);
197
+ console.warn(`[ory-dev] --fresh: local Ory reset failed: ${msg}. Continuing.`);
198
+ }
199
+ try {
200
+ await (0, manager_js_1.registryClean)();
201
+ }
202
+ catch (err) {
203
+ const msg = err instanceof Error ? err.message : String(err);
204
+ console.warn(`[ory-dev] --fresh: registry clean failed: ${msg}. Continuing.`);
205
+ }
206
+ const jaegerResult = (0, jaeger_js_1.stopDevJaeger)();
207
+ if (jaegerResult.status === "error") {
208
+ console.warn(`[ory-dev] --fresh: Jaeger stop failed: ${jaegerResult.detail ?? "unknown"}. Continuing.`);
209
+ }
210
+ if (fs.existsSync(sandbox)) {
211
+ fs.rmSync(sandbox, { recursive: true, force: true });
212
+ console.log(`[ory-dev] --fresh: removed ${sandbox}`);
213
+ }
214
+ const dataDir = (0, config_js_2.getDataDir)();
215
+ if (fs.existsSync(dataDir)) {
216
+ fs.rmSync(dataDir, { recursive: true, force: true });
217
+ console.log(`[ory-dev] --fresh: removed ${dataDir}`);
218
+ }
219
+ console.log("[ory-dev] --fresh: reset complete.");
220
+ }
221
+ /**
222
+ * Run a dev launcher with the given configuration.
223
+ *
224
+ * Auto-starts the local Verdaccio registry, publishes the harness plugin
225
+ * (with its workspace dependency closure) and `@ory/mcp-server`
226
+ * to it, then invokes each plugin's documented install commands (the same
227
+ * `npx ory-<harness> install` steps from the README) against the local
228
+ * registry. The launcher itself never hand-writes harness config — the
229
+ * plugin's own install logic is the source of truth.
230
+ */
231
+ async function runDevLauncher(config) {
232
+ const workspaceRoot = path.resolve(config.packageRoot, "..", "..");
233
+ const sandbox = path.resolve(workspaceRoot, ".sandbox", config.harnessName);
234
+ const localOryDir = path.resolve(workspaceRoot, ".ory-dev", "ory");
235
+ const logFile = path.resolve(sandbox, "ory-agent-debug.log");
236
+ const traceFile = path.resolve(sandbox, "ory-agent-trace.ndjson");
237
+ const { noLocalFlag, freshFlag, forwardedArgs } = parseDevLauncherArgs(process.argv.slice(2));
238
+ const localEnabled = isLocalOryEnabled(noLocalFlag, process.env.ORY_DEV_LOCAL);
239
+ if (freshFlag) {
240
+ await performFreshReset(sandbox);
241
+ }
242
+ // Belt-and-suspenders: each dev launch is the sole owner of its
243
+ // session, so a stale pkce-flight lock from a previous run that died
244
+ // mid-flow (browser closed, harness crashed, login UI 404'd, etc.)
245
+ // would only block the next launch. Sweep it. The in-process gate's
246
+ // own staleness check would catch this within 5 minutes, but the
247
+ // explicit sweep makes the dev loop tight.
248
+ if ((0, auth_store_js_1.clearPkceFlightLock)()) {
249
+ console.log("[ory-dev] Cleared stale PKCE flight lock from a previous run.");
250
+ }
251
+ assertNpmAvailable();
252
+ console.log(`[ory-dev] Ensuring local npm registry is running...`);
253
+ await (0, manager_js_1.ensureRegistryRunning)();
254
+ console.log(`[ory-dev] Publishing @ory/${config.harnessName} (and mcp-server) to ${config_js_1.REGISTRY_URL}...`);
255
+ await (0, manager_js_1.publishHarnessToLocal)(config.harnessName);
256
+ ensureDir(sandbox);
257
+ console.log(`[ory-dev] Running install flow for @ory/${config.harnessName}...`);
258
+ const ctx = buildInstallContext(config.harnessName, sandbox, config.binaryName);
259
+ config.install(ctx);
260
+ // Each dev launch gets a fresh unique session subject so traces/permission
261
+ // checks are distinguishable across runs. Used as the harness's
262
+ // ORY_AGENT_SUBJECT_ID unless local-Ory mode supplies a real seeded session.
263
+ const sessionName = `ory-sandbox-${crypto.randomBytes(6).toString("hex")}`;
264
+ // When the user opts into local Ory, bring the docker stack up (or reuse
265
+ // it) and seed two identities (agent + user). The harness env is then
266
+ // wired so the user gate runs real browser PKCE against local Hydra and
267
+ // the agent gate runs RFC 7591 dynamic client registration.
268
+ const localOry = localEnabled
269
+ ? await bootstrapLocalOry(localOryDir)
270
+ : { active: false };
271
+ console.log(`[ory-dev] Launching ${config.harnessName} with Ory plugin...`);
272
+ console.log(`[ory-dev] Sandbox: ${sandbox}`);
273
+ if (localOry.active) {
274
+ const seed = localOry.seed;
275
+ console.log("");
276
+ console.log("[ory-dev] ──────────────────────────────────────────────────");
277
+ console.log(`[ory-dev] Local Ory ready.`);
278
+ console.log(`[ory-dev] API gateway: ${localOry.gatewayUrl}`);
279
+ console.log(`[ory-dev] Console: ${configs_js_1.CONSOLE_URL}`);
280
+ console.log(`[ory-dev] Jaeger: ${configs_js_1.JAEGER_UI_URL}`);
281
+ console.log(`[ory-dev]`);
282
+ console.log(`[ory-dev] When the browser opens for login, sign in as:`);
283
+ console.log(`[ory-dev] email: ${seed.user.identity.email}`);
284
+ console.log(`[ory-dev] password: ${seed.user.password}`);
285
+ console.log("[ory-dev] ──────────────────────────────────────────────────");
286
+ console.log("");
287
+ }
288
+ else {
289
+ console.log(`[ory-dev] Session: ${sessionName}`);
290
+ }
291
+ console.log(`[ory-dev] Debug log: ${logFile}`);
292
+ console.log(`[ory-dev] Trace file: ${traceFile}`);
293
+ console.log(`[ory-dev] npm registry: ${config_js_1.REGISTRY_URL} (local)`);
294
+ if (config.extraTips) {
295
+ for (const tip of config.extraTips) {
296
+ console.log(`[ory-dev] ${tip}`);
297
+ }
298
+ }
299
+ const otelEndpoint = await resolveOtelEndpoint();
300
+ if (otelEndpoint) {
301
+ console.log(`[ory-dev] OTLP endpoint: ${otelEndpoint}`);
302
+ }
303
+ console.log(`[ory-dev] Tip: tail -f ${logFile} | jq . — live debug log`);
304
+ console.log(`[ory-dev] Tip: pnpm watch:traces ${config.harnessName} — live trace stream\n`);
305
+ const env = {
306
+ ...npmEnv(),
307
+ ORY_AGENT_DEBUG: "true",
308
+ ORY_AGENT_LOG_FILE: logFile,
309
+ ORY_AGENT_TRACE_FILE: traceFile,
310
+ ...(localOry.active
311
+ ? buildLocalOryEnv(localOry.gatewayUrl, localOry.seed)
312
+ : { ORY_AGENT_SUBJECT_ID: sessionName }),
313
+ ...(otelEndpoint
314
+ ? {
315
+ OTEL_EXPORTER_OTLP_ENDPOINT: otelEndpoint,
316
+ // ORY-prefixed alias for harnesses (e.g. Claude Code) that
317
+ // filter the env passed to hook subprocesses and drop
318
+ // OTEL_*-prefixed vars. The OTLP exporter reads this as a
319
+ // fallback so traces still reach Jaeger when OTEL_* is stripped.
320
+ ORY_OTLP_ENDPOINT: otelEndpoint,
321
+ OTEL_SERVICE_NAME: process.env.OTEL_SERVICE_NAME ??
322
+ `ory-agent-plugin-${config.harnessName}`,
323
+ }
324
+ : {}),
325
+ };
326
+ const result = (0, node_child_process_1.spawnSync)(config.command, forwardedArgs, {
327
+ cwd: sandbox,
328
+ stdio: "inherit",
329
+ env,
330
+ });
331
+ printTraceSummary(traceFile);
332
+ process.exit(result.status ?? 0);
333
+ }
334
+ function printTraceSummary(traceFile) {
335
+ if (!fs.existsSync(traceFile))
336
+ return;
337
+ const raw = fs.readFileSync(traceFile, "utf8").trim();
338
+ if (!raw)
339
+ return;
340
+ const lines = raw.split("\n").filter(Boolean);
341
+ const spans = [];
342
+ for (const line of lines) {
343
+ try {
344
+ spans.push(JSON.parse(line));
345
+ }
346
+ catch {
347
+ /* skip malformed lines */
348
+ }
349
+ }
350
+ if (spans.length === 0)
351
+ return;
352
+ console.log("");
353
+ console.log(`[ory-dev] Trace summary — ${spans.length} span(s) recorded`);
354
+ console.log(`[ory-dev] File: ${traceFile}`);
355
+ const counts = new Map();
356
+ const statusCounts = new Map();
357
+ for (const span of spans) {
358
+ const key = `${span.event}:${span.status}`;
359
+ counts.set(key, (counts.get(key) ?? 0) + 1);
360
+ statusCounts.set(span.status, (statusCounts.get(span.status) ?? 0) + 1);
361
+ }
362
+ console.log("[ory-dev] By status:");
363
+ for (const [status, n] of statusCounts) {
364
+ console.log(` ${status.padEnd(8)} ${n}`);
365
+ }
366
+ console.log("[ory-dev] By event:");
367
+ const eventTotals = new Map();
368
+ for (const span of spans) {
369
+ eventTotals.set(span.event, (eventTotals.get(span.event) ?? 0) + 1);
370
+ }
371
+ const sortedEvents = [...eventTotals.entries()].sort((a, b) => b[1] - a[1]);
372
+ for (const [event, n] of sortedEvents) {
373
+ console.log(` ${event.padEnd(22)} ${n}`);
374
+ }
375
+ const tail = spans.slice(-10);
376
+ console.log(`[ory-dev] Last ${tail.length} span(s):`);
377
+ for (const span of tail) {
378
+ console.log(" " + (0, tracer_js_1.formatSpan)(span));
379
+ }
380
+ }
381
+ /**
382
+ * Compose the harness env when local Ory is active. Wires up both
383
+ * principals' credentials so the user gate runs real PKCE against local
384
+ * Hydra and the agent gate runs RFC 7591 dynamic registration.
385
+ *
386
+ * The launcher always demonstrates the full UX — no opt-out into
387
+ * env-token short-circuits. The user gate is forced on and the browser
388
+ * flow fires every session against the seeded identity. Any pre-supplied
389
+ * tokens leaking from the parent shell are explicitly cleared.
390
+ */
391
+ function buildLocalOryEnv(gatewayUrl, seed) {
392
+ return {
393
+ ORY_PROJECT_URL: gatewayUrl,
394
+ ORY_PERMISSION_NAMESPACE: seed.permissions.namespace,
395
+ // User gate — always on in local dev so the launcher demonstrates
396
+ // the interactive PKCE login UX end-to-end every session.
397
+ ORY_AUTH_GATE: "1",
398
+ // Agent identity — the harness self-registers via DCR on first run
399
+ // using the user's bearer as the initial access token. No static
400
+ // client_credentials are seeded; explicitly clear them so a leaking
401
+ // shell env doesn't preempt the DCR path.
402
+ ORY_AGENT_CLIENT_ID: undefined,
403
+ ORY_AGENT_CLIENT_SECRET: undefined,
404
+ ORY_AGENT_API_KEY: undefined,
405
+ ORY_AGENT_REGISTRATION_TOKEN: undefined,
406
+ // User identity — the OAuth2 client used by the PKCE browser flow.
407
+ // Subject is the bare Kratos identity UUID; the User namespace pairs
408
+ // with it to form the SubjectSet `User:<id>` the seed writes.
409
+ ORY_OAUTH2_CLIENT_ID: seed.user.client.clientId,
410
+ ORY_USER_SUBJECT_NAMESPACE: "User",
411
+ ORY_USER_SUBJECT_ID: seed.user.identity.id,
412
+ // Pre-supplied tokens would short-circuit the gate. Always clear
413
+ // them so the launcher exercises the full PKCE flow.
414
+ ORY_USER_SESSION_TOKEN: undefined,
415
+ ORY_USER_OAUTH2_TOKEN: undefined,
416
+ ORY_API_KEY: undefined,
417
+ ORY_SESSION_TOKEN: undefined,
418
+ ORY_OAUTH2_TOKEN: undefined,
419
+ };
420
+ }
421
+ /**
422
+ * Bring up the local Ory docker stack (Kratos + Keto + Hydra + nginx) and
423
+ * seed a fresh test identity, returning the gateway URL and seed result so
424
+ * the launcher can wire ORY_PROJECT_URL + ORY_SESSION_TOKEN into the harness
425
+ * env.
426
+ *
427
+ * Fail-back-with-warning: any failure (Docker missing, compose error, gateway
428
+ * unhealthy, seed error) is logged and the launcher continues without local
429
+ * Ory. The harness still launches, and the plugin runs in pass-through mode.
430
+ */
431
+ async function bootstrapLocalOry(localDir) {
432
+ console.log("[ory-dev] Local Ory: ensuring docker stack is up...");
433
+ let stack;
434
+ try {
435
+ stack = await (0, manager_js_2.ensureLocalOryStack)({ quiet: true, localDir });
436
+ }
437
+ catch (err) {
438
+ const msg = err instanceof Error ? err.message : String(err);
439
+ console.warn(`[ory-dev] Local Ory bootstrap failed: ${msg}. Continuing without local Ory.`);
440
+ return { active: false };
441
+ }
442
+ switch (stack.status) {
443
+ case "already-running":
444
+ console.log(`[ory-dev] Local Ory: stack already running at ${stack.gatewayUrl} — reusing.`);
445
+ break;
446
+ case "started":
447
+ console.log(`[ory-dev] Local Ory: stack started at ${stack.gatewayUrl}.`);
448
+ break;
449
+ case "skipped:no-docker":
450
+ console.warn(`[ory-dev] Local Ory: ${stack.detail ?? "Docker unavailable."} ` +
451
+ `Continuing without local Ory.`);
452
+ return { active: false };
453
+ case "console-misconfigured":
454
+ console.warn(`[ory-dev] Local Ory: ${stack.detail ?? "console misconfigured."} ` +
455
+ `Continuing without local Ory.`);
456
+ return { active: false };
457
+ case "compose-failed":
458
+ case "gateway-unhealthy":
459
+ console.warn(`[ory-dev] Local Ory: ${stack.detail ?? stack.status}. ` +
460
+ `Inspect logs with: cd ${stack.localDir} && docker compose logs. ` +
461
+ `Continuing without local Ory.`);
462
+ return { active: false };
463
+ }
464
+ const gatewayUrl = stack.gatewayUrl ?? "http://localhost:4000";
465
+ const namespace = process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools";
466
+ console.log("[ory-dev] Local Ory: seeding test identity + permissions...");
467
+ let seed;
468
+ try {
469
+ seed = await (0, seed_js_1.seedLocalEnvironment)(namespace);
470
+ }
471
+ catch (err) {
472
+ const msg = err instanceof Error ? err.message : String(err);
473
+ console.warn(`[ory-dev] Local Ory: seed failed (${msg}). Continuing without local Ory.`);
474
+ return { active: false };
475
+ }
476
+ console.log(`[ory-dev] Local Ory: agent ${seed.agent.identity.email}, user ${seed.user.identity.email}, ` +
477
+ `${seed.permissions.tuples} permission tuples in '${namespace}' for ${seed.permissions.subject}.`);
478
+ return { active: true, gatewayUrl, seed };
479
+ }
480
+ /**
481
+ * Determine the OTLP endpoint for the dev launch:
482
+ * 1. Honor OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
483
+ * from the parent shell (Honeycomb, custom collector, etc.).
484
+ * 2. Otherwise auto-launch a local Jaeger container and use it. If Jaeger
485
+ * is already reachable (from `local up` or a prior dev launch), reuse
486
+ * it without spawning another container.
487
+ * 3. Otherwise return undefined (file-based traces only) — e.g. when
488
+ * Docker is not available on this machine.
489
+ */
490
+ async function resolveOtelEndpoint() {
491
+ const fromEnv = process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ??
492
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
493
+ if (fromEnv)
494
+ return fromEnv;
495
+ console.log("[ory-dev] Ensuring Jaeger is running for trace viewing...");
496
+ const result = await (0, jaeger_js_1.ensureDevJaeger)();
497
+ switch (result.status) {
498
+ case "already-running":
499
+ console.log(`[ory-dev] Jaeger reachable (UI: ${result.uiUrl}) — reusing existing container.`);
500
+ return result.endpoint;
501
+ case "started":
502
+ console.log(`[ory-dev] Jaeger started in Docker (UI: ${result.uiUrl}). Run 'pnpm jaeger:down' to stop it.`);
503
+ return result.endpoint;
504
+ case "skipped:no-docker":
505
+ console.log(`[ory-dev] ${result.detail ?? "Docker not available."} Falling back to NDJSON traces only.`);
506
+ return undefined;
507
+ case "skipped:probe-failed":
508
+ console.log(`[ory-dev] ${result.detail ?? "Jaeger did not become healthy in time."} Falling back to NDJSON traces only.`);
509
+ return undefined;
510
+ case "error":
511
+ console.log(`[ory-dev] Jaeger auto-start failed: ${result.detail ?? "unknown error"}. Falling back to NDJSON traces only.`);
512
+ return undefined;
513
+ }
514
+ }
@@ -0,0 +1,20 @@
1
+ export { OryAgentClient, type OryAgentConfig, type PrincipalIdentity, } from "./client.js";
2
+ export { DebugLogger, redactLogData, type LogEntry, type LogLevel, } from "./logger.js";
3
+ export { Tracer, ActiveSpan, deriveTraceId, formatSpan, watchTraceFile, type TraceEvent, type SpanStatus, type TraceSpan, type SpanOptions, type TracerOptions, type TracerContext, } from "./tracer.js";
4
+ export { loadConfig, saveConfig, resolveConfig, mutateConfig, getConfigPath, getDataDir, getHarnessDataDir, type OryPluginConfig, type OryOAuth2Tokens, type OryUserCredentials, type OryAgentCredentialsBlock, type OryAgentDynamicCredentials, } from "./config.js";
5
+ export { pkceLogin, refreshAccessToken, detectHeadless, generateCodeVerifier, sha256Base64Url, buildAuthorizeUrl, LOOPBACK_PORTS, DEFAULT_LOGIN_TIMEOUT_MS, type PkceLoginOptions, type PkceLoginOutcome, type PkceDeclineReason, } from "./auth.js";
6
+ export { loadTokens, saveTokens, clearTokens, isExpired, refreshAndSave, tryAcquirePkceFlightLock, clearPkceFlightLock, waitForPeerTokens, waitForPeerTokensSync, TOKEN_EXPIRY_SKEW_SEC, type PkceFlightLock, } from "./auth-store.js";
7
+ export { ensureUserAuthenticated, ensureAuthenticated, type AuthGateDecision, type AuthGateMode, type AuthGateOptions, } from "./auth-gate.js";
8
+ export { resolveAgentCredentials, ensureAgentIdentity, ensureSubAgentIdentity, fetchClientCredentialsToken, registerAgentClient, loadAgentDynamicCredentials, saveAgentDynamicCredentials, clearAgentDynamicCredentials, loadSubAgentDynamicCredentials, saveSubAgentDynamicCredentials, clearSubAgentDynamicCredentials, AGENT_TOKEN_EXPIRY_SKEW_SEC, type AgentCredentials, type AgentCredentialKind, type ResolveAgentCredentialsOptions, type EnsureAgentIdentityOptions, type RegisterAgentClientArgs, type SubAgentIdentity, type EnsureSubAgentIdentityOptions, } from "./agent-auth.js";
9
+ export { type SessionInfo, type OAuth2TokenInfo, type PermissionCheck, type PermissionResult, type BatchPermissionResult, type OryError, type OryErrorCode, } from "./types.js";
10
+ export { runConfigureCommand, runAgentCommand, printOryConfig, printEnvironment, printLogTail, printEnvHelp, printTraceTail, runWatchCommand, isTtyAvailable, promptOnTty, promptForProjectUrl, interactiveConfigPrompt, } from "./cli.js";
11
+ export { parseSetupArgs, readJsonFile, writeJsonFile, isOryHookCommand, resolveHookCommand, matcherHookEntry, mergeMatcherHooks, removeMatcherHooks, flatHookEntry, mergeFlatHooks, removeFlatHooks, printSetupHelp, printNextSteps, resolveMcpServerCommand, mcpServerEntry, mergeMcpServer, removeMcpServer, registerPlugin, unregisterPlugin, type SetupArgs, type HookCommand, type MatcherEntry, } from "./setup.js";
12
+ export { runDevLauncher, type DevLauncherConfig, type InstallContext, } from "./dev.js";
13
+ export { renderOrySkills, renderOryCommands, commandToSkill, commandToToml, commandToFrontmatterMarkdown, commandToPlainMarkdown, toSkillMarkdown, writeSkillTree, removeSkillDirs, ORY_SKILL_NAMES, ORY_COMMAND_SKILL_NAMES, ORY_COMMAND_SLUGS, type RenderedSkill, type RenderedCommand, type RenderProfileOptions, } from "./skills.js";
14
+ export { runLocalCommand, ensureDevJaeger, stopDevJaeger, DEV_JAEGER_CONTAINER, type EnsureDevJaegerResult, type StopDevJaegerResult, } from "./local/index.js";
15
+ export { runRegistryCommand } from "./registry/index.js";
16
+ export { parseClaudeCodeMcpTool, parseGeminiMcpTool, parseMcpToolGeneric, checkMcpPermission, type McpToolIdentifier, type McpPermissionCheckOptions, type McpPermissionResult, } from "./mcp.js";
17
+ export { resolveUserSubject, subjectLabel, type UserSubjectRef, } from "./subject.js";
18
+ export { formatDenialMessage, formatDenialSummary, formatAlertMessage, formatAlertSummary, alertAttributes, OryDenialError, type DenialContext, type AlertAttributes, } from "./denial.js";
19
+ export { summarizeToolInput, summarizeToolOutput, type ToolInputSummary, type ToolOutputSummary, } from "./tool-metadata.js";
20
+ export { OtlpHttpExporter, otlpExporterFromEnv, parseKeyValueList, type SpanExporter, type OtlpHttpExporterOptions, } from "./otel/index.js";