@exposify/express 0.3.14 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Exposify
3
+ Copyright (c) 2026 agemno
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -52,7 +52,7 @@ Agents then get validated inputs (a `minimum: 1` rejects `qty: 0` before any
52
52
  request is made) and your summaries as tool descriptions. `openapi` also
53
53
  takes a path to a JSON file, for any Express app with an OpenAPI document.
54
54
  Description precedence: `describe()` in code, then
55
- `exposify.descriptions.json`, then OpenAPI, then the derived text.
55
+ `agemno.descriptions.json`, then OpenAPI, then the derived text.
56
56
 
57
57
  ## Guided setup: `npx @exposify/express setup`
58
58
 
@@ -102,17 +102,17 @@ give your tools real descriptions (below).
102
102
  the `CI` environment variable is set.
103
103
  - **How your users sign in** (step 4): `setup` reads your `package.json`.
104
104
  With Auth0, Clerk, WorkOS or Kinde it points you at the `oauth` option
105
- (your provider already signs agents in). Otherwise it offers Exposify's
106
- hosted broker and a browser sign-in that writes `EXPOSIFY_KEY` to `.env`
105
+ (your provider already signs agents in). Otherwise it offers agemno's
106
+ hosted broker and a browser sign-in that writes `AGEMNO_KEY` to `.env`
107
107
  (a new project named after your app, or an existing one). `--no-sign-in`
108
- skips the step; `EXPOSIFY_NO_BROWSER=1` prints the link instead of
108
+ skips the step; `AGEMNO_NO_BROWSER=1` prints the link instead of
109
109
  opening it.
110
110
 
111
111
  **Tool descriptions.** Agents pick tools by their descriptions, and by default
112
112
  they get one derived from the route ("Create an order (POST /orders)").
113
113
  `setup`'s step 5, or `npx @exposify/express describe` any time, replaces those:
114
114
 
115
- - `a` sends each route's handler source to Exposify's description service,
115
+ - `a` sends each route's handler source to agemno's description service,
116
116
  which writes a proposal with an LLM (`--no-source` sends only method, path
117
117
  and middleware names). Strings that look like secrets are masked on your
118
118
  machine first, and the CLI says exactly what it's about to send and where. The
@@ -124,12 +124,12 @@ they get one derived from the route ("Create an order (POST /orders)").
124
124
  a write does is the worst thing an agent can be told. You don't need an
125
125
  LLM key: without an account you get a small free allowance (2 routes a
126
126
  day by default); when it runs out, the CLI links to a free sign-up and takes your project's secret key
127
- (and offers to save it in `~/.config/exposify/credentials.json`, readable
128
- only by you). `--license-key` / `EXPOSIFY_KEY` pass one directly;
129
- `--api-url` / `EXPOSIFY_API_URL` point at another service.
127
+ (and offers to save it in `~/.config/agemno/credentials.json`, readable
128
+ only by you). `--license-key` / `AGEMNO_KEY` pass one directly;
129
+ `--api-url` / `AGEMNO_API_URL` point at another service.
130
130
  - `w` lets you write them yourself (`e` opens `$EDITOR`).
131
131
 
132
- They're saved to `exposify.descriptions.json`, which `aiReady()` loads at
132
+ They're saved to `agemno.descriptions.json`, which `aiReady()` loads at
133
133
  startup (`descriptions: "path"` or `false` to change that); `describe()` text
134
134
  in your code still wins. Text you wrote or edited is never overwritten. When
135
135
  a route's handler changes, its AI description is offered again; yours is
@@ -142,7 +142,7 @@ whether agents get it; add `--why` for the reason on each (`--json` for
142
142
  scripts): the answer to "why isn't my route showing up?".
143
143
 
144
144
  **Catch tool changes in CI:** `npx @exposify/express inspect --snapshot` writes
145
- `exposify.tools.json` (each route agents can call, and its tool name).
145
+ `agemno.tools.json` (each route agents can call, and its tool name).
146
146
  `setup` offers to save the same file as its last question (default no;
147
147
  `--snapshot` to save without asking). Commit it, and run
148
148
  `npx @exposify/express inspect --check` in CI: it exits 1,
@@ -152,7 +152,7 @@ intended, so it shows up in the PR diff for review.
152
152
 
153
153
  ## AI assistants sign in with your own login
154
154
 
155
- With `EXPOSIFY_KEY` set (the hosted broker), an AI assistant that connects
155
+ With `AGEMNO_KEY` set (the hosted broker), an AI assistant that connects
156
156
  signs in with your app's own login, with no code:
157
157
 
158
158
  - On the first request, `aiReady()` finds your login among your routes: a
@@ -160,14 +160,14 @@ signs in with your app's own login, with no code:
160
160
  `req.body`, and sets a cookie, a session (`req.session`, passport's
161
161
  `req.login`) or signs a token. Sign-up, sign-out and reset routes are never
162
162
  picked.
163
- - When Claude connects, the person clicks Allow on Exposify's page and lands
163
+ - When Claude connects, the person clicks Allow on agemno's page and lands
164
164
  on a sign-in form served at `/mcp/login`, on your domain. On submit,
