@adhd/agent-core-policy 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/drizzle/0000_sleepy_bullseye.sql +16 -0
- package/drizzle/0001_pale_marvel_zombies.sql +11 -0
- package/drizzle/0002_category_policy_inheritance.sql +22 -0
- package/drizzle/meta/0000_snapshot.json +119 -0
- package/drizzle/meta/0001_snapshot.json +186 -0
- package/drizzle/meta/0002_snapshot.json +274 -0
- package/drizzle/meta/_journal.json +27 -0
- package/package.json +53 -0
- package/src/db/client.d.ts +7 -0
- package/src/db/client.d.ts.map +1 -0
- package/src/db/client.js +18 -0
- package/src/db/client.js.map +1 -0
- package/src/db/migrate-runner.d.ts +30 -0
- package/src/db/migrate-runner.d.ts.map +1 -0
- package/src/db/migrate-runner.js +34 -0
- package/src/db/migrate-runner.js.map +1 -0
- package/src/db/migrate.d.ts +9 -0
- package/src/db/migrate.d.ts.map +1 -0
- package/src/db/migrate.js +13 -0
- package/src/db/migrate.js.map +1 -0
- package/src/db/schema.d.ts +383 -0
- package/src/db/schema.d.ts.map +1 -0
- package/src/db/schema.js +139 -0
- package/src/db/schema.js.map +1 -0
- package/src/index.d.ts +14 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +20 -0
- package/src/index.js.map +1 -0
- package/src/plugin/index.d.ts +24 -0
- package/src/plugin/index.d.ts.map +1 -0
- package/src/plugin/index.js +140 -0
- package/src/plugin/index.js.map +1 -0
- package/src/plugin/rate-policy.d.ts +34 -0
- package/src/plugin/rate-policy.d.ts.map +1 -0
- package/src/plugin/rate-policy.js +36 -0
- package/src/plugin/rate-policy.js.map +1 -0
- package/src/seed/index.d.ts +39 -0
- package/src/seed/index.d.ts.map +1 -0
- package/src/seed/index.js +62 -0
- package/src/seed/index.js.map +1 -0
- package/src/seed/policy-templates.d.ts +45 -0
- package/src/seed/policy-templates.d.ts.map +1 -0
- package/src/seed/policy-templates.js +189 -0
- package/src/seed/policy-templates.js.map +1 -0
- package/src/seed/policy-types.d.ts +19 -0
- package/src/seed/policy-types.d.ts.map +1 -0
- package/src/seed/policy-types.js +44 -0
- package/src/seed/policy-types.js.map +1 -0
- package/src/store/agent-policy-store.d.ts +172 -0
- package/src/store/agent-policy-store.d.ts.map +1 -0
- package/src/store/agent-policy-store.js +241 -0
- package/src/store/agent-policy-store.js.map +1 -0
- package/src/store/policy-template-store.d.ts +72 -0
- package/src/store/policy-template-store.d.ts.map +1 -0
- package/src/store/policy-template-store.js +118 -0
- package/src/store/policy-template-store.js.map +1 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { eq } from 'drizzle-orm';
|
|
2
|
+
import { agentCategoriesTable, agentPoliciesTable, categoryPoliciesTable, } from '../db/schema.js';
|
|
3
|
+
import { PolicyError } from './policy-template-store.js';
|
|
4
|
+
/**
|
|
5
|
+
* Typed error thrown by {@link AgentPolicyStore} — mirrors the PolicyError
|
|
6
|
+
* pattern but for junction-specific error codes.
|
|
7
|
+
*/
|
|
8
|
+
export class AgentPolicyError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
data;
|
|
11
|
+
constructor(code, message, data) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = 'AgentPolicyError';
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.data = data;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// Re-export so callers can import the base PolicyError from this module too.
|
|
19
|
+
export { PolicyError };
|
|
20
|
+
// ──────────────────────────────────────────────
|
|
21
|
+
// Store
|
|
22
|
+
// ──────────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Thin Drizzle wrapper for the `policy_agent_policies` junction table.
|
|
25
|
+
*
|
|
26
|
+
* Mirrors the `PolicyTemplateStore` / `agent-mcp` AgentStore pattern:
|
|
27
|
+
* - constructor takes a `BetterSQLite3Database` handle (caller owns lifecycle)
|
|
28
|
+
* - methods are synchronous Drizzle queries
|
|
29
|
+
* - errors throw {@link AgentPolicyError} with typed codes
|
|
30
|
+
*
|
|
31
|
+
* Direct-attach (`attach`) sets `inherited_from = NULL`. Category inheritance
|
|
32
|
+
* resolution (`resolveForAgent`, added in the `policy-inheritance` state) reads
|
|
33
|
+
* the joined category membership at query time — lazy, per Decision 1.
|
|
34
|
+
*/
|
|
35
|
+
export class AgentPolicyStore {
|
|
36
|
+
db;
|
|
37
|
+
constructor(
|
|
38
|
+
// Accept any schema parameter so callers can pass a schema-typed db
|
|
39
|
+
// (e.g. drizzle(sqlite, { schema })) without a type-narrowing cast.
|
|
40
|
+
db) {
|
|
41
|
+
this.db = db;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Attach a policy template DIRECTLY to an agent (`inherited_from = null`).
|
|
45
|
+
*
|
|
46
|
+
* @throws {AgentPolicyError} AGENT_POLICY_ALREADY_ATTACHED when the
|
|
47
|
+
* (agentSlug, policySlug) pair already exists.
|
|
48
|
+
*/
|
|
49
|
+
attach(input) {
|
|
50
|
+
const existing = this.db
|
|
51
|
+
.select()
|
|
52
|
+
.from(agentPoliciesTable)
|
|
53
|
+
.where(eq(agentPoliciesTable.agentSlug, input.agentSlug))
|
|
54
|
+
.all()
|
|
55
|
+
.find((r) => r.policySlug === input.policySlug);
|
|
56
|
+
if (existing) {
|
|
57
|
+
throw new AgentPolicyError('AGENT_POLICY_ALREADY_ATTACHED', `Policy '${input.policySlug}' is already attached to agent '${input.agentSlug}'`);
|
|
58
|
+
}
|
|
59
|
+
const row = {
|
|
60
|
+
agentSlug: input.agentSlug,
|
|
61
|
+
policySlug: input.policySlug,
|
|
62
|
+
// drizzle `text({ mode: "json" })` serialises automatically when
|
|
63
|
+
// passed an object value; NULL is represented as null/undefined.
|
|
64
|
+
overrideConfig: (input.overrideConfig ?? null),
|
|
65
|
+
isMandatory: input.isMandatory ?? false,
|
|
66
|
+
// Direct attach — NOT inherited from a category. [Decision 1]
|
|
67
|
+
inheritedFrom: null,
|
|
68
|
+
};
|
|
69
|
+
this.db.insert(agentPoliciesTable).values(row).run();
|
|
70
|
+
const insertedRow = this.db
|
|
71
|
+
.select()
|
|
72
|
+
.from(agentPoliciesTable)
|
|
73
|
+
.where(eq(agentPoliciesTable.agentSlug, input.agentSlug))
|
|
74
|
+
.all()
|
|
75
|
+
.find((r) => r.policySlug === input.policySlug);
|
|
76
|
+
if (!insertedRow) {
|
|
77
|
+
throw new AgentPolicyError('AGENT_POLICY_ALREADY_ATTACHED', `Failed to read back inserted policy '${input.policySlug}' for agent '${input.agentSlug}'`);
|
|
78
|
+
}
|
|
79
|
+
return this._toRow(insertedRow);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Return all direct `policy_agent_policies` rows for the given agent slug.
|
|
83
|
+
*
|
|
84
|
+
* Returns only rows stored directly against the agent (`inherited_from IS NULL`
|
|
85
|
+
* for direct-attach rows). Use {@link resolveForAgent} to include inherited
|
|
86
|
+
* policies from category membership.
|
|
87
|
+
*
|
|
88
|
+
* @param agentSlug — the slug of the agent whose policies to retrieve.
|
|
89
|
+
*/
|
|
90
|
+
listForAgent(agentSlug) {
|
|
91
|
+
const rows = this.db
|
|
92
|
+
.select()
|
|
93
|
+
.from(agentPoliciesTable)
|
|
94
|
+
.where(eq(agentPoliciesTable.agentSlug, agentSlug))
|
|
95
|
+
.all();
|
|
96
|
+
return rows.map((r) => this._toRow(r));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Attach a policy template to a taxonomy CATEGORY (lazy inheritance).
|
|
100
|
+
*
|
|
101
|
+
* Stores a single `policy_category_policies` row — does NOT fan out rows to
|
|
102
|
+
* individual agents. Any agent already in or later added to the category
|
|
103
|
+
* inherits this policy at the next `resolveForAgent` call. [Decision 1]
|
|
104
|
+
*
|
|
105
|
+
* @throws {AgentPolicyError} CATEGORY_POLICY_ALREADY_ATTACHED when the
|
|
106
|
+
* (categorySlug, policySlug) pair already exists.
|
|
107
|
+
*/
|
|
108
|
+
attachToCategory(input) {
|
|
109
|
+
const existing = this.db
|
|
110
|
+
.select()
|
|
111
|
+
.from(categoryPoliciesTable)
|
|
112
|
+
.where(eq(categoryPoliciesTable.categorySlug, input.categorySlug))
|
|
113
|
+
.all()
|
|
114
|
+
.find((r) => r.policySlug === input.policySlug);
|
|
115
|
+
if (existing) {
|
|
116
|
+
throw new AgentPolicyError('CATEGORY_POLICY_ALREADY_ATTACHED', `Policy '${input.policySlug}' is already attached to category '${input.categorySlug}'`);
|
|
117
|
+
}
|
|
118
|
+
const row = {
|
|
119
|
+
categorySlug: input.categorySlug,
|
|
120
|
+
policySlug: input.policySlug,
|
|
121
|
+
isMandatory: input.isMandatory ?? false,
|
|
122
|
+
};
|
|
123
|
+
this.db.insert(categoryPoliciesTable).values(row).run();
|
|
124
|
+
return {
|
|
125
|
+
categorySlug: row.categorySlug,
|
|
126
|
+
policySlug: row.policySlug,
|
|
127
|
+
isMandatory: Boolean(row.isMandatory),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Record that an agent is a member of a taxonomy category.
|
|
132
|
+
*
|
|
133
|
+
* At the next `resolveForAgent` call the agent automatically inherits all
|
|
134
|
+
* policies attached to the category — no re-fanout or migration needed.
|
|
135
|
+
* This is the "agent added AFTER the category-attach" case from Decision 1.
|
|
136
|
+
*
|
|
137
|
+
* @throws {AgentPolicyError} AGENT_CATEGORY_ALREADY_JOINED when the
|
|
138
|
+
* (agentSlug, categorySlug) pair already exists.
|
|
139
|
+
*/
|
|
140
|
+
addAgentToCategory(input) {
|
|
141
|
+
const existing = this.db
|
|
142
|
+
.select()
|
|
143
|
+
.from(agentCategoriesTable)
|
|
144
|
+
.where(eq(agentCategoriesTable.agentSlug, input.agentSlug))
|
|
145
|
+
.all()
|
|
146
|
+
.find((r) => r.categorySlug === input.categorySlug);
|
|
147
|
+
if (existing) {
|
|
148
|
+
throw new AgentPolicyError('AGENT_CATEGORY_ALREADY_JOINED', `Agent '${input.agentSlug}' is already in category '${input.categorySlug}'`);
|
|
149
|
+
}
|
|
150
|
+
this.db
|
|
151
|
+
.insert(agentCategoriesTable)
|
|
152
|
+
.values({ agentSlug: input.agentSlug, categorySlug: input.categorySlug })
|
|
153
|
+
.run();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Resolve the complete effective policy set for an agent at query time.
|
|
157
|
+
*
|
|
158
|
+
* Returns a union of:
|
|
159
|
+
* 1. Policies attached DIRECTLY to the agent (inheritedFrom = null).
|
|
160
|
+
* 2. Policies inherited from every category the agent belongs to,
|
|
161
|
+
* synthesised as rows with inheritedFrom = categorySlug. [Decision 1]
|
|
162
|
+
*
|
|
163
|
+
* The join is performed at call time so newly added category policies or
|
|
164
|
+
* membership changes are always reflected — there is no stale materialised
|
|
165
|
+
* cache to invalidate.
|
|
166
|
+
*
|
|
167
|
+
* If an agent has a direct-attach for a policy AND inherits the same policy
|
|
168
|
+
* from a category, the direct-attach row takes precedence (override wins).
|
|
169
|
+
*
|
|
170
|
+
* @param agentSlug — the slug of the agent to resolve policies for.
|
|
171
|
+
*/
|
|
172
|
+
resolveForAgent(agentSlug) {
|
|
173
|
+
// 1. Direct-attach policies for this agent.
|
|
174
|
+
const directRows = this.db
|
|
175
|
+
.select()
|
|
176
|
+
.from(agentPoliciesTable)
|
|
177
|
+
.where(eq(agentPoliciesTable.agentSlug, agentSlug))
|
|
178
|
+
.all();
|
|
179
|
+
const directPolicySlugs = new Set(directRows.map((r) => r.policySlug));
|
|
180
|
+
// 2. Categories the agent belongs to.
|
|
181
|
+
const categoryMemberships = this.db
|
|
182
|
+
.select()
|
|
183
|
+
.from(agentCategoriesTable)
|
|
184
|
+
.where(eq(agentCategoriesTable.agentSlug, agentSlug))
|
|
185
|
+
.all();
|
|
186
|
+
// 3. For each category membership, fetch attached policies and synthesise
|
|
187
|
+
// inherited rows — skipping any policy already covered by a direct-attach
|
|
188
|
+
// (direct attachment wins per the override semantics).
|
|
189
|
+
const inheritedRows = [];
|
|
190
|
+
for (const membership of categoryMemberships) {
|
|
191
|
+
const catPolicies = this.db
|
|
192
|
+
.select()
|
|
193
|
+
.from(categoryPoliciesTable)
|
|
194
|
+
.where(eq(categoryPoliciesTable.categorySlug, membership.categorySlug))
|
|
195
|
+
.all();
|
|
196
|
+
for (const catPolicy of catPolicies) {
|
|
197
|
+
if (directPolicySlugs.has(catPolicy.policySlug)) {
|
|
198
|
+
// Direct-attach overrides; skip the inherited copy.
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
inheritedRows.push({
|
|
202
|
+
agentSlug: agentSlug,
|
|
203
|
+
policySlug: catPolicy.policySlug,
|
|
204
|
+
overrideConfig: null,
|
|
205
|
+
isMandatory: Boolean(catPolicy.isMandatory),
|
|
206
|
+
// The key contract: inherited_from = the category slug. [Decision 1]
|
|
207
|
+
inheritedFrom: catPolicy.categorySlug,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return [...directRows.map((r) => this._toRow(r)), ...inheritedRows];
|
|
212
|
+
}
|
|
213
|
+
// ── private helpers ──────────────────────────────────────────────────────
|
|
214
|
+
_toRow(row) {
|
|
215
|
+
return {
|
|
216
|
+
agentSlug: row.agentSlug,
|
|
217
|
+
policySlug: row.policySlug,
|
|
218
|
+
// drizzle returns parsed JS value for `mode:"json"` columns.
|
|
219
|
+
overrideConfig: row.overrideConfig ?? null,
|
|
220
|
+
isMandatory: Boolean(row.isMandatory),
|
|
221
|
+
inheritedFrom: row.inheritedFrom ?? null,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Compute effective rules by shallow-merging `overrideConfig` on top of
|
|
227
|
+
* `templateRules`. Override keys replace template keys (arrays and nested
|
|
228
|
+
* objects are replaced wholesale). An absent or empty override leaves the
|
|
229
|
+
* template unchanged. [Decision 3]
|
|
230
|
+
*
|
|
231
|
+
* @param templateRules — the base rules object from `policy_policy_templates`.
|
|
232
|
+
* @param overrideConfig — the per-agent override (may be null/undefined).
|
|
233
|
+
* @returns the effective merged rules object.
|
|
234
|
+
*/
|
|
235
|
+
export function resolveEffectiveRules(templateRules, overrideConfig) {
|
|
236
|
+
if (!overrideConfig || Object.keys(overrideConfig).length === 0) {
|
|
237
|
+
return templateRules;
|
|
238
|
+
}
|
|
239
|
+
return { ...templateRules, ...overrideConfig };
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=agent-policy-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-policy-store.js","sourceRoot":"","sources":["../../../../../../packages/agent/agent-core-policy/src/store/agent-policy-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
type AnyBetterSQLite3Database = import('drizzle-orm/better-sqlite3').BetterSQLite3Database<any>;
|
|
2
|
+
export type PolicyErrorCode = 'POLICY_TEMPLATE_NOT_FOUND' | 'POLICY_TEMPLATE_ALREADY_EXISTS';
|
|
3
|
+
/**
|
|
4
|
+
* Typed error thrown by policy stores — mirrors the ToolError pattern from
|
|
5
|
+
* agent-mcp but uses the policy-specific error code union.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PolicyError extends Error {
|
|
8
|
+
readonly code: PolicyErrorCode;
|
|
9
|
+
readonly data?: unknown;
|
|
10
|
+
constructor(code: PolicyErrorCode, message: string, data?: unknown);
|
|
11
|
+
}
|
|
12
|
+
/** A policy template as persisted and returned by {@link PolicyTemplateStore}. */
|
|
13
|
+
export interface PolicyTemplate {
|
|
14
|
+
/** Unique identifier slug (text PK). */
|
|
15
|
+
slug: string;
|
|
16
|
+
/** FK to policy_policy_types.slug (plain text — no cross-prefix FK). */
|
|
17
|
+
type: string;
|
|
18
|
+
description: string;
|
|
19
|
+
/** Structured rule parameters — deserialized from the JSON column. */
|
|
20
|
+
rules: Record<string, unknown>;
|
|
21
|
+
/**
|
|
22
|
+
* One or more enforcement mechanism strings.
|
|
23
|
+
* Always a JSON ARRAY — never a scalar string. [inv:enforcement-is-array]
|
|
24
|
+
*/
|
|
25
|
+
enforcement: string[];
|
|
26
|
+
/** Schema version; starts at 1. */
|
|
27
|
+
version: number;
|
|
28
|
+
/** True for system-owned templates (shipped with the package). */
|
|
29
|
+
isSystem: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Input for {@link PolicyTemplateStore.create}. `version` and `isSystem`
|
|
33
|
+
* default to 1 / false when omitted.
|
|
34
|
+
*/
|
|
35
|
+
export type PolicyTemplateCreateInput = Omit<PolicyTemplate, 'version' | 'isSystem'> & {
|
|
36
|
+
version?: number;
|
|
37
|
+
isSystem?: boolean;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Thin Drizzle wrapper for the `policy_policy_templates` table.
|
|
41
|
+
*
|
|
42
|
+
* Mirrors `@adhd/agent-mcp`'s AgentStore pattern:
|
|
43
|
+
* - constructor takes a `BetterSQLite3Database` handle (caller owns lifecycle)
|
|
44
|
+
* - methods are synchronous Drizzle queries
|
|
45
|
+
* - errors throw {@link PolicyError} with typed codes
|
|
46
|
+
*/
|
|
47
|
+
export declare class PolicyTemplateStore {
|
|
48
|
+
private readonly db;
|
|
49
|
+
constructor(db: AnyBetterSQLite3Database);
|
|
50
|
+
/**
|
|
51
|
+
* Persist a new policy template.
|
|
52
|
+
*
|
|
53
|
+
* @throws {PolicyError} POLICY_TEMPLATE_ALREADY_EXISTS if the slug is taken.
|
|
54
|
+
*/
|
|
55
|
+
create(input: PolicyTemplateCreateInput): PolicyTemplate;
|
|
56
|
+
/**
|
|
57
|
+
* Retrieve a single template by slug.
|
|
58
|
+
*
|
|
59
|
+
* @throws {PolicyError} POLICY_TEMPLATE_NOT_FOUND if no such slug exists.
|
|
60
|
+
*/
|
|
61
|
+
read(slug: string): PolicyTemplate;
|
|
62
|
+
/**
|
|
63
|
+
* Return all templates, optionally filtered by `type` slug.
|
|
64
|
+
*
|
|
65
|
+
* @param typeFilter — when provided, only templates whose `type` matches
|
|
66
|
+
* this slug are returned.
|
|
67
|
+
*/
|
|
68
|
+
list(typeFilter?: string): PolicyTemplate[];
|
|
69
|
+
private _toTemplate;
|
|
70
|
+
}
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=policy-template-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-template-store.d.ts","sourceRoot":"","sources":["../../../../../../packages/agent/agent-core-policy/src/store/policy-template-store.ts"],"names":[],"mappings":"AAGA,KAAK,wBAAwB,GAAG,OAAO,4BAA4B,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC;AAQhG,MAAM,MAAM,eAAe,GACvB,2BAA2B,GAC3B,gCAAgC,CAAC;AAErC;;;GAGG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;gBAEZ,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAMnE;AAMD,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;;;OAGG;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,cAAc,EACd,SAAS,GAAG,UAAU,CACvB,GAAG;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAMF;;;;;;;GAOG;AACH,qBAAa,mBAAmB;IAI5B,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,wBAAwB;IAG/C;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,yBAAyB,GAAG,cAAc;IA2CxD;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc;IAiBlC;;;;;OAKG;IACH,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE;IAc3C,OAAO,CAAC,WAAW;CAcpB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { eq } from 'drizzle-orm';
|
|
2
|
+
import { policyTemplatesTable } from '../db/schema.js';
|
|
3
|
+
/**
|
|
4
|
+
* Typed error thrown by policy stores — mirrors the ToolError pattern from
|
|
5
|
+
* agent-mcp but uses the policy-specific error code union.
|
|
6
|
+
*/
|
|
7
|
+
export class PolicyError extends Error {
|
|
8
|
+
code;
|
|
9
|
+
data;
|
|
10
|
+
constructor(code, message, data) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'PolicyError';
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.data = data;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// ──────────────────────────────────────────────
|
|
18
|
+
// Store
|
|
19
|
+
// ──────────────────────────────────────────────
|
|
20
|
+
/**
|
|
21
|
+
* Thin Drizzle wrapper for the `policy_policy_templates` table.
|
|
22
|
+
*
|
|
23
|
+
* Mirrors `@adhd/agent-mcp`'s AgentStore pattern:
|
|
24
|
+
* - constructor takes a `BetterSQLite3Database` handle (caller owns lifecycle)
|
|
25
|
+
* - methods are synchronous Drizzle queries
|
|
26
|
+
* - errors throw {@link PolicyError} with typed codes
|
|
27
|
+
*/
|
|
28
|
+
export class PolicyTemplateStore {
|
|
29
|
+
db;
|
|
30
|
+
constructor(
|
|
31
|
+
// Accept any schema parameter so callers can pass a schema-typed db
|
|
32
|
+
// (e.g. drizzle(sqlite, { schema })) without a type-narrowing cast.
|
|
33
|
+
db) {
|
|
34
|
+
this.db = db;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Persist a new policy template.
|
|
38
|
+
*
|
|
39
|
+
* @throws {PolicyError} POLICY_TEMPLATE_ALREADY_EXISTS if the slug is taken.
|
|
40
|
+
*/
|
|
41
|
+
create(input) {
|
|
42
|
+
const existing = this.db
|
|
43
|
+
.select()
|
|
44
|
+
.from(policyTemplatesTable)
|
|
45
|
+
.where(eq(policyTemplatesTable.slug, input.slug))
|
|
46
|
+
.get();
|
|
47
|
+
if (existing) {
|
|
48
|
+
throw new PolicyError('POLICY_TEMPLATE_ALREADY_EXISTS', `Policy template '${input.slug}' already exists`);
|
|
49
|
+
}
|
|
50
|
+
const row = {
|
|
51
|
+
slug: input.slug,
|
|
52
|
+
type: input.type,
|
|
53
|
+
description: input.description,
|
|
54
|
+
// drizzle `text({ mode: "json" })` serialises automatically when
|
|
55
|
+
// passed an object/array value.
|
|
56
|
+
rules: input.rules,
|
|
57
|
+
enforcement: input.enforcement,
|
|
58
|
+
version: input.version ?? 1,
|
|
59
|
+
isSystem: input.isSystem ?? false,
|
|
60
|
+
};
|
|
61
|
+
this.db.insert(policyTemplatesTable).values(row).run();
|
|
62
|
+
const inserted = this.db
|
|
63
|
+
.select()
|
|
64
|
+
.from(policyTemplatesTable)
|
|
65
|
+
.where(eq(policyTemplatesTable.slug, input.slug))
|
|
66
|
+
.get();
|
|
67
|
+
if (!inserted) {
|
|
68
|
+
throw new Error(`Failed to read back inserted policy template '${input.slug}'`);
|
|
69
|
+
}
|
|
70
|
+
return this._toTemplate(inserted);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Retrieve a single template by slug.
|
|
74
|
+
*
|
|
75
|
+
* @throws {PolicyError} POLICY_TEMPLATE_NOT_FOUND if no such slug exists.
|
|
76
|
+
*/
|
|
77
|
+
read(slug) {
|
|
78
|
+
const row = this.db
|
|
79
|
+
.select()
|
|
80
|
+
.from(policyTemplatesTable)
|
|
81
|
+
.where(eq(policyTemplatesTable.slug, slug))
|
|
82
|
+
.get();
|
|
83
|
+
if (!row) {
|
|
84
|
+
throw new PolicyError('POLICY_TEMPLATE_NOT_FOUND', `Policy template '${slug}' not found`);
|
|
85
|
+
}
|
|
86
|
+
return this._toTemplate(row);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Return all templates, optionally filtered by `type` slug.
|
|
90
|
+
*
|
|
91
|
+
* @param typeFilter — when provided, only templates whose `type` matches
|
|
92
|
+
* this slug are returned.
|
|
93
|
+
*/
|
|
94
|
+
list(typeFilter) {
|
|
95
|
+
const rows = typeFilter
|
|
96
|
+
? this.db
|
|
97
|
+
.select()
|
|
98
|
+
.from(policyTemplatesTable)
|
|
99
|
+
.where(eq(policyTemplatesTable.type, typeFilter))
|
|
100
|
+
.all()
|
|
101
|
+
: this.db.select().from(policyTemplatesTable).all();
|
|
102
|
+
return rows.map((row) => this._toTemplate(row));
|
|
103
|
+
}
|
|
104
|
+
// ── private helpers ──────────────────────────────────────────────────────
|
|
105
|
+
_toTemplate(row) {
|
|
106
|
+
return {
|
|
107
|
+
slug: row.slug,
|
|
108
|
+
type: row.type,
|
|
109
|
+
description: row.description,
|
|
110
|
+
// drizzle returns parsed JS value for `mode:"json"` columns.
|
|
111
|
+
rules: row.rules,
|
|
112
|
+
enforcement: row.enforcement,
|
|
113
|
+
version: row.version,
|
|
114
|
+
isSystem: Boolean(row.isSystem),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=policy-template-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-template-store.js","sourceRoot":"","sources":["../../../../../../packages/agent/agent-core-policy/src/store/policy-template-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAKjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAUvD;;;GAGG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,IAAI,CAAkB;IACtB,IAAI,CAAW;IAExB,YAAY,IAAqB,EAAE,OAAe,EAAE,IAAc;QAChE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAsCD,iDAAiD;AACjD,QAAQ;AACR,iDAAiD;AAEjD;;;;;;;GAOG;AACH,MAAM,OAAO,mBAAmB;IAIX;IAHnB;IACE,oEAAoE;IACpE,oEAAoE;IACnD,EAA4B;QAA5B,OAAE,GAAF,EAAE,CAA0B;IAC5C,CAAC;IAEJ;;;;OAIG;IACH,MAAM,CAAC,KAAgC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE;aACrB,MAAM,EAAE;aACR,IAAI,CAAC,oBAAoB,CAAC;aAC1B,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;aAChD,GAAG,EAAE,CAAC;QAET,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,IAAI,WAAW,CACnB,gCAAgC,EAChC,oBAAoB,KAAK,CAAC,IAAI,kBAAkB,CACjD,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG;YACV,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,iEAAiE;YACjE,gCAAgC;YAChC,KAAK,EAAE,KAAK,CAAC,KAA0B;YACvC,WAAW,EAAE,KAAK,CAAC,WAAgC;YACnD,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,CAAC;YAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK;SAClC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAEvD,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE;aACrB,MAAM,EAAE;aACR,IAAI,CAAC,oBAAoB,CAAC;aAC1B,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;aAChD,GAAG,EAAE,CAAC;QAET,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,iDAAiD,KAAK,CAAC,IAAI,GAAG,CAC/D,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED;;;;OAIG;IACH,IAAI,CAAC,IAAY;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,MAAM,EAAE;aACR,IAAI,CAAC,oBAAoB,CAAC;aAC1B,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;aAC1C,GAAG,EAAE,CAAC;QAET,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,WAAW,CACnB,2BAA2B,EAC3B,oBAAoB,IAAI,aAAa,CACtC,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,UAAmB;QACtB,MAAM,IAAI,GAAG,UAAU;YACrB,CAAC,CAAC,IAAI,CAAC,EAAE;iBACJ,MAAM,EAAE;iBACR,IAAI,CAAC,oBAAoB,CAAC;iBAC1B,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;iBAChD,GAAG,EAAE;YACV,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,GAAG,EAAE,CAAC;QAEtD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,4EAA4E;IAEpE,WAAW,CACjB,GAA6C;QAE7C,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,6DAA6D;YAC7D,KAAK,EAAE,GAAG,CAAC,KAA2C;YACtD,WAAW,EAAE,GAAG,CAAC,WAAkC;YACnD,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;SAChC,CAAC;IACJ,CAAC;CACF"}
|