@eddacraft/anvil-kindling-integration 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +542 -0
  3. package/dist/adapter.d.ts +49 -0
  4. package/dist/adapter.d.ts.map +1 -0
  5. package/dist/adapter.js +100 -0
  6. package/dist/config.d.ts +89 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +173 -0
  9. package/dist/emitters/action-emitter.d.ts +40 -0
  10. package/dist/emitters/action-emitter.d.ts.map +1 -0
  11. package/dist/emitters/action-emitter.js +52 -0
  12. package/dist/emitters/constraint-emitter.d.ts +32 -0
  13. package/dist/emitters/constraint-emitter.d.ts.map +1 -0
  14. package/dist/emitters/constraint-emitter.js +41 -0
  15. package/dist/emitters/error-emitter.d.ts +33 -0
  16. package/dist/emitters/error-emitter.d.ts.map +1 -0
  17. package/dist/emitters/error-emitter.js +50 -0
  18. package/dist/emitters/gate-emitter.d.ts +37 -0
  19. package/dist/emitters/gate-emitter.d.ts.map +1 -0
  20. package/dist/emitters/gate-emitter.js +53 -0
  21. package/dist/emitters/human-input-emitter.d.ts +30 -0
  22. package/dist/emitters/human-input-emitter.d.ts.map +1 -0
  23. package/dist/emitters/human-input-emitter.js +38 -0
  24. package/dist/emitters/index.d.ts +13 -0
  25. package/dist/emitters/index.d.ts.map +1 -0
  26. package/dist/emitters/index.js +19 -0
  27. package/dist/emitters/plan-emitter.d.ts +75 -0
  28. package/dist/emitters/plan-emitter.d.ts.map +1 -0
  29. package/dist/emitters/plan-emitter.js +116 -0
  30. package/dist/emitters/session-emitter.d.ts +57 -0
  31. package/dist/emitters/session-emitter.d.ts.map +1 -0
  32. package/dist/emitters/session-emitter.js +80 -0
  33. package/dist/index.d.ts +40 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +111 -0
  36. package/dist/kindling-service.d.ts +122 -0
  37. package/dist/kindling-service.d.ts.map +1 -0
  38. package/dist/kindling-service.js +203 -0
  39. package/dist/observation-contract.d.ts +561 -0
  40. package/dist/observation-contract.d.ts.map +1 -0
  41. package/dist/observation-contract.js +391 -0
  42. package/dist/query-contract.d.ts +463 -0
  43. package/dist/query-contract.d.ts.map +1 -0
  44. package/dist/query-contract.js +314 -0
  45. package/dist/query-limits.d.ts +40 -0
  46. package/dist/query-limits.d.ts.map +1 -0
  47. package/dist/query-limits.js +79 -0
  48. package/dist/query-service.d.ts +109 -0
  49. package/dist/query-service.d.ts.map +1 -0
  50. package/dist/query-service.js +140 -0
  51. package/dist/retention.d.ts +79 -0
  52. package/dist/retention.d.ts.map +1 -0
  53. package/dist/retention.js +81 -0
  54. package/dist/sensitive-data-validator.d.ts +47 -0
  55. package/dist/sensitive-data-validator.d.ts.map +1 -0
  56. package/dist/sensitive-data-validator.js +135 -0
  57. package/dist/status.d.ts +104 -0
  58. package/dist/status.d.ts.map +1 -0
  59. package/dist/status.js +136 -0
  60. package/dist/utils/debug.d.ts +9 -0
  61. package/dist/utils/debug.d.ts.map +1 -0
  62. package/dist/utils/debug.js +55 -0
  63. package/package.json +114 -0
  64. package/src/adapter.ts +117 -0
  65. package/src/config.ts +202 -0
  66. package/src/emitters/action-emitter.ts +90 -0
  67. package/src/emitters/constraint-emitter.ts +73 -0
  68. package/src/emitters/error-emitter.ts +86 -0
  69. package/src/emitters/gate-emitter.ts +87 -0
  70. package/src/emitters/human-input-emitter.ts +71 -0
  71. package/src/emitters/index.ts +40 -0
  72. package/src/emitters/plan-emitter.ts +183 -0
  73. package/src/emitters/session-emitter.ts +131 -0
  74. package/src/index.ts +254 -0
  75. package/src/kindling-service.ts +272 -0
  76. package/src/malicious-ai.test.ts +949 -0
  77. package/src/observation-contract.ts +500 -0
  78. package/src/query-contract.ts +389 -0
  79. package/src/query-limits.ts +106 -0
  80. package/src/query-service.ts +217 -0
  81. package/src/retention.ts +153 -0
  82. package/src/sensitive-data-validator.ts +167 -0
  83. package/src/status.ts +221 -0
  84. package/src/utils/debug.ts +65 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * KindlingService (KINDLING-001)
