@hachej/boring-governance 0.1.64

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 boringdata
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # @hachej/boring-governance
2
+
3
+ Reusable tenant governance wiring for boring-ui apps: YAML policy loading, model filtering, budget metering, company-context bindings, routes, and Company Admin rendering.
4
+
5
+ ## Server wiring
6
+
7
+ Call `createGovernance(config)` after loading core config and before `createCoreWorkspaceAgentServer` so invalid production policy still refuses boot early.
8
+
9
+ ```ts
10
+ const governance = await createGovernance(config)
11
+ const credits = buildCreditsWiring()
12
+ let appDb: unknown
13
+ const app = await createCoreWorkspaceAgentServer({
14
+ config,
15
+ plugins: createAppPlugins([governance.serverPlugin]),
16
+ metering: governance.createMeteringSink(credits.meteringSink, () => appDb as never),
17
+ filterModels: governance.filterModels,
18
+ getFilesystemBindings: governance.getFilesystemBindings(),
19
+ pi: governance.pi,
20
+ })
21
+ appDb = app.db
22
+ credits.attach(app)
23
+ ```
24
+
25
+ ## Front wiring
26
+
27
+ ```tsx
28
+ const governanceCompanyAdmin = createGovernanceCompanyAdmin()
29
+
30
+ <CoreWorkspaceAgentFront companyAdmin={governanceCompanyAdmin} />
31
+ ```
32
+
33
+ Policy source is configured with `BORING_GOVERNANCE_POLICY_PATH`. Company context source roots use `BORING_GOVERNANCE_COMPANY_CONTEXT_ROOT` or the default workspace root resolver outside sandbox mode.
@@ -0,0 +1,60 @@
1
+ import { LoadCompanyAdminStatus, RenderCompanyAdminContent, CompanyAdminLabels } from '@hachej/boring-core/front';
2
+ import * as react from 'react';
3
+
4
+ interface GovernancePolicyStatus {
5
+ state: 'disabled' | 'active' | 'invalid';
6
+ reason?: string;
7
+ path?: string | null;
8
+ message?: string;
9
+ tenantId?: string;
10
+ userCount?: number;
11
+ }
12
+ interface GovernanceMeResponse {
13
+ enabled: boolean;
14
+ role: 'admin' | 'user' | null;
15
+ admin: boolean;
16
+ policyStatus?: GovernancePolicyStatus;
17
+ tenant?: {
18
+ id: string;
19
+ companyContextWorkspaceId: string | null;
20
+ defaultMonthlyModelBudgetEur: number;
21
+ perRunHoldEur: number;
22
+ };
23
+ users?: Array<{
24
+ email: string;
25
+ role: 'admin' | 'user';
26
+ modelCount: number;
27
+ contextRuleCount: number;
28
+ }>;
29
+ models?: Array<{
30
+ email: string;
31
+ provider: string;
32
+ id: string;
33
+ monthlyBudgetEur: number;
34
+ monthlyBudgetMicros: number;
35
+ }>;
36
+ companyContextRules?: Array<{
37
+ email: string;
38
+ pattern: string;
39
+ }>;
40
+ }
41
+ declare function GovernanceAdminView({ status }: {
42
+ status: GovernanceMeResponse;
43
+ }): react.JSX.Element;
44
+
45
+ interface CreateGovernanceCompanyAdminOptions {
46
+ fetchImpl?: typeof fetch;
47
+ }
48
+ interface GovernanceCompanyAdminProvider {
49
+ loadStatus: LoadCompanyAdminStatus;
50
+ renderContent: RenderCompanyAdminContent;
51
+ labels: CompanyAdminLabels;
52
+ }
53
+ declare function createGovernanceCompanyAdmin({ fetchImpl }?: CreateGovernanceCompanyAdminOptions): GovernanceCompanyAdminProvider;
54
+ type GovernanceFrontPlugin = ((api: unknown) => void) & {
55
+ pluginId: string;
56
+ pluginLabel?: string;
57
+ };
58
+ declare const governanceFrontPlugin: GovernanceFrontPlugin;
59
+
60
+ export { type CreateGovernanceCompanyAdminOptions, GovernanceAdminView, type GovernanceCompanyAdminProvider, type GovernanceMeResponse, type GovernancePolicyStatus, createGovernanceCompanyAdmin, governanceFrontPlugin as default };
@@ -0,0 +1,137 @@
1
+ "use client";
2
+
3
+ // src/front/GovernanceAdminView.tsx
4
+ import { Button, Tabs, TabsContent, TabsList, TabsTrigger } from "@hachej/boring-ui-kit";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ function GovernanceAdminView({ status }) {
7
+ return /* @__PURE__ */ jsx("main", { className: "min-h-screen bg-background px-4 py-8 text-foreground sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-6xl flex-col gap-6", children: [
8
+ /* @__PURE__ */ jsxs("header", { className: "rounded-2xl border border-border bg-card p-6 shadow-sm", children: [
9
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground", children: "Company admin" }),
10
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between", children: [
11
+ /* @__PURE__ */ jsxs("div", { children: [
12
+ /* @__PURE__ */ jsx("h1", { className: "text-3xl font-semibold tracking-tight", children: "Tenant governance" }),
13
+ /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-2xl text-sm text-muted-foreground", children: "YAML-managed in v1. Review effective tenant roles, exact model grants, monthly EUR budgets, and company-context rules." })
14
+ ] }),
15
+ /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", children: /* @__PURE__ */ jsx("a", { href: "/", children: "Back to workspace" }) })
16
+ ] })
17
+ ] }),
18
+ /* @__PURE__ */ jsxs("section", { className: "grid gap-4 rounded-2xl border border-border bg-card p-6 shadow-sm md:grid-cols-3", children: [
19
+ /* @__PURE__ */ jsxs("div", { children: [
20
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground", children: "Policy source" }),
21
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium text-foreground", children: "YAML-managed in v1" }),
22
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Edit the host policy file and restart to reload." })
23
+ ] }),
24
+ /* @__PURE__ */ jsxs("div", { children: [
25
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground", children: "Tenant" }),
26
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium text-foreground", children: status.tenant?.id ?? status.policyStatus?.tenantId ?? "\u2014" }),
27
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: [
28
+ "Role: ",
29
+ status.role ?? "none"
30
+ ] })
31
+ ] }),
32
+ /* @__PURE__ */ jsxs("div", { children: [
33
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground", children: "Policy status" }),
34
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium text-foreground", children: status.policyStatus?.state ?? "active" }),
35
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Tenant invites are deferred/not implemented in v1." })
36
+ ] })
37
+ ] }),
38
+ /* @__PURE__ */ jsx("section", { className: "rounded-2xl border border-border bg-card p-4 shadow-sm sm:p-6", children: /* @__PURE__ */ jsxs(Tabs, { defaultValue: "context", className: "gap-4", children: [
39
+ /* @__PURE__ */ jsxs(TabsList, { "aria-label": "Company admin tabs", variant: "line", className: "flex-wrap justify-start", children: [
40
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "context", children: "Context access" }),
41
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "models", children: "Model control" }),
42
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "users", children: "Users" })
43
+ ] }),
44
+ /* @__PURE__ */ jsx(TabsContent, { value: "context", children: /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-border bg-muted/20 p-6", children: [
45
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold tracking-tight", children: "Context access" }),
46
+ /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-2xl text-sm text-muted-foreground", children: "Read-only effective company-context path grants from the YAML policy." }),
47
+ /* @__PURE__ */ jsx("div", { className: "mt-5 overflow-hidden rounded-lg border border-border bg-background", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
48
+ /* @__PURE__ */ jsx("thead", { className: "bg-muted/60 text-xs uppercase tracking-[0.12em] text-muted-foreground", children: /* @__PURE__ */ jsxs("tr", { children: [
49
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "User" }),
50
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "Allowed pattern" })
51
+ ] }) }),
52
+ /* @__PURE__ */ jsx("tbody", { children: (status.companyContextRules ?? []).length > 0 ? status.companyContextRules.map((rule, index) => /* @__PURE__ */ jsxs("tr", { className: "border-t border-border", children: [
53
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2 font-medium", children: rule.email }),
54
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2 font-mono text-xs text-muted-foreground", children: rule.pattern })
55
+ ] }, `${rule.email}-${index}`)) : /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 2, className: "px-3 py-4 text-muted-foreground", children: "No company-context rules in policy." }) }) })
56
+ ] }) })
57
+ ] }) }),
58
+ /* @__PURE__ */ jsx(TabsContent, { value: "models", children: /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-border bg-muted/20 p-6", children: [
59
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold tracking-tight", children: "Model control" }),
60
+ /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-2xl text-sm text-muted-foreground", children: "Read-only exact model grants and monthly EUR budgets from the YAML policy." }),
61
+ /* @__PURE__ */ jsx("div", { className: "mt-5 overflow-hidden rounded-lg border border-border bg-background", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
62
+ /* @__PURE__ */ jsx("thead", { className: "bg-muted/60 text-xs uppercase tracking-[0.12em] text-muted-foreground", children: /* @__PURE__ */ jsxs("tr", { children: [
63
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "User" }),
64
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "Model" }),
65
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "Monthly budget" })
66
+ ] }) }),
67
+ /* @__PURE__ */ jsx("tbody", { children: (status.models ?? []).length > 0 ? status.models.map((model) => /* @__PURE__ */ jsxs("tr", { className: "border-t border-border", children: [
68
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2 font-medium", children: model.email }),
69
+ /* @__PURE__ */ jsxs("td", { className: "px-3 py-2 font-mono text-xs text-muted-foreground", children: [
70
+ model.provider,
71
+ "/",
72
+ model.id
73
+ ] }),
74
+ /* @__PURE__ */ jsxs("td", { className: "px-3 py-2", children: [
75
+ "\u20AC",
76
+ model.monthlyBudgetEur
77
+ ] })
78
+ ] }, `${model.email}-${model.provider}-${model.id}`)) : /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 3, className: "px-3 py-4 text-muted-foreground", children: "No model grants in policy." }) }) })
79
+ ] }) })
80
+ ] }) }),
81
+ /* @__PURE__ */ jsx(TabsContent, { value: "users", children: /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-border bg-muted/20 p-6", children: [
82
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold tracking-tight", children: "Users" }),
83
+ /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-2xl text-sm text-muted-foreground", children: "Read-only tenant users from the YAML policy. Tenant invites are not implemented in v1." }),
84
+ /* @__PURE__ */ jsx("div", { className: "mt-5 overflow-hidden rounded-lg border border-border bg-background", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
85
+ /* @__PURE__ */ jsx("thead", { className: "bg-muted/60 text-xs uppercase tracking-[0.12em] text-muted-foreground", children: /* @__PURE__ */ jsxs("tr", { children: [
86
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "User" }),
87
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "Role" }),
88
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "Models" }),
89
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: "Context rules" })
90
+ ] }) }),
91
+ /* @__PURE__ */ jsx("tbody", { children: (status.users ?? []).length > 0 ? status.users.map((user) => /* @__PURE__ */ jsxs("tr", { className: "border-t border-border", children: [
92
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2 font-medium", children: user.email }),
93
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: user.role }),
94
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: user.modelCount }),
95
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: user.contextRuleCount })
96
+ ] }, user.email)) : /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 4, className: "px-3 py-4 text-muted-foreground", children: "No users in policy." }) }) })
97
+ ] }) })
98
+ ] }) })
99
+ ] }) })
100
+ ] }) });
101
+ }
102
+
103
+ // src/front/index.tsx
104
+ import { jsx as jsx2 } from "react/jsx-runtime";
105
+ function createGovernanceCompanyAdmin({ fetchImpl = fetch } = {}) {
106
+ const loadStatus = async () => {
107
+ const response = await fetchImpl("/api/v1/governance/me", { credentials: "include" });
108
+ if (response.status === 404) return null;
109
+ if (!response.ok) throw new Error(`Company admin status failed: HTTP ${response.status}`);
110
+ const body = await response.json();
111
+ if (body.policyStatus?.state === "invalid") {
112
+ throw new Error(body.policyStatus.message ?? "Governance policy is invalid");
113
+ }
114
+ return {
115
+ enabled: body.enabled,
116
+ admin: body.admin,
117
+ role: body.role,
118
+ details: body
119
+ };
120
+ };
121
+ const renderContent = (status) => /* @__PURE__ */ jsx2(GovernanceAdminView, { status: status.details });
122
+ const labels = {
123
+ menuLabel: "Company Admin",
124
+ pageTitle: "Company Admin",
125
+ deniedMessage: "You do not have access to Company Admin."
126
+ };
127
+ return { loadStatus, renderContent, labels };
128
+ }
129
+ var governanceFrontPlugin = (() => void 0);
130
+ Object.defineProperty(governanceFrontPlugin, "pluginId", { value: "boring-governance", enumerable: true });
131
+ Object.defineProperty(governanceFrontPlugin, "pluginLabel", { value: "Governance", enumerable: true });
132
+ var front_default = governanceFrontPlugin;
133
+ export {
134
+ GovernanceAdminView,
135
+ createGovernanceCompanyAdmin,
136
+ front_default as default
137
+ };
@@ -0,0 +1,176 @@
1
+ import * as _hachej_boring_agent_server from '@hachej/boring-agent/server';
2
+ import { AgentMeteringSink, RegisterAgentRoutesOptions } from '@hachej/boring-agent/server';
3
+ import { CoreConfig } from '@hachej/boring-core/shared';
4
+ import { CoreWorkspaceAgentServerPlugin } from '@hachej/boring-core/app/server';
5
+ import { FastifyRequest } from 'fastify';
6
+
7
+ type TenantRole = 'admin' | 'user';
8
+ interface GovernanceModelGrant {
9
+ provider: string;
10
+ id: string;
11
+ monthlyBudgetEur: number;
12
+ monthlyBudgetMicros: number;
13
+ }
14
+ interface GovernanceUserPolicy {
15
+ email: string;
16
+ role: TenantRole;
17
+ models: GovernanceModelGrant[];
18
+ companyContext: {
19
+ allow: string[];
20
+ };
21
+ }
22
+ interface GovernancePolicy {
23
+ tenant: {
24
+ id: string;
25
+ companyContextWorkspaceId: string | null;
26
+ defaultMonthlyModelBudgetEur: number;
27
+ perRunHoldEur: number;
28
+ perRunHoldMicros: number;
29
+ };
30
+ users: GovernanceUserPolicy[];
31
+ usersByEmail: Map<string, GovernanceUserPolicy>;
32
+ }
33
+ type GovernancePolicyStatus = {
34
+ state: 'disabled';
35
+ reason: 'missing-env' | 'missing-file';
36
+ path: string | null;
37
+ } | {
38
+ state: 'active';
39
+ path: string;
40
+ tenantId: string;
41
+ userCount: number;
42
+ } | {
43
+ state: 'invalid';
44
+ path: string;
45
+ message: string;
46
+ };
47
+ interface GovernanceLoadResult {
48
+ enabled: boolean;
49
+ policy: GovernancePolicy | null;
50
+ status: GovernancePolicyStatus;
51
+ }
52
+ interface GovernanceUserLike {
53
+ id?: string;
54
+ email: string;
55
+ emailVerified: boolean;
56
+ }
57
+ interface ServedModelLike {
58
+ provider: string;
59
+ id: string;
60
+ }
61
+
62
+ declare const GOVERNANCE_POLICY_PATH_ENV = "BORING_GOVERNANCE_POLICY_PATH";
63
+ declare const GOVERNANCE_DEV_EMAIL_VERIFICATION_OVERRIDE_ENV = "BORING_GOVERNANCE_ALLOW_UNVERIFIED_EMAIL_DEV";
64
+ interface LoadGovernancePolicyOptions {
65
+ env?: NodeJS.ProcessEnv;
66
+ nodeEnv?: string;
67
+ config?: Pick<CoreConfig, 'auth'>;
68
+ }
69
+ declare function loadGovernancePolicy({ env, nodeEnv, config, }?: LoadGovernancePolicyOptions): Promise<GovernanceLoadResult>;
70
+
71
+ type GovernancePolicyErrorCode = 'disabled' | 'invalid' | 'denied' | 'not_allowed';
72
+ declare class GovernancePolicyError extends Error {
73
+ readonly code: GovernancePolicyErrorCode;
74
+ constructor(message: string, code: GovernancePolicyErrorCode);
75
+ }
76
+ interface GovernanceMeResponse {
77
+ enabled: boolean;
78
+ role: TenantRole | null;
79
+ admin: boolean;
80
+ policyStatus?: GovernancePolicyStatus;
81
+ tenant?: {
82
+ id: string;
83
+ companyContextWorkspaceId: string | null;
84
+ defaultMonthlyModelBudgetEur: number;
85
+ perRunHoldEur: number;
86
+ };
87
+ users?: Array<{
88
+ email: string;
89
+ role: TenantRole;
90
+ modelCount: number;
91
+ contextRuleCount: number;
92
+ }>;
93
+ models?: Array<GovernanceModelGrant & {
94
+ email: string;
95
+ }>;
96
+ companyContextRules?: Array<{
97
+ email: string;
98
+ pattern: string;
99
+ }>;
100
+ }
101
+ declare class GovernanceService {
102
+ private readonly loaded;
103
+ constructor(loaded: GovernanceLoadResult);
104
+ isEnabled(): boolean;
105
+ policyStatus(): GovernancePolicyStatus;
106
+ policy(): GovernancePolicy | null;
107
+ private enabledPolicy;
108
+ private userPolicy;
109
+ roleForUser(user: GovernanceUserLike | null | undefined): TenantRole | null;
110
+ isAdmin(user: GovernanceUserLike | null | undefined): boolean;
111
+ allowedModelsForUser<TModel extends ServedModelLike>(user: GovernanceUserLike, servedModels: readonly TModel[]): TModel[];
112
+ assertModelAllowed(user: GovernanceUserLike, model: ServedModelLike): void;
113
+ monthlyBudgetMicros(user: GovernanceUserLike, model: ServedModelLike): number | null;
114
+ companyContextRules(user: GovernanceUserLike): string[];
115
+ companyContextWorkspaceId(): string | null;
116
+ me(user: GovernanceUserLike | null | undefined): GovernanceMeResponse;
117
+ }
118
+
119
+ declare const PostgresModelBudgetStore: new (db: unknown) => {
120
+ reserve(input: unknown): Promise<{
121
+ reservationId: string;
122
+ }>;
123
+ settle(input: unknown): Promise<void>;
124
+ release(input: unknown): Promise<void>;
125
+ };
126
+ type ModelBudgetDb = ConstructorParameters<typeof PostgresModelBudgetStore>[0];
127
+ declare function createGovernanceMeteringSink(options: {
128
+ service: GovernanceService;
129
+ getDb: () => ModelBudgetDb;
130
+ delegate: AgentMeteringSink;
131
+ holdTtlSeconds?: number;
132
+ }): AgentMeteringSink;
133
+
134
+ interface GovernanceFilesystemBindingContext {
135
+ request?: FastifyRequest;
136
+ workspaceId: string;
137
+ workspaceRoot: string;
138
+ sessionId?: string;
139
+ userId?: string;
140
+ userEmail?: string;
141
+ userEmailVerified?: boolean;
142
+ requestId?: string;
143
+ }
144
+ type CompanyContextRootResolver = (ctx: GovernanceFilesystemBindingContext, companyContextWorkspaceId: string) => string | null | undefined | Promise<string | null | undefined>;
145
+ interface CreateGovernanceFilesystemBindingsOptions {
146
+ /** Explicit source root resolver for the tenant company-context workspace. */
147
+ resolveCompanyContextRoot?: CompanyContextRootResolver;
148
+ projectionRootParent?: string;
149
+ }
150
+ declare function createDefaultCompanyContextRootResolver(env?: NodeJS.ProcessEnv): CompanyContextRootResolver | undefined;
151
+ declare function createGovernanceFilesystemBindings(service: GovernanceService, options?: CreateGovernanceFilesystemBindingsOptions): NonNullable<_hachej_boring_agent_server.RegisterAgentRoutesOptions['getFilesystemBindings']>;
152
+
153
+ declare function normalizePolicyEmail(value: string): string;
154
+ declare function validateGovernancePolicy(input: unknown): GovernancePolicy;
155
+
156
+ interface BuildGovernanceOptions extends Omit<LoadGovernancePolicyOptions, 'config'> {
157
+ config?: Pick<CoreConfig, 'auth'>;
158
+ }
159
+ declare function buildGovernanceService(options?: BuildGovernanceOptions): Promise<GovernanceService>;
160
+ type GovernanceMeteringOptions = Parameters<typeof createGovernanceMeteringSink>[0];
161
+ interface CreateGovernanceResult {
162
+ service: GovernanceService;
163
+ status: ReturnType<GovernanceService['policyStatus']>;
164
+ serverPlugin: CoreWorkspaceAgentServerPlugin;
165
+ filterModels: RegisterAgentRoutesOptions['filterModels'];
166
+ createMeteringSink(delegate: AgentMeteringSink, getDb: GovernanceMeteringOptions['getDb']): AgentMeteringSink;
167
+ getFilesystemBindings(options?: CreateGovernanceFilesystemBindingsOptions): NonNullable<RegisterAgentRoutesOptions['getFilesystemBindings']>;
168
+ pi: {
169
+ strictModelResolution: boolean;
170
+ };
171
+ }
172
+ declare function createGovernance(config: CoreConfig): Promise<CreateGovernanceResult>;
173
+ declare function createGovernanceModelFilter(service: GovernanceService): RegisterAgentRoutesOptions['filterModels'];
174
+ declare function createGovernanceServerPlugin(service: GovernanceService): CoreWorkspaceAgentServerPlugin;
175
+
176
+ export { type BuildGovernanceOptions, type CompanyContextRootResolver, type CreateGovernanceFilesystemBindingsOptions, type CreateGovernanceResult, GOVERNANCE_DEV_EMAIL_VERIFICATION_OVERRIDE_ENV, GOVERNANCE_POLICY_PATH_ENV, type GovernanceFilesystemBindingContext, type GovernanceLoadResult, type GovernanceMeResponse, type GovernanceModelGrant, type GovernancePolicy, GovernancePolicyError, type GovernancePolicyErrorCode, type GovernancePolicyStatus, GovernanceService, type GovernanceUserLike, type GovernanceUserPolicy, type ServedModelLike, type TenantRole, buildGovernanceService, createDefaultCompanyContextRootResolver, createGovernance, createGovernanceFilesystemBindings, createGovernanceMeteringSink, createGovernanceModelFilter, createGovernanceServerPlugin, loadGovernancePolicy, normalizePolicyEmail, validateGovernancePolicy };