@renseiai/agentfactory-server 0.8.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 (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/dist/src/a2a-server.d.ts +88 -0
  4. package/dist/src/a2a-server.d.ts.map +1 -0
  5. package/dist/src/a2a-server.integration.test.d.ts +9 -0
  6. package/dist/src/a2a-server.integration.test.d.ts.map +1 -0
  7. package/dist/src/a2a-server.integration.test.js +397 -0
  8. package/dist/src/a2a-server.js +235 -0
  9. package/dist/src/a2a-server.test.d.ts +2 -0
  10. package/dist/src/a2a-server.test.d.ts.map +1 -0
  11. package/dist/src/a2a-server.test.js +311 -0
  12. package/dist/src/a2a-types.d.ts +125 -0
  13. package/dist/src/a2a-types.d.ts.map +1 -0
  14. package/dist/src/a2a-types.js +8 -0
  15. package/dist/src/agent-tracking.d.ts +201 -0
  16. package/dist/src/agent-tracking.d.ts.map +1 -0
  17. package/dist/src/agent-tracking.js +349 -0
  18. package/dist/src/env-validation.d.ts +65 -0
  19. package/dist/src/env-validation.d.ts.map +1 -0
  20. package/dist/src/env-validation.js +134 -0
  21. package/dist/src/governor-dedup.d.ts +15 -0
  22. package/dist/src/governor-dedup.d.ts.map +1 -0
  23. package/dist/src/governor-dedup.js +31 -0
  24. package/dist/src/governor-event-bus.d.ts +54 -0
  25. package/dist/src/governor-event-bus.d.ts.map +1 -0
  26. package/dist/src/governor-event-bus.js +152 -0
  27. package/dist/src/governor-storage.d.ts +28 -0
  28. package/dist/src/governor-storage.d.ts.map +1 -0
  29. package/dist/src/governor-storage.js +52 -0
  30. package/dist/src/index.d.ts +26 -0
  31. package/dist/src/index.d.ts.map +1 -0
  32. package/dist/src/index.js +50 -0
  33. package/dist/src/issue-lock.d.ts +129 -0
  34. package/dist/src/issue-lock.d.ts.map +1 -0
  35. package/dist/src/issue-lock.js +508 -0
  36. package/dist/src/logger.d.ts +76 -0
  37. package/dist/src/logger.d.ts.map +1 -0
  38. package/dist/src/logger.js +218 -0
  39. package/dist/src/orphan-cleanup.d.ts +64 -0
  40. package/dist/src/orphan-cleanup.d.ts.map +1 -0
  41. package/dist/src/orphan-cleanup.js +369 -0
  42. package/dist/src/pending-prompts.d.ts +67 -0
  43. package/dist/src/pending-prompts.d.ts.map +1 -0
  44. package/dist/src/pending-prompts.js +176 -0
  45. package/dist/src/processing-state-storage.d.ts +38 -0
  46. package/dist/src/processing-state-storage.d.ts.map +1 -0
  47. package/dist/src/processing-state-storage.js +61 -0
  48. package/dist/src/quota-tracker.d.ts +62 -0
  49. package/dist/src/quota-tracker.d.ts.map +1 -0
  50. package/dist/src/quota-tracker.js +155 -0
  51. package/dist/src/rate-limit.d.ts +111 -0
  52. package/dist/src/rate-limit.d.ts.map +1 -0
  53. package/dist/src/rate-limit.js +171 -0
  54. package/dist/src/redis-circuit-breaker.d.ts +67 -0
  55. package/dist/src/redis-circuit-breaker.d.ts.map +1 -0
  56. package/dist/src/redis-circuit-breaker.js +290 -0
  57. package/dist/src/redis-rate-limiter.d.ts +51 -0
  58. package/dist/src/redis-rate-limiter.d.ts.map +1 -0
  59. package/dist/src/redis-rate-limiter.js +168 -0
  60. package/dist/src/redis.d.ts +146 -0
  61. package/dist/src/redis.d.ts.map +1 -0
  62. package/dist/src/redis.js +343 -0
  63. package/dist/src/session-hash.d.ts +48 -0
  64. package/dist/src/session-hash.d.ts.map +1 -0
  65. package/dist/src/session-hash.js +80 -0
  66. package/dist/src/session-storage.d.ts +166 -0
  67. package/dist/src/session-storage.d.ts.map +1 -0
  68. package/dist/src/session-storage.js +397 -0
  69. package/dist/src/token-storage.d.ts +118 -0
  70. package/dist/src/token-storage.d.ts.map +1 -0
  71. package/dist/src/token-storage.js +263 -0
  72. package/dist/src/types.d.ts +11 -0
  73. package/dist/src/types.d.ts.map +1 -0
  74. package/dist/src/types.js +7 -0
  75. package/dist/src/webhook-idempotency.d.ts +44 -0
  76. package/dist/src/webhook-idempotency.d.ts.map +1 -0
  77. package/dist/src/webhook-idempotency.js +148 -0
  78. package/dist/src/work-queue.d.ts +120 -0
  79. package/dist/src/work-queue.d.ts.map +1 -0
  80. package/dist/src/work-queue.js +384 -0
  81. package/dist/src/worker-auth.d.ts +29 -0
  82. package/dist/src/worker-auth.d.ts.map +1 -0
  83. package/dist/src/worker-auth.js +49 -0
  84. package/dist/src/worker-storage.d.ts +108 -0
  85. package/dist/src/worker-storage.d.ts.map +1 -0
  86. package/dist/src/worker-storage.js +295 -0
  87. package/dist/src/workflow-state-integration.test.d.ts +2 -0
  88. package/dist/src/workflow-state-integration.test.d.ts.map +1 -0
  89. package/dist/src/workflow-state-integration.test.js +342 -0
  90. package/dist/src/workflow-state.test.d.ts +2 -0
  91. package/dist/src/workflow-state.test.d.ts.map +1 -0
  92. package/dist/src/workflow-state.test.js +113 -0
  93. package/package.json +72 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Environment Variable Validation
3
+ *
4
+ * Validates required environment variables on startup.
5
+ * Fails fast if critical security variables are missing in production.
6
+ */
7
+ import { createLogger } from './logger.js';
8
+ const log = createLogger('env-validation');
9
+ /**
10
+ * Default required environment variables for production
11
+ * These are critical for security and must be present
12
+ */
13
+ const DEFAULT_REQUIRED_VARS = [
14
+ 'LINEAR_WEBHOOK_SECRET',
15
+ 'CRON_SECRET',
16
+ 'WORKER_API_KEY',
17
+ 'SESSION_HASH_SALT',
18
+ ];
19
+ /**
20
+ * Default minimum length validations
21
+ */
22
+ const DEFAULT_MIN_LENGTH_VARS = [
23
+ { name: 'SESSION_HASH_SALT', minLength: 32 },
24
+ ];
25
+ /**
26
+ * Check if running in production environment
27
+ */
28
+ function isProduction() {
29
+ return (process.env.NODE_ENV === 'production' ||
30
+ process.env.VERCEL_ENV === 'production');
31
+ }
32
+ /**
33
+ * Validate environment variables
34
+ *
35
+ * In production: All required vars must be present
36
+ * In development: Log warnings for missing vars but don't fail
37
+ *
38
+ * @param config - Optional configuration to override defaults
39
+ * @returns Validation result with missing vars
40
+ */
41
+ export function validateEnv(config) {
42
+ const missing = [];
43
+ const warnings = [];
44
+ const requiredVars = config?.requiredVars ?? DEFAULT_REQUIRED_VARS;
45
+ const minLengthVars = config?.minLengthVars ?? DEFAULT_MIN_LENGTH_VARS;
46
+ for (const varName of requiredVars) {
47
+ if (!process.env[varName]) {
48
+ if (isProduction()) {
49
+ missing.push(varName);
50
+ }
51
+ else {
52
+ warnings.push(varName);
53
+ }
54
+ }
55
+ }
56
+ // Additional validation for minimum length variables
57
+ for (const { name, minLength } of minLengthVars) {
58
+ const value = process.env[name];
59
+ if (value && value.length < minLength) {
60
+ const msg = `${name} should be at least ${minLength} characters for security`;
61
+ if (isProduction()) {
62
+ missing.push(`${name} (too short)`);
63
+ }
64
+ else {
65
+ warnings.push(msg);
66
+ }
67
+ }
68
+ }
69
+ return {
70
+ valid: missing.length === 0,
71
+ missing,
72
+ warnings,
73
+ };
74
+ }
75
+ /**
76
+ * Validate and fail fast if critical vars are missing
77
+ *
78
+ * Call this at application startup to ensure required
79
+ * environment variables are configured.
80
+ *
81
+ * @param config - Optional configuration to override defaults
82
+ * @throws Error if required vars are missing in production
83
+ */
84
+ export function validateEnvOrThrow(config) {
85
+ const result = validateEnv(config);
86
+ // Log warnings for development
87
+ if (result.warnings.length > 0) {
88
+ log.warn('Missing environment variables (development mode)', {
89
+ variables: result.warnings,
90
+ hint: 'These are required in production',
91
+ });
92
+ }
93
+ // Fail in production if required vars are missing
94
+ if (!result.valid) {
95
+ const errorMsg = `Missing required environment variables: ${result.missing.join(', ')}`;
96
+ log.error(errorMsg, {
97
+ missing: result.missing,
98
+ environment: process.env.NODE_ENV,
99
+ });
100
+ throw new Error(errorMsg);
101
+ }
102
+ log.debug('Environment validation passed');
103
+ }
104
+ /**
105
+ * Check if webhook signature verification is configured
106
+ */
107
+ export function isWebhookSecretConfigured() {
108
+ return !!process.env.LINEAR_WEBHOOK_SECRET;
109
+ }
110
+ /**
111
+ * Check if cron authentication is configured
112
+ */
113
+ export function isCronSecretConfigured() {
114
+ return !!process.env.CRON_SECRET;
115
+ }
116
+ /**
117
+ * Check if session hashing is configured
118
+ */
119
+ export function isSessionHashConfigured() {
120
+ const salt = process.env.SESSION_HASH_SALT;
121
+ return !!salt && salt.length >= 32;
122
+ }
123
+ /**
124
+ * Get session hash salt
125
+ * @param saltEnvVar - Environment variable name for the salt (default: SESSION_HASH_SALT)
126
+ * @throws Error if not configured
127
+ */
128
+ export function getSessionHashSalt(saltEnvVar = 'SESSION_HASH_SALT') {
129
+ const salt = process.env[saltEnvVar];
130
+ if (!salt) {
131
+ throw new Error(`${saltEnvVar} not configured`);
132
+ }
133
+ return salt;
134
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Redis Event Deduplicator
3
+ *
4
+ * Production EventDeduplicator backed by Redis SETNX with TTL.
5
+ * Key pattern: `governor:dedup:{dedupKey}`
6
+ */
7
+ import type { EventDeduplicator, EventDeduplicatorConfig } from '@renseiai/agentfactory';
8
+ export declare class RedisEventDeduplicator implements EventDeduplicator {
9
+ private readonly windowMs;
10
+ private readonly keyPrefix;
11
+ constructor(config?: Partial<EventDeduplicatorConfig>, keyPrefix?: string);
12
+ isDuplicate(key: string): Promise<boolean>;
13
+ clear(): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=governor-dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governor-dedup.d.ts","sourceRoot":"","sources":["../../src/governor-dedup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAQxF,qBAAa,sBAAuB,YAAW,iBAAiB;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;gBAGhC,MAAM,GAAE,OAAO,CAAC,uBAAuB,CAAM,EAC7C,SAAS,SAAmB;IAMxB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Redis Event Deduplicator
3
+ *
4
+ * Production EventDeduplicator backed by Redis SETNX with TTL.
5
+ * Key pattern: `governor:dedup:{dedupKey}`
6
+ */
7
+ import { DEFAULT_DEDUP_CONFIG } from '@renseiai/agentfactory';
8
+ import { redisSetNX } from './redis.js';
9
+ // ---------------------------------------------------------------------------
10
+ // RedisEventDeduplicator
11
+ // ---------------------------------------------------------------------------
12
+ export class RedisEventDeduplicator {
13
+ windowMs;
14
+ keyPrefix;
15
+ constructor(config = {}, keyPrefix = 'governor:dedup') {
16
+ this.windowMs = config.windowMs ?? DEFAULT_DEDUP_CONFIG.windowMs;
17
+ this.keyPrefix = keyPrefix;
18
+ }
19
+ async isDuplicate(key) {
20
+ const redisKey = `${this.keyPrefix}:${key}`;
21
+ const ttlSeconds = Math.max(1, Math.ceil(this.windowMs / 1000));
22
+ // SETNX returns true if key was newly set (not a duplicate)
23
+ const wasSet = await redisSetNX(redisKey, '1', ttlSeconds);
24
+ return !wasSet; // if we couldn't set, it's a duplicate
25
+ }
26
+ async clear() {
27
+ // In production, keys auto-expire via TTL.
28
+ // Explicit clear is mainly for testing — not implemented for Redis
29
+ // since test suites should use InMemoryEventDeduplicator.
30
+ }
31
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Redis Event Bus
3
+ *
4
+ * Production GovernorEventBus backed by Redis Streams.
5
+ * Uses a consumer group for reliable delivery and horizontal scaling.
6
+ *
7
+ * Stream: `governor:events`
8
+ * Consumer group: `governor-group`
9
+ * MAXLEN: 10,000 (approximate trim)
10
+ */
11
+ import type { GovernorEvent, GovernorEventBus } from '@renseiai/agentfactory';
12
+ export interface RedisEventBusConfig {
13
+ /** Redis stream key (default: 'governor:events') */
14
+ streamKey?: string;
15
+ /** Consumer group name (default: 'governor-group') */
16
+ groupName?: string;
17
+ /** Consumer name within the group (default: hostname or random) */
18
+ consumerName?: string;
19
+ /** Max stream length — approximate trim (default: 10000) */
20
+ maxLen?: number;
21
+ /** Block timeout in milliseconds for XREADGROUP (default: 5000) */
22
+ blockMs?: number;
23
+ }
24
+ export declare class RedisEventBus implements GovernorEventBus {
25
+ private readonly streamKey;
26
+ private readonly groupName;
27
+ private readonly consumerName;
28
+ private readonly maxLen;
29
+ private readonly blockMs;
30
+ private closed;
31
+ private groupCreated;
32
+ constructor(config?: RedisEventBusConfig);
33
+ /**
34
+ * Ensure the consumer group exists. Idempotent — safe to call multiple times.
35
+ */
36
+ private ensureGroup;
37
+ publish(event: GovernorEvent): Promise<string>;
38
+ subscribe(): AsyncGenerator<{
39
+ id: string;
40
+ event: GovernorEvent;
41
+ }>;
42
+ ack(eventId: string): Promise<void>;
43
+ close(): Promise<void>;
44
+ /**
45
+ * Re-deliver pending messages (claimed but not acked from a previous run).
46
+ */
47
+ private readPending;
48
+ /**
49
+ * Parse a Redis stream message fields array into a GovernorEvent.
50
+ * Fields come as [key1, val1, key2, val2, ...].
51
+ */
52
+ private parseEvent;
53
+ }
54
+ //# sourceMappingURL=governor-event-bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governor-event-bus.d.ts","sourceRoot":"","sources":["../../src/governor-event-bus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAO7E,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAWD,qBAAa,aAAc,YAAW,gBAAgB;IACpD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,YAAY,CAAQ;gBAEhB,MAAM,GAAE,mBAAwB;IAQ5C;;OAEG;YACW,WAAW;IAenB,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IA0B7C,SAAS,IAAI,cAAc,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,CAAC;IAiDlE,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B;;OAEG;YACY,WAAW;IAiC1B;;;OAGG;IACH,OAAO,CAAC,UAAU;CAanB"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Redis Event Bus
3
+ *
4
+ * Production GovernorEventBus backed by Redis Streams.
5
+ * Uses a consumer group for reliable delivery and horizontal scaling.
6
+ *
7
+ * Stream: `governor:events`
8
+ * Consumer group: `governor-group`
9
+ * MAXLEN: 10,000 (approximate trim)
10
+ */
11
+ import { getRedisClient } from './redis.js';
12
+ const DEFAULT_STREAM_KEY = 'governor:events';
13
+ const DEFAULT_GROUP_NAME = 'governor-group';
14
+ const DEFAULT_MAX_LEN = 10_000;
15
+ const DEFAULT_BLOCK_MS = 5_000;
16
+ // ---------------------------------------------------------------------------
17
+ // RedisEventBus
18
+ // ---------------------------------------------------------------------------
19
+ export class RedisEventBus {
20
+ streamKey;
21
+ groupName;
22
+ consumerName;
23
+ maxLen;
24
+ blockMs;
25
+ closed = false;
26
+ groupCreated = false;
27
+ constructor(config = {}) {
28
+ this.streamKey = config.streamKey ?? DEFAULT_STREAM_KEY;
29
+ this.groupName = config.groupName ?? DEFAULT_GROUP_NAME;
30
+ this.consumerName = config.consumerName ?? `governor-${process.pid}-${Date.now()}`;
31
+ this.maxLen = config.maxLen ?? DEFAULT_MAX_LEN;
32
+ this.blockMs = config.blockMs ?? DEFAULT_BLOCK_MS;
33
+ }
34
+ /**
35
+ * Ensure the consumer group exists. Idempotent — safe to call multiple times.
36
+ */
37
+ async ensureGroup() {
38
+ if (this.groupCreated)
39
+ return;
40
+ const redis = getRedisClient();
41
+ try {
42
+ await redis.xgroup('CREATE', this.streamKey, this.groupName, '0', 'MKSTREAM');
43
+ }
44
+ catch (err) {
45
+ // BUSYGROUP = group already exists, which is fine
46
+ if (err instanceof Error && !err.message.includes('BUSYGROUP')) {
47
+ throw err;
48
+ }
49
+ }
50
+ this.groupCreated = true;
51
+ }
52
+ async publish(event) {
53
+ if (this.closed) {
54
+ throw new Error('Event bus is closed');
55
+ }
56
+ const redis = getRedisClient();
57
+ const payload = JSON.stringify(event);
58
+ // XADD with approximate MAXLEN trim
59
+ const id = await redis.xadd(this.streamKey, 'MAXLEN', '~', String(this.maxLen), '*', 'data', payload);
60
+ if (!id) {
61
+ throw new Error('XADD returned null — stream write failed');
62
+ }
63
+ return id;
64
+ }
65
+ async *subscribe() {
66
+ await this.ensureGroup();
67
+ const redis = getRedisClient();
68
+ // First, re-deliver any pending messages (from previous crash)
69
+ yield* this.readPending(redis);
70
+ // Then read new messages
71
+ while (!this.closed) {
72
+ try {
73
+ const results = await redis.xreadgroup('GROUP', this.groupName, this.consumerName, 'COUNT', '1', 'BLOCK', this.blockMs, 'STREAMS', this.streamKey, '>');
74
+ if (!results || results.length === 0) {
75
+ continue; // timeout, loop back
76
+ }
77
+ for (const [, messages] of results) {
78
+ for (const [id, fields] of messages) {
79
+ const event = this.parseEvent(fields);
80
+ if (event) {
81
+ yield { id, event };
82
+ }
83
+ else {
84
+ // Malformed event — ack and skip
85
+ await this.ack(id);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ catch (err) {
91
+ if (this.closed)
92
+ return;
93
+ // Log and continue on transient errors
94
+ console.error('[redis-event-bus] Error reading from stream:', err);
95
+ // Brief backoff before retry
96
+ await new Promise((r) => setTimeout(r, 1000));
97
+ }
98
+ }
99
+ }
100
+ async ack(eventId) {
101
+ const redis = getRedisClient();
102
+ await redis.xack(this.streamKey, this.groupName, eventId);
103
+ }
104
+ async close() {
105
+ this.closed = true;
106
+ }
107
+ // ---- Internal ----
108
+ /**
109
+ * Re-deliver pending messages (claimed but not acked from a previous run).
110
+ */
111
+ async *readPending(redis) {
112
+ try {
113
+ const results = await redis.xreadgroup('GROUP', this.groupName, this.consumerName, 'COUNT', '100', 'STREAMS', this.streamKey, '0');
114
+ if (!results || results.length === 0)
115
+ return;
116
+ for (const [, messages] of results) {
117
+ for (const [id, fields] of messages) {
118
+ if (!fields || fields.length === 0)
119
+ continue; // already acked
120
+ const event = this.parseEvent(fields);
121
+ if (event) {
122
+ yield { id, event };
123
+ }
124
+ else {
125
+ await this.ack(id);
126
+ }
127
+ }
128
+ }
129
+ }
130
+ catch (err) {
131
+ console.error('[redis-event-bus] Error reading pending messages:', err);
132
+ }
133
+ }
134
+ /**
135
+ * Parse a Redis stream message fields array into a GovernorEvent.
136
+ * Fields come as [key1, val1, key2, val2, ...].
137
+ */
138
+ parseEvent(fields) {
139
+ try {
140
+ // Find the 'data' field
141
+ for (let i = 0; i < fields.length; i += 2) {
142
+ if (fields[i] === 'data') {
143
+ return JSON.parse(fields[i + 1]);
144
+ }
145
+ }
146
+ return null;
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Governor Storage — Redis Implementation
3
+ *
4
+ * Redis-backed storage adapter for the human touchpoint override state.
5
+ * Implements the OverrideStorage interface from @renseiai/agentfactory (packages/core).
6
+ */
7
+ import type { OverrideStorage, OverrideState } from '@renseiai/agentfactory';
8
+ /**
9
+ * Redis-backed override storage for production use.
10
+ *
11
+ * Stores override state under `governor:override:{issueId}` keys
12
+ * with a 30-day TTL.
13
+ */
14
+ export declare class RedisOverrideStorage implements OverrideStorage {
15
+ /**
16
+ * Get the override state for an issue from Redis
17
+ */
18
+ get(issueId: string): Promise<OverrideState | null>;
19
+ /**
20
+ * Persist override state for an issue to Redis
21
+ */
22
+ set(issueId: string, state: OverrideState): Promise<void>;
23
+ /**
24
+ * Remove override state for an issue from Redis
25
+ */
26
+ clear(issueId: string): Promise<void>;
27
+ }
28
+ //# sourceMappingURL=governor-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governor-storage.d.ts","sourceRoot":"","sources":["../../src/governor-storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAgB5E;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC1D;;OAEG;IACG,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAWzD;;OAEG;IACG,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAM/D;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAK5C"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Governor Storage — Redis Implementation
3
+ *
4
+ * Redis-backed storage adapter for the human touchpoint override state.
5
+ * Implements the OverrideStorage interface from @renseiai/agentfactory (packages/core).
6
+ */
7
+ import { redisSet, redisGet, redisDel } from './redis.js';
8
+ const log = {
9
+ info: (msg, data) => console.log(`[governor-storage] ${msg}`, data ? JSON.stringify(data) : ''),
10
+ warn: (msg, data) => console.warn(`[governor-storage] ${msg}`, data ? JSON.stringify(data) : ''),
11
+ error: (msg, data) => console.error(`[governor-storage] ${msg}`, data ? JSON.stringify(data) : ''),
12
+ debug: (_msg, _data) => { },
13
+ };
14
+ /** Redis key prefix for governor override state */
15
+ const GOVERNOR_OVERRIDE_PREFIX = 'governor:override:';
16
+ /** TTL for override state: 30 days in seconds */
17
+ const GOVERNOR_OVERRIDE_TTL = 30 * 24 * 60 * 60;
18
+ /**
19
+ * Redis-backed override storage for production use.
20
+ *
21
+ * Stores override state under `governor:override:{issueId}` keys
22
+ * with a 30-day TTL.
23
+ */
24
+ export class RedisOverrideStorage {
25
+ /**
26
+ * Get the override state for an issue from Redis
27
+ */
28
+ async get(issueId) {
29
+ const key = `${GOVERNOR_OVERRIDE_PREFIX}${issueId}`;
30
+ const state = await redisGet(key);
31
+ if (state) {
32
+ log.debug('Retrieved override state', { issueId, type: state.directive.type });
33
+ }
34
+ return state;
35
+ }
36
+ /**
37
+ * Persist override state for an issue to Redis
38
+ */
39
+ async set(issueId, state) {
40
+ const key = `${GOVERNOR_OVERRIDE_PREFIX}${issueId}`;
41
+ await redisSet(key, state, GOVERNOR_OVERRIDE_TTL);
42
+ log.info('Stored override state', { issueId, type: state.directive.type });
43
+ }
44
+ /**
45
+ * Remove override state for an issue from Redis
46
+ */
47
+ async clear(issueId) {
48
+ const key = `${GOVERNOR_OVERRIDE_PREFIX}${issueId}`;
49
+ await redisDel(key);
50
+ log.info('Cleared override state', { issueId });
51
+ }
52
+ }
@@ -0,0 +1,26 @@
1
+ export * from './logger.js';
2
+ export * from './types.js';
3
+ export * from './redis.js';
4
+ export * from './session-storage.js';
5
+ export * from './work-queue.js';
6
+ export * from './worker-storage.js';
7
+ export * from './issue-lock.js';
8
+ export * from './agent-tracking.js';
9
+ export * from './webhook-idempotency.js';
10
+ export * from './pending-prompts.js';
11
+ export * from './orphan-cleanup.js';
12
+ export * from './worker-auth.js';
13
+ export * from './session-hash.js';
14
+ export * from './rate-limit.js';
15
+ export * from './token-storage.js';
16
+ export * from './env-validation.js';
17
+ export * from './governor-storage.js';
18
+ export * from './processing-state-storage.js';
19
+ export * from './governor-event-bus.js';
20
+ export * from './governor-dedup.js';
21
+ export * from './redis-rate-limiter.js';
22
+ export * from './redis-circuit-breaker.js';
23
+ export * from './quota-tracker.js';
24
+ export * from './a2a-types.js';
25
+ export * from './a2a-server.js';
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAG3B,cAAc,YAAY,CAAA;AAG1B,cAAc,YAAY,CAAA;AAG1B,cAAc,sBAAsB,CAAA;AAGpC,cAAc,iBAAiB,CAAA;AAG/B,cAAc,qBAAqB,CAAA;AAGnC,cAAc,iBAAiB,CAAA;AAG/B,cAAc,qBAAqB,CAAA;AAGnC,cAAc,0BAA0B,CAAA;AAGxC,cAAc,sBAAsB,CAAA;AAGpC,cAAc,qBAAqB,CAAA;AAGnC,cAAc,kBAAkB,CAAA;AAGhC,cAAc,mBAAmB,CAAA;AAGjC,cAAc,iBAAiB,CAAA;AAG/B,cAAc,oBAAoB,CAAA;AAGlC,cAAc,qBAAqB,CAAA;AAGnC,cAAc,uBAAuB,CAAA;AAGrC,cAAc,+BAA+B,CAAA;AAG7C,cAAc,yBAAyB,CAAA;AAGvC,cAAc,qBAAqB,CAAA;AAGnC,cAAc,yBAAyB,CAAA;AAGvC,cAAc,4BAA4B,CAAA;AAG1C,cAAc,oBAAoB,CAAA;AAGlC,cAAc,gBAAgB,CAAA;AAG9B,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,50 @@
1
+ // Logger
2
+ export * from './logger.js';
3
+ // Types
4
+ export * from './types.js';
5
+ // Redis client
6
+ export * from './redis.js';
7
+ // Session management
8
+ export * from './session-storage.js';
9
+ // Work queue
10
+ export * from './work-queue.js';
11
+ // Worker pool
12
+ export * from './worker-storage.js';
13
+ // Issue locking
14
+ export * from './issue-lock.js';
15
+ // Agent tracking
16
+ export * from './agent-tracking.js';
17
+ // Webhook idempotency
18
+ export * from './webhook-idempotency.js';
19
+ // Pending prompts
20
+ export * from './pending-prompts.js';
21
+ // Orphan cleanup
22
+ export * from './orphan-cleanup.js';
23
+ // Worker authentication
24
+ export * from './worker-auth.js';
25
+ // Session hashing
26
+ export * from './session-hash.js';
27
+ // Rate limiting
28
+ export * from './rate-limit.js';
29
+ // Token storage
30
+ export * from './token-storage.js';
31
+ // Environment validation
32
+ export * from './env-validation.js';
33
+ // Governor storage (Redis-backed override state)
34
+ export * from './governor-storage.js';
35
+ // Processing state storage (Redis-backed top-of-funnel phase tracking)
36
+ export * from './processing-state-storage.js';
37
+ // Governor event bus (Redis Streams)
38
+ export * from './governor-event-bus.js';
39
+ // Governor event deduplicator (Redis SETNX)
40
+ export * from './governor-dedup.js';
41
+ // Redis-backed Linear API rate limiter (shared across processes)
42
+ export * from './redis-rate-limiter.js';
43
+ // Redis-backed circuit breaker (shared across processes)
44
+ export * from './redis-circuit-breaker.js';
45
+ // Linear API quota tracker (reads rate limit headers)
46
+ export * from './quota-tracker.js';
47
+ // A2A Protocol types
48
+ export * from './a2a-types.js';
49
+ // A2A Server (AgentCard + JSON-RPC handlers)
50
+ export * from './a2a-server.js';