165
165
  `aiReady()` sends your login route the fields through your own app (no
166
166
  browser cookies, the person's address forwarded), and the session it
167
167
  creates goes to the broker for this connection. Every tool call then runs
168
168
  as that person; cookies you set later are kept; a 401 or a redirect to the
169
169
  login ends the connection, so the assistant asks to connect again.
170
- - `aiReady()` tells Exposify about the login and its MCP address before
170
+ - `aiReady()` tells agemno about the login and its MCP address before
171
171
  answering `/mcp`, so there's nothing to add in the dashboard. The address
172
172
  comes from the request's `Host` (and `X-Forwarded-Host` only when you've
173
173
  set Express's `trust proxy`, as you should behind a proxy). The first
@@ -188,7 +188,7 @@ same way. `loginVerify: { path, fields, body? }` names the second step;
188
188
  **No login found, and no sign-in method in the dashboard?** Then agents use
189
189
  your app signed out: `/mcp` doesn't ask them to sign in, and your own checks
190
190
  decide what they can do. The startup log says which it is
191
- (`[exposify] How agents sign in: ...`), and so does the dashboard's "How
191
+ (`[agemno] How agents sign in: ...`), and so does the dashboard's "How
192
192
  agents sign in" page. Adding a sign-in method there takes effect within a
193
193
  minute.
194
194
 
@@ -273,17 +273,17 @@ On boot (`npm run dev`, or in production), right after your routes
273
273
  register, `aiReady()` prints one line saying whether MCP is up:
274
274
 
275
275
  ```
276
- [exposify] MCP ready at /mcp: 6 tools (4 read, 1 write, search_docs), 1 write route hidden (opt in with exposed()), 2 docs indexed, auth: passthrough
276
+ [agemno] MCP ready at /mcp: 6 tools (4 read, 1 write, search_docs), 1 write route hidden (opt in with exposed()), 2 docs indexed, auth: passthrough
277
277
  ```
278
278
 
279
279
  When something's wrong, the line names the problem and a fix instead:
280
280
 
281
281
  ```
282
- [exposify] MCP failed to start: <reason>
282
+ [agemno] MCP failed to start: <reason>
283
283
  fix: <what to do>
284
- [exposify] warning: MCP is up at /mcp but exposes no route tools
284
+ [agemno] warning: MCP is up at /mcp but exposes no route tools
285
285
  fix: register app.use(aiReady()) before your routers, ...
286
- [exposify] warning: can't verify access tokens from oauth.issuer https://...: <reason>
286
+ [agemno] warning: can't verify access tokens from oauth.issuer https://...: <reason>
287
287
  fix: make oauth.issuer match the tokens' `iss` exactly ...
288
288
  ```
289
289
 
@@ -356,7 +356,7 @@ aiReady({
356
356
  telemetry?: { enabled: boolean; sink?(event): void; capturePayloads?: boolean },
357
357
  cwd?: string, // default process.cwd()
358
358
  mounts?: Record<string, unknown>, // explicit router/sub-app overrides
359
- descriptions?: string | false, // default "exposify.descriptions.json" if present
359
+ descriptions?: string | false, // default "agemno.descriptions.json" if present
360
360
  openapi?: string | object, // your OpenAPI document: tool schemas + descriptions
361
361
  login?: false | { path, fields, body? }, // your own login, for the hosted broker (found by itself)
362
362
  });
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // bin/exposify-express.ts
3
+ // bin/agemno-express.ts
4
4
  import { runCli } from "@exposify/cli";
5
5
 
6
6
  // bin/adapter.ts
@@ -168,11 +168,11 @@ import { fileURLToPath, pathToFileURL } from "url";
168
168
 
169
169
  // bin/scan/env.ts
170
170
  var SCAN_ENV = {
171
- entry: "EXPOSIFY_SCAN_ENTRY",
171
+ entry: "AGEMNO_SCAN_ENTRY",
172
172
  /** Set to "1" in the child so an app can skip heavy boot work if it wants. */
173
- flag: "EXPOSIFY_SCAN",
173
+ flag: "AGEMNO_SCAN",
174
174
  /** How long to wait for listen() after the last route registration (ms). */
175
- quietMs: "EXPOSIFY_SCAN_QUIET_MS"
175
+ quietMs: "AGEMNO_SCAN_QUIET_MS"
176
176
  };
177
177
 
178
178
  // bin/scan/run.ts
@@ -285,7 +285,7 @@ function applyStep(result, config, viaNest, root, code) {
285
285
  }
286
286
  }
287
287
 