3
+ *
4
+ * Core service wrapper that mediates between Anvil and the Kindling store.
5
+ * Handles validation, sensitive-data checks, and delegation to the store adapter.
6
+ *
7
+ * The service is built against the abstract `IKindlingStore` interface so that
8
+ * it compiles without @kindling/core or @kindling/store-sqlite installed.
9
+ * The actual storage backend is plugged in at runtime via the factory function.
10
+ *
11
+ * When no store is provided, the service operates in "disabled mode" using a
12
+ * no-op store that silently discards all observations.
13
+ */
14
+ import type { Observation } from './observation-contract.js';
15
+ import type { QueryRequest, QueryResponse } from './query-contract.js';
16
+ import type { KindlingConfig } from './config.js';
17
+ /**
18
+ * Abstract storage adapter interface.
19
+ *
20
+ * Implementations must provide emit (write), query (read), and close (cleanup).
21
+ * This decouples the service layer from any concrete Kindling SDK dependency.
22
+ */
23
+ export interface IKindlingStore {
24
+ /**
25
+ * Persist an observation to the store.
26
+ * The observation has already been validated and redacted by the service layer.
27
+ */
28
+ emit(observation: Observation): Promise<void>;
29
+ /**
30
+ * Execute a bounded query against the store.
31
+ * The request has already been validated by the service layer.
32
+ */
33
+ query(request: QueryRequest): Promise<QueryResponse>;
34
+ /**
35
+ * Release resources (close database connections, flush buffers, etc.)
36
+ */
37
+ close(): Promise<void>;
38
+ }
39
+ /**
40
+ * No-op store used when Kindling is disabled or no store is provided.
41
+ * All operations succeed silently without side effects.
42
+ */
43
+ export declare class NoOpKindlingStore implements IKindlingStore {
44
+ emit(_observation: Observation): Promise<void>;
45
+ query(_request: QueryRequest): Promise<QueryResponse>;
46
+ close(): Promise<void>;
47
+ }
48
+ /**
49
+ * Error thrown when observation validation fails
50
+ */
51
+ export declare class ObservationValidationError extends Error {
52
+ readonly issues: string[];
53
+ constructor(message: string, issues: string[]);
54
+ }
55
+ /**
56
+ * Error thrown when query validation fails
57
+ */
58
+ export declare class QueryValidationError extends Error {
59
+ constructor(message: string);
60
+ }
61
+ /**
62
+ * Core Kindling service that wraps the store adapter with validation,
63
+ * sensitive-data checks, and config-driven behavior.
64
+ */
65
+ export declare class KindlingService {
66
+ private readonly store;
67
+ private readonly config;
68
+ private closed;
69
+ constructor(store: IKindlingStore, config: KindlingConfig);
70
+ /**
71
+ * Whether the service is enabled (will actually emit observations)
72
+ */
73
+ get enabled(): boolean;
74
+ /**
75
+ * The active configuration
76
+ */
77
+ get configuration(): Readonly<KindlingConfig>;
78
+ /**
79
+ * Emit an observation to the Kindling store.
80
+ *
81
+ * This method is designed to be async and non-blocking. It:
82
+ * 1. Checks if the service is enabled and the observation kind should be captured
83
+ * 2. Validates the observation against the contract schema
84
+ * 3. Checks for and redacts sensitive data
85
+ * 4. Delegates to the store adapter
86
+ *
87
+ * Validation errors are thrown. Store errors are thrown (callers should catch
88
+ * if they want fire-and-forget semantics -- see emitters).
89
+ *
90
+ * @param observation - The observation to emit
91
+ * @throws ObservationValidationError if the observation is invalid
92
+ */
93
+ emit(observation: Observation): Promise<void>;
94
+ /**
95
+ * Execute a query against the Kindling store.
96
+ *
97
+ * Validates the query request against the contract schema and enforces
98
+ * configured query limits before delegating to the store.
99
+ *
100
+ * @param request - The query request
101
+ * @returns Query response with observations
102
+ * @throws QueryValidationError if the request is invalid
103
+ */
104
+ query(request: QueryRequest): Promise<QueryResponse>;
105
+ /**
106
+ * Close the service and release underlying store resources.
107
+ * After calling close(), emit() becomes a no-op and query() throws.
108
+ */
109
+ close(): Promise<void>;
110
+ }
111
+ /**
112
+ * Create a KindlingService instance.
113
+ *
114
+ * If no store is provided, the service operates in disabled mode with a no-op store.
115
+ * This allows code to unconditionally call emit/query without checking for null.
116
+ *
117
+ * @param config - Kindling configuration (defaults to disabled config)
118
+ * @param store - Optional store adapter (defaults to NoOpKindlingStore)
119
+ * @returns Configured KindlingService instance
120
+ */
121
+ export declare function createKindlingService(config?: KindlingConfig, store?: IKindlingStore): KindlingService;
122
+ //# sourceMappingURL=kindling-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kindling-service.d.ts","sourceRoot":"","sources":["../src/kindling-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAWlD;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAErD;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAMD;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,cAAc;IAChD,IAAI,CAAC,YAAY,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,KAAK,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAcrD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAMD;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;aAGjC,MAAM,EAAE,MAAM,EAAE;gBADhC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EAAE;CAKnC;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAMD;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,MAAM,CAAS;gBAEX,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc;IAMzD;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,QAAQ,CAAC,cAAc,CAAC,CAE5C;IAED;;;;;;;;;;;;;;OAcG;IACG,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCnD;;;;;;;;;OASG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IA8B1D;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B;AAMD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,GAAE,cAAwC,EAChD,KAAK,CAAC,EAAE,cAAc,GACrB,eAAe,CAIjB"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * KindlingService (KINDLING-001)
3
+ *
4
+ * Core service wrapper that mediates between Anvil and the Kindling store.
5
+ * Handles validation, sensitive-data checks, and delegation to the store adapter.
6
+ *
7
+ * The service is built against the abstract `IKindlingStore` interface so that
8
+ * it compiles without @kindling/core or @kindling/store-sqlite installed.
9
+ * The actual storage backend is plugged in at runtime via the factory function.
10
+ *
11
+ * When no store is provided, the service operates in "disabled mode" using a
12
+ * no-op store that silently discards all observations.
13
+ */
14
+ import { validateObservation } from './observation-contract.js';
15
+ import { QueryRequestSchema } from './query-contract.js';
16
+ import { DEFAULT_KINDLING_CONFIG, shouldCapture } from './config.js';
17
+ import { validateNoSensitiveData, redactSensitiveFields } from './sensitive-data-validator.js';
18
+ import { createDebugger } from './utils/debug.js';
19
+ const debug = createDebugger('kindling');
20
+ // =============================================================================
21
+ // No-Op Store (Disabled Mode)
22
+ // =============================================================================
23
+ /**
24
+ * No-op store used when Kindling is disabled or no store is provided.
25
+ * All operations succeed silently without side effects.
26
+ */
27
+ export class NoOpKindlingStore {
28
+ async emit(_observation) {
29
+ // Intentionally empty -- disabled mode
30
+ }
31
+ async query(_request) {
32
+ return {
33
+ metadata: {
34
+ query_id: crypto.randomUUID(),
35
+ executed_at: new Date().toISOString(),
36
+ contract_version: '1.0.0',
37
+ result_count: 0,
38
+ truncated: false,
39
+ truncation_reason: 'none',
40
+ },
41
+ observations: [],
42
+ };
43
+ }
44
+ async close() {
45
+ // Intentionally empty -- nothing to close
46
+ }
47
+ }
48
+ // =============================================================================
49
+ // Service Errors
50
+ // =============================================================================
51
+ /**
52
+ * Error thrown when observation validation fails
53
+ */
54
+ export class ObservationValidationError extends Error {
55
+ issues;
56
+ constructor(message, issues) {
57
+ super(message);
58
+ this.issues = issues;
59
+ this.name = 'ObservationValidationError';
60
+ }
61
+ }
62
+ /**
63
+ * Error thrown when query validation fails
64
+ */
65
+ export class QueryValidationError extends Error {
66
+ constructor(message) {
67
+ super(message);
68
+ this.name = 'QueryValidationError';
69
+ }
70
+ }
71
+ // =============================================================================
72
+ // KindlingService
73
+ // =============================================================================
74
+ /**
75
+ * Core Kindling service that wraps the store adapter with validation,
76
+ * sensitive-data checks, and config-driven behavior.
77
+ */
78
+ export class KindlingService {
79
+ store;
80
+ config;
81
+ closed = false;
82
+ constructor(store, config) {
83
+ this.store = store;
84
+ this.config = config;
85
+ debug('KindlingService created', { enabled: config.enabled });
86
+ }
87
+ /**
88
+ * Whether the service is enabled (will actually emit observations)
89
+ */
90
+ get enabled() {
91
+ return this.config.enabled;
92
+ }
93
+ /**
94
+ * The active configuration
95
+ */
96
+ get configuration() {
97
+ return this.config;
98
+ }
99
+ /**
100
+ * Emit an observation to the Kindling store.
101
+ *
102
+ * This method is designed to be async and non-blocking. It:
103
+ * 1. Checks if the service is enabled and the observation kind should be captured
104
+ * 2. Validates the observation against the contract schema
105
+ * 3. Checks for and redacts sensitive data
106
+ * 4. Delegates to the store adapter
107
+ *
108
+ * Validation errors are thrown. Store errors are thrown (callers should catch
109
+ * if they want fire-and-forget semantics -- see emitters).
110
+ *
111
+ * @param observation - The observation to emit
112
+ * @throws ObservationValidationError if the observation is invalid
113
+ */
114
+ async emit(observation) {
115
+ if (this.closed) {
116
+ debug('emit skipped: service is closed');
117
+ return;
118
+ }
119
+ // Check if this kind should be captured
120
+ if (!shouldCapture(this.config, observation.kind)) {
121
+ debug('emit skipped: kind not captured', observation.kind);
122
+ return;
123
+ }
124
+ // Validate against the contract schema
125
+ const validation = validateObservation(observation);
126
+ if (!validation.success) {
127
+ debug('emit validation failed', validation.error);
128
+ throw new ObservationValidationError(`Invalid observation: ${validation.error}`, [
129
+ validation.error ?? 'Unknown validation error',
130
+ ]);
131
+ }
132
+ // Check for sensitive data and redact if found
133
+ const sensitiveCheck = validateNoSensitiveData(observation);
134
+ let safeObservation = observation;
135
+ if (sensitiveCheck.hasSensitiveData) {
136
+ debug('sensitive data detected, redacting', sensitiveCheck.issues);
137
+ safeObservation = redactSensitiveFields(observation);
138
+ }
139
+ // Delegate to store (async, non-blocking from caller's perspective)
140
+ debug('emitting observation', { kind: observation.kind, session_id: observation.session_id });
141
+ await this.store.emit(safeObservation);
142
+ }
143
+ /**
144
+ * Execute a query against the Kindling store.
145
+ *
146
+ * Validates the query request against the contract schema and enforces
147
+ * configured query limits before delegating to the store.
148
+ *
149
+ * @param request - The query request
150
+ * @returns Query response with observations
151
+ * @throws QueryValidationError if the request is invalid
152
+ */
153
+ async query(request) {
154
+ if (this.closed) {
155
+ debug('query rejected: service is closed');
156
+ throw new QueryValidationError('Service is closed');
157
+ }
158
+ // Validate the request
159
+ const validation = QueryRequestSchema.safeParse(request);
160
+ if (!validation.success) {
161
+ debug('query validation failed', validation.error.format());
162
+ throw new QueryValidationError(`Invalid query request: ${validation.error.format()._errors.join(', ')}`);
163
+ }
164
+ debug('executing query', { scope: request.scope });
165
+ // Enforce configured query limits (use config defaults if request has higher values)
166
+ const limitedRequest = {
167
+ ...validation.data,
168
+ max_results: Math.min(validation.data.max_results, this.config.query_limits.max_results),
169
+ max_payload_bytes: Math.min(validation.data.max_payload_bytes, this.config.query_limits.max_payload_bytes),
170
+ };
171
+ return this.store.query(limitedRequest);
172
+ }
173
+ /**
174
+ * Close the service and release underlying store resources.
175
+ * After calling close(), emit() becomes a no-op and query() throws.
176
+ */
177
+ async close() {
178
+ if (this.closed) {
179
+ return;
180
+ }
181
+ debug('closing KindlingService');
182
+ this.closed = true;
183
+ await this.store.close();
184
+ }
185
+ }
186
+ // =============================================================================
187
+ // Factory
188
+ // =============================================================================
189
+ /**
190
+ * Create a KindlingService instance.
191
+ *
192
+ * If no store is provided, the service operates in disabled mode with a no-op store.
193
+ * This allows code to unconditionally call emit/query without checking for null.
194
+ *
195
+ * @param config - Kindling configuration (defaults to disabled config)
196
+ * @param store - Optional store adapter (defaults to NoOpKindlingStore)
197
+ * @returns Configured KindlingService instance
198
+ */
199
+ export function createKindlingService(config = DEFAULT_KINDLING_CONFIG, store) {
200
+ const effectiveStore = store ?? new NoOpKindlingStore();
201
+ debug('creating KindlingService', { enabled: config.enabled, hasStore: !!store });
202
+ return new KindlingService(effectiveStore, config);
203
+ }