@adonis-agora/agent-dashboard 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,71 @@
1
1
  # @adonis-agora/agent-dashboard
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`05ea997`](https://github.com/DavideCarvalho/adonis-agent/commit/05ea997c6c9d4f20497ca0a1f81a1e09b77141b3) - O console de governança agora também se recusa a montar quando `governanceQueries: false`, não só quando falta o `governanceAuthorize`.
8
+
9
+ Os dois casos produzem o MESMO console quebrado — 10 dos 11 endpoints de leitura do console são `/agent/governance/*`, e sem read-model essas rotas não existem, então todo painel menos o Quota dá 404 no clique. Antes, `governanceQueries: false` com um gate configurado passava pela checagem de mount e servia esse console morto sem nada explicando o motivo.
10
+
11
+ **Como voltar a ter o console:** o aviso de boot agora nomeia QUAL das duas peças falta, porque as duas quebram igual e mensagem genérica não ajuda ninguém a diagnosticar.
12
+
13
+ - Faltando o gate → configure `governanceAuthorize` em `config/agent.ts` (tipicamente uma checagem de ADMIN), ou `governanceAuthorize: () => true` pra restaurar deliberadamente o comportamento antigo de deixar QUALQUER ator autenticado ler.
14
+ - `governanceQueries: false` → remova essa linha (omitir dá o read-model Lucid quando o store principal é Lucid) ou passe um store/factory explícito.
15
+ - Pra manter o console desligado de propósito e sem aviso: `dashboard: { enabled: false }`.
16
+
17
+ Só um `false` explícito em `governanceQueries` bloqueia o mount. `undefined` NÃO é esse caso: o provider do agent resolve o read-model Lucid por default quando o store principal é Lucid, então omitir a chave continua montando o console normalmente.
18
+
19
+ `GET /agent/approvals/mine` segue inalterado — montado e escopado ao ator chamador.
20
+
21
+ - [`fa39b5f`](https://github.com/DavideCarvalho/adonis-agent/commit/fa39b5faef317fb47cf1fbb8fe29cec448270d21) - **If your governance console suddenly 404s, or every panel in it is failing: set `governanceAuthorize` in `config/agent.ts`.**
22
+
23
+ ```ts
24
+ // config/agent.ts
25
+ export default defineConfig({
26
+ // ...
27
+ governanceAuthorize: (actor) => actor.roles?.includes("ADMIN") ?? false,
28
+ });
29
+ ```
30
+
31
+ That one line brings both the console and its data back. If you deliberately want the old behaviour where any authenticated actor could read the platform-wide governance data, say so explicitly with `governanceAuthorize: () => true` — same effect, but greppable and reviewable.
32
+
33
+ **Why.** The cross-actor `/agent/governance/*` read routes stopped mounting without a `governanceAuthorize` gate (see the previous `@adonis-agora/agent` release). Ten of the console's eleven read endpoints are those routes, and the SPA calls them **from the browser** — so an app with the dashboard installed and no gate got a console that loaded fine and then failed on every panel except Quota, with nothing in the logs explaining it.
34
+
35
+ **What changed.** `@adonis-agora/agent-dashboard` now refuses to mount when the agent config has no `governanceAuthorize`, and logs a boot warning naming both fixes above. The console URL returns `404` instead of serving a shell that cannot work. Nothing that still worked is broken by this: every affected app already had a console dead in six of its seven views.
36
+
37
+ Unaffected:
38
+
39
+ - Apps that already set `governanceAuthorize` — no change whatsoever.
40
+ - `dashboard: { enabled: false }` — still off, still silent, no warning.
41
+ - `dashboard.authorize` — still an optional EXTRA gate on the SPA shell, unchanged. It is deliberately not what decides whether the console mounts: it gates the shell, not the data, so an app could set it and still have a console with nothing to render.
42
+ - `GET /agent/approvals/mine` — never behind the governance gate; still mounted and still scoped to the calling actor.
43
+
44
+ The `@adonis-agora/agent` half of this release is documentation only: the `governanceAuthorize` JSDoc and the `governance-gate.ts` comments still described the old open-by-default behaviour they no longer have. `evaluateGovernanceGate`'s behaviour is unchanged.
45
+
46
+ ### Patch Changes
47
+
48
+ - [`63b9b08`](https://github.com/DavideCarvalho/adonis-agent/commit/63b9b08caa19a092965a465612215254fbb14997) - **No published version of either package is affected.** This is a repo-tooling fix with no runtime change — nothing in `src/` moved. Checked rather than assumed: the live tarballs for `@adonis-agora/agent@0.17.0` and `@adonis-agora/agent-dashboard@0.3.2` contain 105 and 13 `.js` files respectively, exactly what a full local build emits. The release workflow publishes from a cold `actions/checkout`, which has no `dist/` and no `.tsbuildinfo` to go stale, so the defect below could not reach npm. It could reach a contributor's working copy, and did.
49
+
50
+ `pnpm build` could exit `0` having emitted no JavaScript. `tsc` ran with `incremental: true` against a `.tsbuildinfo` that records what it already wrote to `dist/`; delete `dist/` and leave the buildinfo behind and `tsc` concludes every output is current and emits nothing. In `@adonis-agora/agent`, `copy:stubs` is a plain `cp` and ran anyway, so `dist/` came out holding four stub files and zero `.js`. Turbo then cached that empty directory as a _successful_ `build` and replayed it onto clean trees — a later `pnpm build` on a freshly wiped checkout restored the vacuum as `FULL TURBO` in 32ms. Downstream, `packages/dashboard` failed with `TS2307: Cannot find module '@adonis-agora/agent'` against the package that had just "built".
51
+
52
+ Both packages are fixed the same way:
53
+
54
+ - `build` removes `dist/` up front and compiles through a new `tsconfig.build.json` with `incremental: false`, so an emit is always a full emit and no state survives to disagree with `dist/`.
55
+ - A new `scripts/assert-build-output.mjs` runs as the last step of `build` and fails it if `dist/` holds no JavaScript or is missing the package entrypoint. It runs inside the build, so it also covers `prepack` — which never goes through turbo, and is the path a manual `pnpm publish` would take.
56
+ - `build` and `typecheck` no longer share a buildinfo. `typecheck` keeps `.typecheck.tsbuildinfo`; `build` keeps none at all. `turbo.json` is unchanged.
57
+
58
+ If you have a checkout in the broken state, the guard now prints the way out — and the command it prints works, which took a second pass to get right: the buildinfo files are dotfiles and a shell `*` does not match those.
59
+
60
+ ```
61
+ rm -rf dist .*tsbuildinfo *.tsbuildinfo
62
+ pnpm run build
63
+ ```
64
+
65
+ The dashboard's exposure needed a different guard. Its `build` is `vite build && tsc`, and vite keeps populating `dist/spa/` whatever `tsc` does — a `dist/` with no provider in it still holds a dozen `.js` files. Counting JavaScript would have passed it, so `check:dist` there asserts the entrypoint by name.
66
+
67
+ Neither a count nor a named entrypoint is enough on its own. A _partial_ emit was observed during this fix: `dist/` came out holding exactly one `.js`, `src/index.js`, which satisfies both checks — and because `index.d.ts` was there too, the dashboard compiled against it without a single `TS2307`. Every subpath export (`@adonis-agora/agent/rag-media`, `/durable`, `/testing`, …) pointed at a file that did not exist, and the first thing to notice would have been a consumer's failed import. So the guard also walks `package.json`'s `exports` and requires every target it declares. That list is the package's real publish contract, and it maintains itself — adding an export adds a post-condition, with nobody having to remember. It also covers `@adonis-agora/agent-dashboard/client`, which the by-name check never looked at.
68
+
3
69
  ## 0.3.2
4
70
 
5
71
  ### Patch Changes
@@ -12,6 +12,10 @@ import type { ApplicationService } from '@adonisjs/core/types';
12
12
  * - `GET <mount>/` → the SPA shell (`index.html`, with the resolved API base injected)
13
13
  * - `GET <mount>/*` → a built asset, or the SPA shell as a fallback (client-rendered console)
14
14
  *
15
+ * Nothing mounts unless the agent config carries a `governanceAuthorize` gate: without it the
16
+ * `/agent/governance/*` routes the console reads do not exist, so the console would load and fail on
17
+ * every panel but Quota. The provider declines and logs why (see `decideDashboardMount`).
18
+ *
15
19
  * Enable/disable and override the mount via the optional `config('agent').dashboard` block.
16
20
  */
17
21
  export default class AgentDashboardProvider {
@@ -1 +1 @@
1
- {"version":3,"file":"agent_dashboard_provider.d.ts","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAgB/D;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,sBAAsB;IAC7B,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,+FAA+F;IAC/F,OAAO,CAAC,SAAS,CAAuC;IAElD,IAAI;IA0CV;;;;;OAKG;YACW,IAAI;IAalB;;;OAGG;YACW,SAAS;IAOvB,4FAA4F;YAC9E,SAAS;CAmBxB"}
1
+ {"version":3,"file":"agent_dashboard_provider.d.ts","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAiB/D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,OAAO,OAAO,sBAAsB;IAC7B,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,+FAA+F;IAC/F,OAAO,CAAC,SAAS,CAAuC;IAElD,IAAI;IAsDV;;;;;OAKG;YACW,IAAI;IAalB;;;OAGG;YACW,SAAS;IAOvB,4FAA4F;YAC9E,SAAS;CAmBxB"}
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { resolveDashboardConfig, } from '../src/server/define_config.js';
2
+ import { decideDashboardMount, resolveDashboardConfig, } from '../src/server/define_config.js';
3
3
  import { evaluateDashboardGate } from '../src/server/gate.js';
4
4
  import { apiBaseFor, contentTypeFor, injectApiBase, injectBaseHref, mountPathFor, safeAssetSegments, } from '../src/server/paths.js';
5
5
  /**
@@ -15,6 +15,10 @@ import { apiBaseFor, contentTypeFor, injectApiBase, injectBaseHref, mountPathFor
15
15
  * - `GET <mount>/` → the SPA shell (`index.html`, with the resolved API base injected)
16
16
  * - `GET <mount>/*` → a built asset, or the SPA shell as a fallback (client-rendered console)
17
17
  *
18
+ * Nothing mounts unless the agent config carries a `governanceAuthorize` gate: without it the
19
+ * `/agent/governance/*` routes the console reads do not exist, so the console would load and fail on
20
+ * every panel but Quota. The provider declines and logs why (see `decideDashboardMount`).
21
+ *
18
22
  * Enable/disable and override the mount via the optional `config('agent').dashboard` block.
19
23
  */
20
24
  export default class AgentDashboardProvider {
@@ -27,8 +31,15 @@ export default class AgentDashboardProvider {
27
31
  async boot() {
28
32
  const agentConfig = this.app.config.get('agent', {});
29
33
  const dashboardConfig = resolveDashboardConfig(this.app.config.get('agent.dashboard', {}));
30
- if (!dashboardConfig.enabled)
34
+ // Mount only when the console can actually work: every panel but Quota reads the agent's
35
+ // cross-actor `/agent/governance/*` routes, and those do not exist without a `governanceAuthorize`
36
+ // gate. Refusing here — loudly — beats serving a shell that 404s its own data with no explanation.
37
+ const decision = decideDashboardMount(dashboardConfig.enabled, agentConfig.governanceAuthorize, agentConfig.governanceQueries);
38
+ if (!decision.mount) {
39
+ if (decision.reason !== 'disabled')
40
+ console.warn(decision.warning);
31
41
  return;
42
+ }
32
43
  // Resolve the router from the container, NOT from `@adonisjs/core/services/router`: that service's
33
44
  // default export is assigned inside an `app.booted()` hook, which runs AFTER every provider's
34
45
  // `boot()` — so at this point the module default is still `undefined` and `router.get(...)` throws.
@@ -1 +1 @@
1
- {"version":3,"file":"agent_dashboard_provider.js","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent_dashboard_provider.js","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Actor } from '@adonis-agora/agent';
1
+ import type { Actor, AgentGovernanceAuthorize } from '@adonis-agora/agent';
2
2
  import type { HttpContext } from '@adonisjs/core/http';
3
3
  /**
4
4
  * An extra authorization gate for the dashboard, run AFTER the agent config's `actorResolver` has
@@ -13,13 +13,19 @@ export type AgentDashboardAuthorize = (actor: Actor, ctx: HttpContext) => boolea
13
13
  * toggles it on/off, optionally overrides the mount path, and optionally adds an `authorize` gate.
14
14
  */
15
15
  export interface AgentDashboardConfig {
16
- /** Mount the SPA. Default `true` — set `false` to keep the routes off entirely. */
16
+ /**
17
+ * Mount the SPA. Default `true` — set `false` to keep the routes off entirely. Note `true` is
18
+ * necessary but not sufficient: the console also needs the agent's `governanceAuthorize` gate, see
19
+ * {@link decideDashboardMount}.
20
+ */
17
21
  enabled?: boolean;
18
22
  /** Override the mount path. Default `<agentPath>/dashboard`. */
19
23
  path?: string;
20
24
  /**
21
25
  * Extra authorization run after the actor resolves. Return `false` to deny (`403`). Omit to allow
22
- * any resolved actor (the default), matching the `/agent/governance/*` routes' gating.
26
+ * any resolved actor (the default) — note this is only an EXTRA gate on the SPA shell; whether the
27
+ * console mounts at all, and whether its data is readable, is decided by the agent config's
28
+ * `governanceAuthorize`.
23
29
  */
24
30
  authorize?: AgentDashboardAuthorize;
25
31
  }
@@ -30,4 +36,34 @@ export interface ResolvedAgentDashboardConfig {
30
36
  }
31
37
  /** Fill defaults for the optional dashboard config block. */
32
38
  export declare function resolveDashboardConfig(config: AgentDashboardConfig | undefined): ResolvedAgentDashboardConfig;
39
+ /** Whether the provider registers the console's routes, and (when it refuses) what to say about it. */
40
+ export type DashboardMountDecision = {
41
+ mount: true;
42
+ } | {
43
+ mount: false;
44
+ reason: 'disabled';
45
+ } | {
46
+ mount: false;
47
+ reason: 'no-governance-gate';
48
+ warning: string;
49
+ } | {
50
+ mount: false;
51
+ reason: 'no-governance-queries';
52
+ warning: string;
53
+ };
54
+ /**
55
+ * Decide whether to register the console's routes at all — the router-free core of the provider's
56
+ * mount check, extracted so it can be unit tested without booting an app.
57
+ *
58
+ * The console is a pure consumer of the agent's cross-actor `/agent/governance/*` read routes, and
59
+ * those routes are not mounted unless the agent config carries a `governanceAuthorize` gate. Serving
60
+ * a shell that can only 404 its own data is worse than not serving it: the failure shows up as seven
61
+ * dead panels at click time with nothing anywhere explaining why. So the console follows the same
62
+ * fail-closed-by-omission rule one layer down — no gate, no routes — and says so at boot.
63
+ *
64
+ * This costs nothing that still works: every app affected is an app whose console is ALREADY dead in
65
+ * every view but Quota. `dashboard.authorize` is deliberately NOT the trigger; it gates the shell,
66
+ * not the data, and an app can set it and still have a console with nothing to render.
67
+ */
68
+ export declare function decideDashboardMount(enabled: boolean, governanceAuthorize: AgentGovernanceAuthorize | undefined, governanceQueries?: unknown): DashboardMountDecision;
33
69
  //# sourceMappingURL=define_config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,WAAW,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,6DAA6D;AAC7D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,oBAAoB,GAAG,SAAS,GACvC,4BAA4B,CAK9B"}
1
+ {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,WAAW,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,6DAA6D;AAC7D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,oBAAoB,GAAG,SAAS,GACvC,4BAA4B,CAK9B;AAED,uGAAuG;AACvG,MAAM,MAAM,sBAAsB,GAC9B;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,uBAAuB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAoBvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,mBAAmB,EAAE,wBAAwB,GAAG,SAAS,EACzD,iBAAiB,CAAC,EAAE,OAAO,GAC1B,sBAAsB,CAgBxB"}
@@ -7,4 +7,50 @@ export function resolveDashboardConfig(config) {
7
7
  resolved.authorize = config.authorize;
8
8
  return resolved;
9
9
  }
10
+ /**
11
+ * The exact wording the provider logs when it declines to mount. Mirrors the agent provider's own
12
+ * governance boot warning — same three facts, same vocabulary — so a reader who sees one recognises
13
+ * the other.
14
+ */
15
+ const NO_GOVERNANCE_GATE_WARNING = '[@adonis-agora/agent-dashboard] the governance console was NOT mounted: every panel but Quota reads the cross-actor `/agent/governance/*` routes, and those are themselves not mounted because no `governanceAuthorize` gate is configured — so the console would load and then fail on every panel. Set `governanceAuthorize` in config/agent.ts (e.g. an ADMIN check) to mount the routes and this console gated, or `governanceAuthorize: () => true` to deliberately restore the old behaviour of letting ANY authenticated actor read them. `GET /agent/approvals/mine` is unaffected — it stays mounted and scoped to the calling actor. To keep the console off on purpose and silence this, set `dashboard: { enabled: false }`.';
16
+ /**
17
+ * The wording logged when the read-model itself was turned off. Deliberately distinct from
18
+ * {@link NO_GOVERNANCE_GATE_WARNING}: both produce the same dead console, and an operator staring at
19
+ * a 404 must be able to tell from the log ALONE which of the two knobs is responsible. A shared
20
+ * "governance is not configured" message would recreate exactly the diagnosability problem this
21
+ * check exists to remove.
22
+ */
23
+ const NO_GOVERNANCE_QUERIES_WARNING = '[@adonis-agora/agent-dashboard] the governance console was NOT mounted: `governanceQueries` is set to `false` in config/agent.ts, so the cross-actor read-model was never built and the `/agent/governance/*` routes it serves do not exist — the console would load and then fail on every panel but Quota. A `governanceAuthorize` gate is NOT the missing piece here; it is already configured. Remove `governanceQueries: false` (omit it to get the Lucid read-model when the main store is Lucid, or pass a store/factory explicitly) to mount the read-model and this console. To keep the console off on purpose and silence this, set `dashboard: { enabled: false }`.';
24
+ /**
25
+ * Decide whether to register the console's routes at all — the router-free core of the provider's
26
+ * mount check, extracted so it can be unit tested without booting an app.
27
+ *
28
+ * The console is a pure consumer of the agent's cross-actor `/agent/governance/*` read routes, and
29
+ * those routes are not mounted unless the agent config carries a `governanceAuthorize` gate. Serving
30
+ * a shell that can only 404 its own data is worse than not serving it: the failure shows up as seven
31
+ * dead panels at click time with nothing anywhere explaining why. So the console follows the same
32
+ * fail-closed-by-omission rule one layer down — no gate, no routes — and says so at boot.
33
+ *
34
+ * This costs nothing that still works: every app affected is an app whose console is ALREADY dead in
35
+ * every view but Quota. `dashboard.authorize` is deliberately NOT the trigger; it gates the shell,
36
+ * not the data, and an app can set it and still have a console with nothing to render.
37
+ */
38
+ export function decideDashboardMount(enabled, governanceAuthorize, governanceQueries) {
39
+ if (!enabled)
40
+ return { mount: false, reason: 'disabled' };
41
+ if (governanceAuthorize === undefined) {
42
+ return { mount: false, reason: 'no-governance-gate', warning: NO_GOVERNANCE_GATE_WARNING };
43
+ }
44
+ // ONLY an explicit `false` is decidable here. `undefined` does NOT mean "no read-model": the agent
45
+ // provider's `#resolveGovernance` defaults it to the Lucid read-model whenever the main store is
46
+ // Lucid, and reproducing that resolution would duplicate provider logic in the dashboard.
47
+ if (governanceQueries === false) {
48
+ return {
49
+ mount: false,
50
+ reason: 'no-governance-queries',
51
+ warning: NO_GOVERNANCE_QUERIES_WARNING,
52
+ };
53
+ }
54
+ return { mount: true };
55
+ }
10
56
  //# sourceMappingURL=define_config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AAqCA,6DAA6D;AAC7D,MAAM,UAAU,sBAAsB,CACpC,MAAwC;IAExC,MAAM,QAAQ,GAAiC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;IACpF,IAAI,MAAM,EAAE,IAAI,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAC5D,IAAI,MAAM,EAAE,SAAS,KAAK,SAAS;QAAE,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IAC3E,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AA2CA,6DAA6D;AAC7D,MAAM,UAAU,sBAAsB,CACpC,MAAwC;IAExC,MAAM,QAAQ,GAAiC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;IACpF,IAAI,MAAM,EAAE,IAAI,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAC5D,IAAI,MAAM,EAAE,SAAS,KAAK,SAAS;QAAE,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IAC3E,OAAO,QAAQ,CAAC;AAClB,CAAC;AASD;;;;GAIG;AACH,MAAM,0BAA0B,GAC9B,0sBAA0sB,CAAC;AAE7sB;;;;;;GAMG;AACH,MAAM,6BAA6B,GACjC,ipBAAipB,CAAC;AAEppB;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAgB,EAChB,mBAAyD,EACzD,iBAA2B;IAE3B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC1D,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;IAC7F,CAAC;IACD,mGAAmG;IACnG,iGAAiG;IACjG,0FAA0F;IAC1F,IAAI,iBAAiB,KAAK,KAAK,EAAE,CAAC;QAChC,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,uBAAuB;YAC/B,OAAO,EAAE,6BAA6B;SACvC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
@@ -11,11 +11,23 @@ export type DashboardGateVerdict = {
11
11
  };
12
12
  /**
13
13
  * Decide whether a request may reach the dashboard, WITHOUT touching the response — so it is unit
14
- * testable free of the AdonisJS router/app. Mirrors the `/agent/governance/*` gating: resolve the
15
- * actor through the agent config's resolver (missing/failed → `401`), then run the optional
16
- * `authorize` gate over the resolved actor (denied/threw → `403`). No resolver and no `authorize`
17
- * means the SPA is exposed to any request — the caller (the provider) is expected to short-circuit on
18
- * a missing resolver via the `401` here.
14
+ * testable free of the AdonisJS router/app: resolve the actor through the agent config's resolver
15
+ * (missing/failed → `401`), then run the optional `authorize` gate over the resolved actor
16
+ * (denied/threw → `403`).
17
+ *
18
+ * This gates the SPA **shell**, and only the shell. It is NOT what decides whether the console's data
19
+ * is readable, and it is no longer the last line of defence it once had to be:
20
+ *
21
+ * - Whether the console mounts at all is decided earlier, by {@link decideDashboardMount} — the
22
+ * routes are not registered unless the agent config carries a `governanceAuthorize` gate AND its
23
+ * `governanceQueries` read-model exists. So this function never runs for a console that could only
24
+ * 404 its own panels.
25
+ * - Whether the DATA is readable is decided by the agent's own `governanceAuthorize` on the
26
+ * `/agent/governance/*` routes, not here. Omitting `authorize` while a gate is configured leaves
27
+ * the shell open to any resolved actor but exposes no cross-actor data.
28
+ *
29
+ * Omitting BOTH the resolver and `authorize` would expose the shell to any request; the provider is
30
+ * expected to short-circuit on a missing resolver via the `401` here.
19
31
  */
20
32
  export declare function evaluateDashboardGate(ctx: HttpContext, actorResolver: ActorResolver | undefined, authorize?: AgentDashboardAuthorize): Promise<DashboardGateVerdict>;
21
33
  //# sourceMappingURL=gate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../../src/server/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAElE,gGAAgG;AAChG,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,EAChB,aAAa,EAAE,aAAa,GAAG,SAAS,EACxC,SAAS,CAAC,EAAE,uBAAuB,GAClC,OAAO,CAAC,oBAAoB,CAAC,CA4B/B"}
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../../src/server/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAElE,gGAAgG;AAChG,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,EAChB,aAAa,EAAE,aAAa,GAAG,SAAS,EACxC,SAAS,CAAC,EAAE,uBAAuB,GAClC,OAAO,CAAC,oBAAoB,CAAC,CA4B/B"}
@@ -1,10 +1,22 @@
1
1
  /**
2
2
  * Decide whether a request may reach the dashboard, WITHOUT touching the response — so it is unit
3
- * testable free of the AdonisJS router/app. Mirrors the `/agent/governance/*` gating: resolve the
4
- * actor through the agent config's resolver (missing/failed → `401`), then run the optional
5
- * `authorize` gate over the resolved actor (denied/threw → `403`). No resolver and no `authorize`
6
- * means the SPA is exposed to any request — the caller (the provider) is expected to short-circuit on
7
- * a missing resolver via the `401` here.
3
+ * testable free of the AdonisJS router/app: resolve the actor through the agent config's resolver
4
+ * (missing/failed → `401`), then run the optional `authorize` gate over the resolved actor
5
+ * (denied/threw → `403`).
6
+ *
7
+ * This gates the SPA **shell**, and only the shell. It is NOT what decides whether the console's data
8
+ * is readable, and it is no longer the last line of defence it once had to be:
9
+ *
10
+ * - Whether the console mounts at all is decided earlier, by {@link decideDashboardMount} — the
11
+ * routes are not registered unless the agent config carries a `governanceAuthorize` gate AND its
12
+ * `governanceQueries` read-model exists. So this function never runs for a console that could only
13
+ * 404 its own panels.
14
+ * - Whether the DATA is readable is decided by the agent's own `governanceAuthorize` on the
15
+ * `/agent/governance/*` routes, not here. Omitting `authorize` while a gate is configured leaves
16
+ * the shell open to any resolved actor but exposes no cross-actor data.
17
+ *
18
+ * Omitting BOTH the resolver and `authorize` would expose the shell to any request; the provider is
19
+ * expected to short-circuit on a missing resolver via the `401` here.
8
20
  */
9
21
  export async function evaluateDashboardGate(ctx, actorResolver, authorize) {
10
22
  if (actorResolver === undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../src/server/gate.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAgB,EAChB,aAAwC,EACxC,SAAmC;IAEnC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC;IAC3E,CAAC;IACD,IAAI,KAAoD,CAAC;IACzD,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc;SAC/D,CAAC;IACJ,CAAC;IACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;gBACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;YACxD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;aAC5D,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../src/server/gate.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAgB,EAChB,aAAwC,EACxC,SAAmC;IAEnC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC;IAC3E,CAAC;IACD,IAAI,KAAoD,CAAC;IACzD,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc;SAC/D,CAAC;IACJ,CAAC;IACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;gBACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;YACxD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;aAC5D,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonis-agora/agent-dashboard",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Read-only governance console (spend by model/actor, usage trend, recent threads & tool calls, quota) for @adonis-agora/agent — a dependency-light React SPA served by a thin AdonisJS provider. Part of the Agora ecosystem.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -57,7 +57,7 @@
57
57
  "typescript": "^5.4.0",
58
58
  "vite": "^7.0.0",
59
59
  "vitest": "^3.0.0",
60
- "@adonis-agora/agent": "0.5.0"
60
+ "@adonis-agora/agent": "0.18.0"
61
61
  },
62
62
  "engines": {
63
63
  "node": ">=22.0.0"
@@ -76,9 +76,11 @@
76
76
  "agora"
77
77
  ],
78
78
  "scripts": {
79
- "build": "vite build && tsc -p tsconfig.json",
79
+ "build": "pnpm run clean && vite build && tsc -p tsconfig.build.json && pnpm run check:dist",
80
+ "check:dist": "node ../../scripts/assert-build-output.mjs dist providers/agent_dashboard_provider.js",
81
+ "clean": "rm -rf dist",
80
82
  "test": "vitest run --passWithNoTests",
81
83
  "test:watch": "vitest",
82
- "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.app.json --noEmit"
84
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.app.json --noEmit && tsc -p tsconfig.tests.json"
83
85
  }
84
86
  }