288
- // bin/exposify-express.ts
288
+ // bin/agemno-express.ts
289
289
  runCli(process.argv.slice(2), expressAdapter).then(
290
290
  (code) => process.exit(code),
291
291
  (err) => {
package/dist/index.cjs CHANGED
@@ -76,7 +76,7 @@ function installMountRecorder(routerCtor) {
76
76
  } catch {
77
77
  }
78
78
  }
79
- var MOUNT_OWNER_TAG = /* @__PURE__ */ Symbol.for("exposify.express.recordMountOwner");
79
+ var MOUNT_OWNER_TAG = /* @__PURE__ */ Symbol.for("agemno.express.recordMountOwner");
80
80
  var taggedOwners = /* @__PURE__ */ new WeakMap();
81
81
  function recordTaggedOwner(parent, args) {
82
82
  const stack = [...args];
@@ -184,7 +184,7 @@ function warnMountSkipped() {
184
184
  warnedAboutSkippedMount = true;
185
185
  try {
186
186
  console.warn(
187
- `[exposify] skipped one or more mounted routers: their mount path could not be determined automatically, so routes under them will not be exposed as tools. If aiReady() is registered before they're mounted, this is usually automatic (Express 5's mount recorder); otherwise pass them explicitly via aiReady({ mounts: { "/path": router } }).`
187
+ `[agemno] skipped one or more mounted routers: their mount path could not be determined automatically, so routes under them will not be exposed as tools. If aiReady() is registered before they're mounted, this is usually automatic (Express 5's mount recorder); otherwise pass them explicitly via aiReady({ mounts: { "/path": router } }).`
188
188
  );
189
189
  } catch {
190
190
  }
@@ -341,10 +341,10 @@ async function loadOpenApi(cwd, option, warn) {
341
341
 
342
342
  // src/surface.ts
343
343
  var import_core4 = require("@exposify/core");
344
- var warnOnce = (m) => console.warn(`[exposify] warning: ${m}`);
344
+ var warnOnce = (m) => console.warn(`[agemno] warning: ${m}`);
345
345
  var NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
346
346
  var IDENTITY_HEADERS = ["host", "forwarded", "x-forwarded-for", "x-forwarded-proto", "x-forwarded-host", "x-forwarded-port"];
347
- var DISPATCH_HEADER = "x-exposify-dispatch";
347
+ var DISPATCH_HEADER = "x-agemno-dispatch";
348
348
  var callerStore = new import_node_async_hooks.AsyncLocalStorage();
349
349
  function callerOf(req) {
350
350
  const headers = {};
@@ -368,7 +368,7 @@ async function buildExpressSurface(app, cfg, cwd, opts) {
368
368
  const info = await readPackageInfo(cwd);
369
369
  return {
370
370
  info,
371
- // Text precedence: describe() in code > exposify.descriptions.json (reviewed) > OpenAPI > derived.
371
+ // Text precedence: describe() in code > agemno.descriptions.json (reviewed) > OpenAPI > derived.
372
372
  routes: (0, import_core3.applyDescriptions)(
373
373
  (0, import_core4.applyOpenApi)(routesFromExpress(app, opts), await loadOpenApi(cwd, opts?.openapi, warnOnce)),
374
374
  await loadDescriptions(cwd, opts?.descriptions, warnOnce)
@@ -550,10 +550,10 @@ function findExpressLogin(app, mounts) {
550
550
 
551
551
  // src/index.ts
552
552
  var import_core7 = require("@exposify/core");
553
- var AIREADY_OPTIONS_TAG = /* @__PURE__ */ Symbol.for("exposify.express.aiReadyOptions");
553
+ var AIREADY_OPTIONS_TAG = /* @__PURE__ */ Symbol.for("agemno.express.aiReadyOptions");
554
554
  var MCP_PATH = "/mcp";
555
555
  var PRM_ROOT = "/.well-known/oauth-protected-resource";
556
- var LOG_PREFIX = "[exposify]";
556
+ var LOG_PREFIX = "[agemno]";
557
557
  function toolsSummary(routes, docs, cfg) {
558
558
  const counts = (0, import_core6.countTools)(routes, cfg);
559
559
  const details = counts.hiddenWrites > 0 ? [`${counts.hiddenWrites} write route${counts.hiddenWrites === 1 ? "" : "s"} hidden (opt in with exposed())`] : [];
@@ -681,7 +681,7 @@ function aiReady(options = {}) {
681
681
  const login = loginOf(req.app);
682
682
  if (!login) return next();
683
683
  void serveLoginPage(req, res, login).catch((err) => {
684
- console.warn("[exposify] sign-in form failed:", err);
684
+ console.warn("[agemno] sign-in form failed:", err);
685
685
  if (!res.headersSent) res.writeHead(503).end("sign-in is unavailable");
686
686
  });
687
687
  return;
@@ -699,7 +699,7 @@ function aiReady(options = {}) {
699
699
  }
700
700
  if (path !== MCP_PATH && !path.startsWith(`${MCP_PATH}/`)) return next();
701
701
  if (disabled) {
702
- res.writeHead(503).end("exposify is disabled due to an internal error");
702
+ res.writeHead(503).end("agemno is disabled due to an internal error");
703
703
  return;
704
704
  }
705
705
  const authorized = gate ? gate.check(headersOf(req)).then(async (result) => {
@@ -707,7 +707,7 @@ function aiReady(options = {}) {
707
707
  await sendWebResponse(res, result.response);
708
708
  return null;
709
709
  }, (err) => {
710
- console.warn("[exposify] oauth gate failed:", err);
710
+ console.warn("[agemno] oauth gate failed:", err);
711
711
  if (!res.headersSent) res.writeHead(503).end("authorization check failed");
712
712
  return null;
713
713
  }) : brokerGate ? report(req, resourceOf(req, path, MCP_PATH)).then(async (verdict) => {
@@ -717,7 +717,7 @@ function aiReady(options = {}) {
717
717
  await sendWebResponse(res, result.response);
718
718
  return null;
719
719
  }).catch((err) => {
720
- console.warn("[exposify] broker check failed:", err);
720
+ console.warn("[agemno] broker check failed:", err);
721
721
  if (!res.headersSent) res.writeHead(503).end("authorization check failed");
722
722
  return null;
723
723
  }) : Promise.resolve({});
@@ -752,7 +752,7 @@ function aiReady(options = {}) {
752
752
  err
753
753
  );
754
754
  }
755
- if (!res.headersSent) res.writeHead(503).end("exposify failed to initialize");
755
+ if (!res.headersSent) res.writeHead(503).end("agemno failed to initialize");
756
756
  });
757
757
  };
758
758
  async function serveLoginPage(req, res, login) {
@@ -845,7 +845,7 @@ async function initialize(app, cfg, cwd, mounts, extras, onReady) {
845
845
  };
846
846
  const getKb = async () => {
847
847
  const s = await getSurface();
848
- kbPromise ??= (0, import_node2.loadOrBuildKb)(s.docs, (0, import_node_path3.join)(cwd, ".exposify"));
848
+ kbPromise ??= (0, import_node2.loadOrBuildKb)(s.docs, (0, import_node_path3.join)(cwd, ".agemno"));
849
849
  return kbPromise;
850
850
  };
851
851
  const built = await getSurface();
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { RouteInfo, AgentReadyOptions } from '@exposify/core';
1
+ import { RouteInfo, AgemnoOptions } from '@exposify/core';
2
2
  export { HostedAuthResolverConfig, completeMcpLogin, createHostedAuthResolver, describe, exposed, hidden, hostedBroker } from '@exposify/core';
3
3
 
4
4
  interface RoutesFromExpressOptions {
@@ -18,7 +18,7 @@ declare function routesFromExpress(app: unknown, opts?: RoutesFromExpressOptions
18
18
  /** Symbol under which `aiReady()`'s middleware carries the options it was given. */
19
19
  declare const AIREADY_OPTIONS_TAG: unique symbol;
20
20
 
21
- interface ExpressAiReadyOptions extends AgentReadyOptions {
21
+ interface ExpressAiReadyOptions extends AgemnoOptions {
22
22
  /**
23
23
  * The app's own login, for Connect with the hosted broker: AI assistants
24
24
  * sign in on a form served at /mcp/login, which makes this login request
@@ -43,7 +43,7 @@ interface ExpressAiReadyOptions extends AgentReadyOptions {
43
43
  fields: string[];
44
44
  body?: "json" | "form";
45
45
  };
46
- /** Where docs globs and the .exposify cache resolve. Default: process.cwd() */
46
+ /** Where docs globs and the .agemno cache resolve. Default: process.cwd() */
47
47
  cwd?: string;
48
48
  /**
49
49
  * Explicit mount paths for routers (or sub-apps) introspection can't
@@ -58,7 +58,7 @@ interface ExpressAiReadyOptions extends AgentReadyOptions {
58
58
  mounts?: Record<string, unknown>;
59
59
  /**
60
60
  * Tool descriptions file written by `@exposify/express setup`/`describe`.
61
- * Default: exposify.descriptions.json in `cwd`, if present. `false` ignores it.
61
+ * Default: agemno.descriptions.json in `cwd`, if present. `false` ignores it.
62
62
  * describe() text in code still wins over it.
63
63
  */
64
64
  descriptions?: string | false;
@@ -66,7 +66,7 @@ interface ExpressAiReadyOptions extends AgentReadyOptions {
66
66
  * The app's OpenAPI document: an object (e.g. `SwaggerModule.createDocument(app, …)`
67
67
  * in NestJS) or a path to a JSON file. Matching operations give tools real
68
68
  * input schemas, and their summary/description becomes the tool description
69
- * (below describe() and exposify.descriptions.json).
69
+ * (below describe() and agemno.descriptions.json).
70
70
  */
71
71
  openapi?: string | object;
72
72
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { RouteInfo, AgentReadyOptions } from '@exposify/core';
1
+ import { RouteInfo, AgemnoOptions } from '@exposify/core';
2
2
  export { HostedAuthResolverConfig, completeMcpLogin, createHostedAuthResolver, describe, exposed, hidden, hostedBroker } from '@exposify/core';
3
3
 
4
4
  interface RoutesFromExpressOptions {
@@ -18,7 +18,7 @@ declare function routesFromExpress(app: unknown, opts?: RoutesFromExpressOptions
18
18
  /** Symbol under which `aiReady()`'s middleware carries the options it was given. */
19
19
  declare const AIREADY_OPTIONS_TAG: unique symbol;
20
20
 
21
- interface ExpressAiReadyOptions extends AgentReadyOptions {
21
+ interface ExpressAiReadyOptions extends AgemnoOptions {
22
22
  /**
23
23
  * The app's own login, for Connect with the hosted broker: AI assistants
24
24
  * sign in on a form served at /mcp/login, which makes this login request
@@ -43,7 +43,7 @@ interface ExpressAiReadyOptions extends AgentReadyOptions {
43
43
  fields: string[];
44
44
  body?: "json" | "form";
45
45
  };
46
- /** Where docs globs and the .exposify cache resolve. Default: process.cwd() */
46
+ /** Where docs globs and the .agemno cache resolve. Default: process.cwd() */
47
47
  cwd?: string;
48
48
  /**
49
49
  * Explicit mount paths for routers (or sub-apps) introspection can't
@@ -58,7 +58,7 @@ interface ExpressAiReadyOptions extends AgentReadyOptions {
58
58
  mounts?: Record<string, unknown>;
59
59
  /**
60
60
  * Tool descriptions file written by `@exposify/express setup`/`describe`.
61
- * Default: exposify.descriptions.json in `cwd`, if present. `false` ignores it.
61
+ * Default: agemno.descriptions.json in `cwd`, if present. `false` ignores it.
62
62
  * describe() text in code still wins over it.
63
63
  */
64
64
  descriptions?: string | false;
@@ -66,7 +66,7 @@ interface ExpressAiReadyOptions extends AgentReadyOptions {
66
66
  * The app's OpenAPI document: an object (e.g. `SwaggerModule.createDocument(app, …)`
67
67
  * in NestJS) or a path to a JSON file. Matching operations give tools real
68
68
  * input schemas, and their summary/description becomes the tool description
69
- * (below describe() and exposify.descriptions.json).
69
+ * (below describe() and agemno.descriptions.json).
70
70
  */
71
71
  openapi?: string | object;
72
72
  }
package/dist/index.js CHANGED
@@ -77,7 +77,7 @@ function installMountRecorder(routerCtor) {
77
77
  } catch {
78
78
  }
79
79
  }
80
- var MOUNT_OWNER_TAG = /* @__PURE__ */ Symbol.for("exposify.express.recordMountOwner");
80
+ var MOUNT_OWNER_TAG = /* @__PURE__ */ Symbol.for("agemno.express.recordMountOwner");
81
81
  var taggedOwners = /* @__PURE__ */ new WeakMap();
82
82
  function recordTaggedOwner(parent, args) {
83
83
  const stack = [...args];
@@ -185,7 +185,7 @@ function warnMountSkipped() {
185
185
  warnedAboutSkippedMount = true;
186
186
  try {
187
187
  console.warn(
188
- `[exposify] skipped one or more mounted routers: their mount path could not be determined automatically, so routes under them will not be exposed as tools. If aiReady() is registered before they're mounted, this is usually automatic (Express 5's mount recorder); otherwise pass them explicitly via aiReady({ mounts: { "/path": router } }).`
188
+ `[agemno] skipped one or more mounted routers: their mount path could not be determined automatically, so routes under them will not be exposed as tools. If aiReady() is registered before they're mounted, this is usually automatic (Express 5's mount recorder); otherwise pass them explicitly via aiReady({ mounts: { "/path": router } }).`
189
189
  );
190
190
  } catch {
191
191
  }
@@ -342,10 +342,10 @@ async function loadOpenApi(cwd, option, warn) {
342
342
 
343
343
  // src/surface.ts
344
344
  import { applyOpenApi } from "@exposify/core";
345
- var warnOnce = (m) => console.warn(`[exposify] warning: ${m}`);
345
+ var warnOnce = (m) => console.warn(`[agemno] warning: ${m}`);
346
346
  var NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
347
347
  var IDENTITY_HEADERS = ["host", "forwarded", "x-forwarded-for", "x-forwarded-proto", "x-forwarded-host", "x-forwarded-port"];
348
- var DISPATCH_HEADER = "x-exposify-dispatch";
348
+ var DISPATCH_HEADER = "x-agemno-dispatch";
349
349
  var callerStore = new AsyncLocalStorage();
350
350
  function callerOf(req) {
351
351
  const headers = {};
@@ -369,7 +369,7 @@ async function buildExpressSurface(app, cfg, cwd, opts) {
369
369
  const info = await readPackageInfo(cwd);
370
370
  return {
371
371
  info,
372
- // Text precedence: describe() in code > exposify.descriptions.json (reviewed) > OpenAPI > derived.
372
+ // Text precedence: describe() in code > agemno.descriptions.json (reviewed) > OpenAPI > derived.
373
373
  routes: applyDescriptions(
374
374
  applyOpenApi(routesFromExpress(app, opts), await loadOpenApi(cwd, opts?.openapi, warnOnce)),
375
375
  await loadDescriptions(cwd, opts?.descriptions, warnOnce)
@@ -558,10 +558,10 @@ import {
558
558
  createHostedAuthResolver,
559
559
  hostedBroker
560
560
  } from "@exposify/core";
561
- var AIREADY_OPTIONS_TAG = /* @__PURE__ */ Symbol.for("exposify.express.aiReadyOptions");
561
+ var AIREADY_OPTIONS_TAG = /* @__PURE__ */ Symbol.for("agemno.express.aiReadyOptions");
562
562
  var MCP_PATH = "/mcp";
563
563
  var PRM_ROOT = "/.well-known/oauth-protected-resource";
564
- var LOG_PREFIX = "[exposify]";
564
+ var LOG_PREFIX = "[agemno]";
565
565
  function toolsSummary(routes, docs, cfg) {
566
566
  const counts = countTools(routes, cfg);
567
567
  const details = counts.hiddenWrites > 0 ? [`${counts.hiddenWrites} write route${counts.hiddenWrites === 1 ? "" : "s"} hidden (opt in with exposed())`] : [];
@@ -689,7 +689,7 @@ function aiReady(options = {}) {
689
689
  const login = loginOf(req.app);
690
690
  if (!login) return next();
691
691
  void serveLoginPage(req, res, login).catch((err) => {
692
- console.warn("[exposify] sign-in form failed:", err);
692
+ console.warn("[agemno] sign-in form failed:", err);
693
693
  if (!res.headersSent) res.writeHead(503).end("sign-in is unavailable");
694
694
  });
695
695
  return;
@@ -707,7 +707,7 @@ function aiReady(options = {}) {
707
707
  }
708
708
  if (path !== MCP_PATH && !path.startsWith(`${MCP_PATH}/`)) return next();
709
709
  if (disabled) {
710
- res.writeHead(503).end("exposify is disabled due to an internal error");
710
+ res.writeHead(503).end("agemno is disabled due to an internal error");
711
711
  return;
712
712
  }
713
713
  const authorized = gate ? gate.check(headersOf(req)).then(async (result) => {
@@ -715,7 +715,7 @@ function aiReady(options = {}) {
715
715
  await sendWebResponse(res, result.response);
716
716
  return null;
717
717
  }, (err) => {
718
- console.warn("[exposify] oauth gate failed:", err);
718
+ console.warn("[agemno] oauth gate failed:", err);
719
719
  if (!res.headersSent) res.writeHead(503).end("authorization check failed");
720
720
  return null;
721
721
  }) : brokerGate ? report(req, resourceOf(req, path, MCP_PATH)).then(async (verdict) => {
@@ -725,7 +725,7 @@ function aiReady(options = {}) {
725
725
  await sendWebResponse(res, result.response);
726
726
  return null;
727
727
  }).catch((err) => {
728
- console.warn("[exposify] broker check failed:", err);
728
+ console.warn("[agemno] broker check failed:", err);
729
729
  if (!res.headersSent) res.writeHead(503).end("authorization check failed");
730
730
  return null;
731
731
  }) : Promise.resolve({});
@@ -760,7 +760,7 @@ function aiReady(options = {}) {
760
760
  err
761
761
  );
762
762
  }
763
- if (!res.headersSent) res.writeHead(503).end("exposify failed to initialize");
763
+ if (!res.headersSent) res.writeHead(503).end("agemno failed to initialize");
764
764
  });
765
765
  };
766
766
  async function serveLoginPage(req, res, login) {
@@ -853,7 +853,7 @@ async function initialize(app, cfg, cwd, mounts, extras, onReady) {
853
853
  };
854
854
  const getKb = async () => {
855
855
  const s = await getSurface();
856
- kbPromise ??= loadOrBuildKb(s.docs, join3(cwd, ".exposify"));
856
+ kbPromise ??= loadOrBuildKb(s.docs, join3(cwd, ".agemno"));
857
857
  return kbPromise;
858
858
  };
859
859
  const built = await getSurface();
@@ -1828,10 +1828,10 @@ init_cjs_shims();
1828
1828
 
1829
1829
  // ../core/src/markers.ts
1830
1830
  init_cjs_shims();
1831
- var AGENTREADY_MARKER = /* @__PURE__ */ Symbol.for("agentready.marker");
1831
+ var AGEMNO_MARKER = /* @__PURE__ */ Symbol.for("agemno.marker");
1832
1832
  function getMarker(fn) {
1833
1833
  if (typeof fn !== "function") return void 0;
1834
- return fn[AGENTREADY_MARKER];
1834
+ return fn[AGEMNO_MARKER];
1835
1835
  }
1836
1836
 
1837
1837
  // ../core/src/policy.ts
@@ -2022,16 +2022,16 @@ function resolveOAuthOptions(opts) {
2022
2022
  };
2023
2023
  }
2024
2024
 
2025
- // ../core/src/exposify-key.ts
2025
+ // ../core/src/agemno-key.ts
2026
2026
  init_cjs_shims();
2027
2027
  var DEFAULT_BROKER_URL = "https://broker.agemno.com";
2028
- var EXPOSIFY_KEY_ENV = "EXPOSIFY_KEY";
2029
- var BROKER_URL_ENV = "EXPOSIFY_BROKER_URL";
2028
+ var AGEMNO_KEY_ENV = "AGEMNO_KEY";
2029
+ var BROKER_URL_ENV = "AGEMNO_BROKER_URL";
2030
2030
  var DEFAULT_API_URL = "https://infra.agemno.com";
2031
- var API_URL_ENV = "EXPOSIFY_API_URL";
2032
- var HOSTED_RESOLVER = /* @__PURE__ */ Symbol.for("exposify.hostedResolver");
2031
+ var API_URL_ENV = "AGEMNO_API_URL";
2032
+ var HOSTED_RESOLVER = /* @__PURE__ */ Symbol.for("agemno.hostedResolver");
2033
2033
  var KEY_RE = /^exk_([0-9a-f]{32})_[A-Za-z0-9_-]{20,}$/;
2034
- function parseExposifyKey(key) {
2034
+ function parseAgemnoKey(key) {
2035
2035
  const m = KEY_RE.exec(key.trim());
2036
2036
  if (!m) return null;
2037
2037
  const h = m[1];
@@ -2155,8 +2155,8 @@ function signInMethodsOf(body) {
2155
2155
  }
2156
2156
  function createHostedAuthResolver(config) {
2157
2157
  const givenKey = config.key ?? config.licenseKey;
2158
- const projectId = config.projectId ?? (config.key ? parseExposifyKey(config.key)?.projectId : void 0);
2159
- if (!givenKey) throw new Error("createHostedAuthResolver: pass your secret key as `key` (the EXPOSIFY_KEY value)");
2158
+ const projectId = config.projectId ?? (config.key ? parseAgemnoKey(config.key)?.projectId : void 0);
2159
+ if (!givenKey) throw new Error("createHostedAuthResolver: pass your secret key as `key` (the AGEMNO_KEY value)");
2160
2160
  const licenseKey = givenKey;
2161
2161
  if (!projectId) {
2162
2162
  throw new Error("createHostedAuthResolver: that key doesn't carry a project id (expected exk_...); rotate it in the dashboard, or pass projectId");
@@ -2248,7 +2248,7 @@ function createHostedAuthResolver(config) {
2248
2248
  const reported = /* @__PURE__ */ new Map();
2249
2249
  let passwordDirect;
2250
2250
  const apiUrl = requireHttpsBaseUrl("apiUrl", config.apiUrl ?? readEnv(API_URL_ENV) ?? DEFAULT_API_URL);
2251
- const stepSealer = createSealer(licenseKey, "exposify login-step v1");
2251
+ const stepSealer = createSealer(licenseKey, "agemno login-step v1");
2252
2252
  let connectInfo;
2253
2253
  let connectInflight;
2254
2254
  const fetchConnectInfo = async () => {
@@ -2321,6 +2321,9 @@ function createHostedAuthResolver(config) {
2321
2321
  countConnectOpen() {
2322
2322
  void brokerPost("connect-open", {});
2323
2323
  },
2324
+ countConnectComponentLoad() {
2325
+ void brokerPost("connect-component-load", {});
2326
+ },
2324
2327
  reportLogin(report) {
2325
2328
  const key = JSON.stringify(report);
2326
2329
  const send2 = async () => {
@@ -2359,11 +2362,11 @@ function createHostedAuthResolver(config) {
2359
2362
  return resolver;
2360
2363
  }
2361
2364
  function hostedResolverFromEnv() {
2362
- const key = readEnv(EXPOSIFY_KEY_ENV);
2365
+ const key = readEnv(AGEMNO_KEY_ENV);
2363
2366
  if (!key) return void 0;
2364
- if (!parseExposifyKey(key)) {
2367
+ if (!parseAgemnoKey(key)) {
2365
2368
  try {
2366
- console.warn(`[exposify] warning: ${EXPOSIFY_KEY_ENV} isn't a secret key from the Exposify dashboard (exk_...); ignoring it`);
2369
+ console.warn(`[agemno] warning: ${AGEMNO_KEY_ENV} isn't a secret key from the agemno dashboard (exk_...); ignoring it`);
2367
2370
  } catch {
2368
2371
  }
2369
2372
  return void 0;
@@ -6474,7 +6477,7 @@ var coerce = {
6474
6477
  var NEVER = INVALID;
6475
6478
 
6476
6479
  // ../core/src/openapi.ts
6477
- var EXPOSIFY_EXTENSION = "x-exposify";
6480
+ var AGEMNO_EXTENSION = "x-agemno";
6478
6481
  var METHODS = ["get", "put", "post", "delete", "patch", "head", "options"];
6479
6482
  var MAX_DEPTH = 8;
6480
6483
  function openApiPathToRoute(path) {
@@ -6519,7 +6522,7 @@ function toMatch(op, shared, schemas, doc) {
6519
6522
  input.body = body?.required ? field : field.optional();
6520
6523
  }
6521
6524
  const text = [op.summary, op.description].find((t) => typeof t === "string" && t.trim().length > 0);
6522
- const marker = markerFrom(op[EXPOSIFY_EXTENSION]);
6525
+ const marker = markerFrom(op[AGEMNO_EXTENSION]);
6523
6526
  return { ...text ? { description: text.trim() } : {}, ...marker ? { marker } : {}, input };
6524
6527
  }
6525
6528
  function markerFrom(ext) {
@@ -6677,7 +6680,7 @@ function installMountRecorder(routerCtor) {
6677
6680
  } catch {
6678
6681
  }
6679
6682
  }
6680
- var MOUNT_OWNER_TAG = /* @__PURE__ */ Symbol.for("exposify.express.recordMountOwner");
6683
+ var MOUNT_OWNER_TAG = /* @__PURE__ */ Symbol.for("agemno.express.recordMountOwner");
6681
6684
  var taggedOwners = /* @__PURE__ */ new WeakMap();
6682
6685
  function recordTaggedOwner(parent, args) {
6683
6686
  const stack = [...args];
@@ -6782,7 +6785,7 @@ function warnMountSkipped() {
6782
6785
  warnedAboutSkippedMount = true;
6783
6786
  try {
6784
6787
  console.warn(
6785
- `[exposify] skipped one or more mounted routers: their mount path could not be determined automatically, so routes under them will not be exposed as tools. If aiReady() is registered before they're mounted, this is usually automatic (Express 5's mount recorder); otherwise pass them explicitly via aiReady({ mounts: { "/path": router } }).`
6788
+ `[agemno] skipped one or more mounted routers: their mount path could not be determined automatically, so routes under them will not be exposed as tools. If aiReady() is registered before they're mounted, this is usually automatic (Express 5's mount recorder); otherwise pass them explicitly via aiReady({ mounts: { "/path": router } }).`
6786
6789
  );
6787
6790
  } catch {
6788
6791
  }
@@ -6976,15 +6979,15 @@ function findExpressLogin(app, mounts) {
6976
6979
  // bin/scan/env.ts
6977
6980
  init_cjs_shims();
6978
6981
  var SCAN_ENV = {
6979
- entry: "EXPOSIFY_SCAN_ENTRY",
6982
+ entry: "AGEMNO_SCAN_ENTRY",
6980
6983
  /** Set to "1" in the child so an app can skip heavy boot work if it wants. */
6981
- flag: "EXPOSIFY_SCAN",
6984
+ flag: "AGEMNO_SCAN",
6982
6985
  /** How long to wait for listen() after the last route registration (ms). */
6983
- quietMs: "EXPOSIFY_SCAN_QUIET_MS"
6986
+ quietMs: "AGEMNO_SCAN_QUIET_MS"
6984
6987
  };
6985
6988
 
6986
6989
  // bin/scan/preload.ts
6987
- var AIREADY_OPTIONS_TAG = /* @__PURE__ */ Symbol.for("exposify.express.aiReadyOptions");
6990
+ var AIREADY_OPTIONS_TAG = /* @__PURE__ */ Symbol.for("agemno.express.aiReadyOptions");
6988
6991
  var QUIET_MS = Number(process.env[SCAN_ENV.quietMs] ?? 3e3);
6989
6992
  var NOTHING_CREATED_MS = 2e4;
6990
6993
  var HARD_LIMIT_MS = 6e4;
@@ -1832,10 +1832,10 @@ init_esm_shims();
1832
1832
 
1833
1833
  // ../core/src/markers.ts
1834
1834
  init_esm_shims();
1835
- var AGENTREADY_MARKER = /* @__PURE__ */ Symbol.for("agentready.marker");
1835
+ var AGEMNO_MARKER = /* @__PURE__ */ Symbol.for("agemno.marker");
1836
1836
  function getMarker(fn) {
1837
1837
  if (typeof fn !== "function") return void 0;
1838
- return fn[AGENTREADY_MARKER];
1838
+ return fn[AGEMNO_MARKER];
1839
1839
  }
1840
1840
 
1841
1841
  // ../core/src/policy.ts
@@ -2026,16 +2026,16 @@ function resolveOAuthOptions(opts) {
2026
2026
  };
2027
2027
  }
2028
2028
 
2029
- // ../core/src/exposify-key.ts
2029
+ // ../core/src/agemno-key.ts
2030
2030
  init_esm_shims();
2031
2031
  var DEFAULT_BROKER_URL = "https://broker.agemno.com";
2032
- var EXPOSIFY_KEY_ENV = "EXPOSIFY_KEY";
2033
- var BROKER_URL_ENV = "EXPOSIFY_BROKER_URL";
2032
+ var AGEMNO_KEY_ENV = "AGEMNO_KEY";
2033
+ var BROKER_URL_ENV = "AGEMNO_BROKER_URL";
2034
2034
  var DEFAULT_API_URL = "https://infra.agemno.com";
2035
- var API_URL_ENV = "EXPOSIFY_API_URL";
2036
- var HOSTED_RESOLVER = /* @__PURE__ */ Symbol.for("exposify.hostedResolver");
2035
+ var API_URL_ENV = "AGEMNO_API_URL";
2036
+ var HOSTED_RESOLVER = /* @__PURE__ */ Symbol.for("agemno.hostedResolver");
2037
2037
  var KEY_RE = /^exk_([0-9a-f]{32})_[A-Za-z0-9_-]{20,}$/;
2038
- function parseExposifyKey(key) {
2038
+ function parseAgemnoKey(key) {
2039
2039
  const m = KEY_RE.exec(key.trim());
2040
2040
  if (!m) return null;
2041
2041
  const h = m[1];
@@ -2159,8 +2159,8 @@ function signInMethodsOf(body) {
2159
2159
  }
2160
2160
  function createHostedAuthResolver(config) {
2161
2161
  const givenKey = config.key ?? config.licenseKey;
2162
- const projectId = config.projectId ?? (config.key ? parseExposifyKey(config.key)?.projectId : void 0);
2163
- if (!givenKey) throw new Error("createHostedAuthResolver: pass your secret key as `key` (the EXPOSIFY_KEY value)");
2162
+ const projectId = config.projectId ?? (config.key ? parseAgemnoKey(config.key)?.projectId : void 0);
2163
+ if (!givenKey) throw new Error("createHostedAuthResolver: pass your secret key as `key` (the AGEMNO_KEY value)");
2164
2164
  const licenseKey = givenKey;
2165
2165
  if (!projectId) {
2166
2166
  throw new Error("createHostedAuthResolver: that key doesn't carry a project id (expected exk_...); rotate it in the dashboard, or pass projectId");
@@ -2252,7 +2252,7 @@ function createHostedAuthResolver(config) {
2252
2252
  const reported = /* @__PURE__ */ new Map();
2253
2253
  let passwordDirect;
2254
2254
  const apiUrl = requireHttpsBaseUrl("apiUrl", config.apiUrl ?? readEnv(API_URL_ENV) ?? DEFAULT_API_URL);
2255
- const stepSealer = createSealer(licenseKey, "exposify login-step v1");
2255
+ const stepSealer = createSealer(licenseKey, "agemno login-step v1");
2256
2256
  let connectInfo;
2257
2257
  let connectInflight;
2258
2258
  const fetchConnectInfo = async () => {
@@ -2325,6 +2325,9 @@ function createHostedAuthResolver(config) {
2325
2325
  countConnectOpen() {
2326
2326
  void brokerPost("connect-open", {});
2327
2327
  },
2328
+ countConnectComponentLoad() {
2329
+ void brokerPost("connect-component-load", {});
2330
+ },
2328
2331
  reportLogin(report) {
2329
2332
  const key = JSON.stringify(report);
2330
2333
  const send2 = async () => {
@@ -2363,11 +2366,11 @@ function createHostedAuthResolver(config) {
2363
2366
  return resolver;
2364
2367
  }
2365
2368
  function hostedResolverFromEnv() {
2366
- const key = readEnv(EXPOSIFY_KEY_ENV);
2369
+ const key = readEnv(AGEMNO_KEY_ENV);
2367
2370
  if (!key) return void 0;
2368
- if (!parseExposifyKey(key)) {
2371
+ if (!parseAgemnoKey(key)) {
2369
2372
  try {
2370
- console.warn(`[exposify] warning: ${EXPOSIFY_KEY_ENV} isn't a secret key from the Exposify dashboard (exk_...); ignoring it`);
2373
+ console.warn(`[agemno] warning: ${AGEMNO_KEY_ENV} isn't a secret key from the agemno dashboard (exk_...); ignoring it`);
2371
2374
  } catch {
2372
2375
  }
2373
2376
  return void 0;
@@ -6478,7 +6481,7 @@ var coerce = {
6478
6481
  var NEVER = INVALID;
6479
6482
 
6480
6483
  // ../core/src/openapi.ts
6481
- var EXPOSIFY_EXTENSION = "x-exposify";
6484
+ var AGEMNO_EXTENSION = "x-agemno";
6482
6485
  var METHODS = ["get", "put", "post", "delete", "patch", "head", "options"];
6483
6486
  var MAX_DEPTH = 8;
6484
6487
  function openApiPathToRoute(path2) {
@@ -6523,7 +6526,7 @@ function toMatch(op, shared, schemas, doc) {
6523
6526
  input.body = body?.required ? field : field.optional();
6524
6527
  }
6525
6528
  const text = [op.summary, op.description].find((t) => typeof t === "string" && t.trim().length > 0);
6526
- const marker = markerFrom(op[EXPOSIFY_EXTENSION]);
6529
+ const marker = markerFrom(op[AGEMNO_EXTENSION]);
6527
6530
  return { ...text ? { description: text.trim() } : {}, ...marker ? { marker } : {}, input };
6528
6531
  }
6529
6532
  function markerFrom(ext) {
@@ -6681,7 +6684,7 @@ function installMountRecorder(routerCtor) {
6681
6684
  } catch {
6682
6685
  }
6683
6686
  }
6684
- var MOUNT_OWNER_TAG = /* @__PURE__ */ Symbol.for("exposify.express.recordMountOwner");
6687
+ var MOUNT_OWNER_TAG = /* @__PURE__ */ Symbol.for("agemno.express.recordMountOwner");
6685
6688
  var taggedOwners = /* @__PURE__ */ new WeakMap();
6686
6689
  function recordTaggedOwner(parent, args) {
6687
6690
  const stack = [...args];
@@ -6786,7 +6789,7 @@ function warnMountSkipped() {
6786
6789
  warnedAboutSkippedMount = true;
6787
6790
  try {
6788
6791
  console.warn(
6789
- `[exposify] skipped one or more mounted routers: their mount path could not be determined automatically, so routes under them will not be exposed as tools. If aiReady() is registered before they're mounted, this is usually automatic (Express 5's mount recorder); otherwise pass them explicitly via aiReady({ mounts: { "/path": router } }).`
6792
+ `[agemno] skipped one or more mounted routers: their mount path could not be determined automatically, so routes under them will not be exposed as tools. If aiReady() is registered before they're mounted, this is usually automatic (Express 5's mount recorder); otherwise pass them explicitly via aiReady({ mounts: { "/path": router } }).`
6790
6793
  );
6791
6794
  } catch {
6792
6795
  }
@@ -6980,15 +6983,15 @@ function findExpressLogin(app, mounts) {
6980
6983
  // bin/scan/env.ts
6981
6984
  init_esm_shims();
6982
6985
  var SCAN_ENV = {
6983
- entry: "EXPOSIFY_SCAN_ENTRY",
6986
+ entry: "AGEMNO_SCAN_ENTRY",
6984
6987
  /** Set to "1" in the child so an app can skip heavy boot work if it wants. */
6985
- flag: "EXPOSIFY_SCAN",
6988
+ flag: "AGEMNO_SCAN",
6986
6989
  /** How long to wait for listen() after the last route registration (ms). */
6987
- quietMs: "EXPOSIFY_SCAN_QUIET_MS"
6990
+ quietMs: "AGEMNO_SCAN_QUIET_MS"
6988
6991
  };
6989
6992
 
6990
6993
  // bin/scan/preload.ts
6991
- var AIREADY_OPTIONS_TAG = /* @__PURE__ */ Symbol.for("exposify.express.aiReadyOptions");
6994
+ var AIREADY_OPTIONS_TAG = /* @__PURE__ */ Symbol.for("agemno.express.aiReadyOptions");
6992
6995
  var QUIET_MS = Number(process.env[SCAN_ENV.quietMs] ?? 3e3);
6993
6996
  var NOTHING_CREATED_MS = 2e4;
6994
6997
  var HARD_LIMIT_MS = 6e4;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@exposify/express",
3
- "version": "0.3.14",
3
+ "version": "0.3.15",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "bin": {
10
- "exposify-express": "./dist/cli.js"
10
+ "agemno-express": "./dist/cli.js"
11
11
  },
12
12
  "exports": {
13
13
  ".": {
@@ -20,14 +20,14 @@
20
20
  "dist"
21
21
  ],
22
22
  "scripts": {
23
- "build": "tsup src/index.ts --format esm,cjs --dts --clean && tsup --entry.cli bin/exposify-express.ts --format esm --outDir dist --no-clean && tsup --config tsup.preload.config.ts",
23
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean && tsup --entry.cli bin/agemno-express.ts --format esm --outDir dist --no-clean && tsup --config tsup.preload.config.ts",
24
24
  "test": "vitest run",
25
25
  "typecheck": "tsc --noEmit",
26
26
  "prepack": "yarn build"
27
27
  },
28
28
  "dependencies": {
29
- "@exposify/cli": "0.0.9",
30
- "@exposify/core": "0.3.19"
29
+ "@exposify/cli": "0.0.10",
30
+ "@exposify/core": "0.3.21"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "express": ">=4 <6"
@@ -48,7 +48,7 @@
48
48
  "access": "public"
49
49
  },
50
50
  "description": "Turn an Express app into an MCP server in one line: routes become AI agent tools automatically, writes are opt-in, and the caller's own credentials pass straight through.",
51
- "author": "Exposify",
51
+ "author": "agemno",
52
52
  "keywords": [
53
53
  "mcp",
54
54
  "model-context-protocol",