@stackbilt/aegis-core 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/package.json +11 -3
  2. package/src/adapters/voice/cloudflare-agent.ts +0 -0
  3. package/src/bluesky.ts +0 -0
  4. package/src/claude-tools/content.ts +0 -0
  5. package/src/claude-tools/email.ts +0 -0
  6. package/src/codebeast.ts +0 -0
  7. package/src/content/column.ts +0 -0
  8. package/src/content/hero-image.ts +0 -0
  9. package/src/content/index.ts +0 -0
  10. package/src/content/journal.ts +0 -0
  11. package/src/content/roundtable.ts +0 -0
  12. package/src/contracts/agenda-item.contract.ts +113 -0
  13. package/src/contracts/cc-task.contract.ts +204 -0
  14. package/src/contracts/goal.contract.ts +147 -0
  15. package/src/contracts/memory-entry.contract.ts +177 -0
  16. package/src/core.ts +0 -0
  17. package/src/dashboard.ts +0 -0
  18. package/src/decision-docs.ts +0 -0
  19. package/src/dispatch.ts +0 -0
  20. package/src/edge-env.ts +0 -0
  21. package/src/exports.ts +0 -0
  22. package/src/github-projects.ts +0 -0
  23. package/src/kernel/argus-actions.ts +0 -0
  24. package/src/kernel/argus-correlation.ts +0 -0
  25. package/src/kernel/board.ts +0 -0
  26. package/src/kernel/classify-memory-topic.ts +0 -0
  27. package/src/kernel/dynamic-tools.ts +0 -0
  28. package/src/kernel/executor-port.ts +0 -0
  29. package/src/kernel/insight-cache.ts +0 -0
  30. package/src/kernel/memory/insights.ts +0 -0
  31. package/src/kernel/memory-guardrails.ts +0 -0
  32. package/src/kernel/port.ts +0 -0
  33. package/src/kernel/resilience.ts +0 -0
  34. package/src/kernel/scheduled/agent-dispatch.ts +0 -0
  35. package/src/kernel/scheduled/argus-analytics.ts +0 -0
  36. package/src/kernel/scheduled/argus-heartbeat.ts +0 -0
  37. package/src/kernel/scheduled/argus-notify.ts +0 -0
  38. package/src/kernel/scheduled/board-sync.ts +0 -0
  39. package/src/kernel/scheduled/ci-watcher.ts +0 -0
  40. package/src/kernel/scheduled/content-drip.ts +0 -0
  41. package/src/kernel/scheduled/content.ts +0 -0
  42. package/src/kernel/scheduled/conversation-facts.ts +0 -0
  43. package/src/kernel/scheduled/cost-report.ts +0 -0
  44. package/src/kernel/scheduled/dev-activity.ts +0 -0
  45. package/src/kernel/scheduled/digest.ts +0 -0
  46. package/src/kernel/scheduled/dreaming/agenda-triage.ts +0 -0
  47. package/src/kernel/scheduled/dreaming/facts.ts +0 -0
  48. package/src/kernel/scheduled/dreaming/index.ts +0 -0
  49. package/src/kernel/scheduled/dreaming/llm.ts +0 -0
  50. package/src/kernel/scheduled/dreaming/pattern-synthesis.ts +0 -0
  51. package/src/kernel/scheduled/dreaming/persona.ts +0 -0
  52. package/src/kernel/scheduled/dreaming/symbolic.ts +0 -0
  53. package/src/kernel/scheduled/dreaming/task-proposals.ts +0 -0
  54. package/src/kernel/scheduled/entropy.ts +0 -0
  55. package/src/kernel/scheduled/feed-watcher.ts +0 -0
  56. package/src/kernel/scheduled/inbox-processor.ts +0 -0
  57. package/src/kernel/scheduled/issue-proposer.ts +0 -0
  58. package/src/kernel/scheduled/issue-watcher.ts +0 -0
  59. package/src/kernel/scheduled/pr-automerge.ts +0 -0
  60. package/src/kernel/scheduled/product-health.ts +0 -0
  61. package/src/kernel/scheduled/self-improvement.ts +0 -0
  62. package/src/kernel/scheduled/social-engage.ts +0 -0
  63. package/src/kernel/scheduled/task-audit.ts +0 -0
  64. package/src/landing.ts +0 -0
  65. package/src/lib/audit-chain/chain.ts +0 -0
  66. package/src/lib/audit-chain/types.ts +0 -0
  67. package/src/lib/observability/errors.ts +0 -0
  68. package/src/operator/config.ts +0 -0
  69. package/src/operator/persona.ts +0 -0
  70. package/src/pulse.ts +0 -0
  71. package/src/routes/bluesky.ts +0 -0
  72. package/src/routes/codebeast.ts +0 -0
  73. package/src/routes/content.ts +0 -0
  74. package/src/routes/dynamic-tools.ts +0 -0
  75. package/src/routes/observability.ts +0 -0
  76. package/src/routes/operator-logs.ts +0 -0
  77. package/src/routes/pages.ts +0 -0
  78. package/src/schema-enums.ts +0 -0
  79. package/src/task-intelligence.ts +0 -0
  80. package/src/ui.ts +0 -0
  81. package/src/wiki/client.ts +346 -0
  82. package/src/wiki/types.ts +90 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackbilt/aegis-core",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Persistent AI agent framework for Cloudflare Workers. Multi-tier memory, autonomous goals, dreaming cycles, MCP native.",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -55,7 +55,13 @@
55
55
  "./routes/pages": "./src/routes/pages.ts",
56
56
  "./routes/dynamic-tools": "./src/routes/dynamic-tools.ts",
57
57
  "./adapters/voice": "./src/adapters/voice/cloudflare-agent.ts",
58
- "./schema-enums": "./src/schema-enums.ts"
58
+ "./schema-enums": "./src/schema-enums.ts",
59
+ "./contracts/goal": "./src/contracts/goal.contract.ts",
60
+ "./contracts/agenda-item": "./src/contracts/agenda-item.contract.ts",
61
+ "./contracts/cc-task": "./src/contracts/cc-task.contract.ts",
62
+ "./contracts/memory-entry": "./src/contracts/memory-entry.contract.ts",
63
+ "./wiki/client": "./src/wiki/client.ts",
64
+ "./wiki/types": "./src/wiki/types.ts"
59
65
  },
60
66
  "scripts": {
61
67
  "dev": "wrangler dev",
@@ -70,9 +76,11 @@
70
76
  "dependencies": {
71
77
  "@cloudflare/voice": "^0.1.3",
72
78
  "@cloudflare/workers-oauth-provider": "^0.2.4",
79
+ "@stackbilt/contracts": "^0.2.1",
73
80
  "@stackbilt/llm-providers": "^1.6.0",
74
81
  "agents": "^0.12.3",
75
- "hono": "^4.12.12"
82
+ "hono": "^4.12.12",
83
+ "zod": "^4.4.3"
76
84
  },
77
85
  "devDependencies": {
78
86
  "@cloudflare/workers-types": "^4.20241218.0",
File without changes
package/src/bluesky.ts CHANGED
File without changes
File without changes
File without changes
package/src/codebeast.ts CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,113 @@
1
+ import { z } from 'zod';
2
+ import { defineContract } from '@stackbilt/contracts';
3
+
4
+ const AgendaPriority = z.enum(['low', 'medium', 'high']);
5
+ const AgendaStatus = z.enum(['active', 'done', 'dismissed']);
6
+
7
+ export const AgendaItemContract = defineContract({
8
+ name: 'AgendaItem',
9
+ version: '1.0.0',
10
+ description: 'Operator agenda item — work scratchpad with priority and lifecycle tracking',
11
+
12
+ schema: z.object({
13
+ id: z.number().int().positive(),
14
+ item: z.string().min(1),
15
+ context: z.string().nullable(),
16
+ priority: AgendaPriority.default('medium'),
17
+ status: AgendaStatus.default('active'),
18
+ createdAt: z.string().datetime(),
19
+ resolvedAt: z.string().datetime().nullable(),
20
+ businessUnit: z.string().min(1).default('stackbilt'),
21
+ }),
22
+
23
+ operations: {
24
+ add: {
25
+ input: z.object({
26
+ item: z.string().min(1),
27
+ context: z.string().optional(),
28
+ priority: AgendaPriority.optional(),
29
+ businessUnit: z.string().min(1).optional(),
30
+ }),
31
+ output: 'self' as const,
32
+ emits: ['agenda_item.added'],
33
+ },
34
+
35
+ resolve: {
36
+ input: z.object({ id: z.number().int().positive() }),
37
+ output: 'self' as const,
38
+ transition: { from: 'active', to: 'done' },
39
+ emits: ['agenda_item.resolved'],
40
+ },
41
+
42
+ dismiss: {
43
+ input: z.object({ id: z.number().int().positive() }),
44
+ output: 'self' as const,
45
+ transition: { from: 'active', to: 'dismissed' },
46
+ emits: ['agenda_item.dismissed'],
47
+ },
48
+
49
+ escalate: {
50
+ input: z.object({ id: z.number().int().positive() }),
51
+ output: 'self' as const,
52
+ emits: ['agenda_item.escalated'],
53
+ },
54
+ },
55
+
56
+ states: {
57
+ field: 'status',
58
+ initial: 'active',
59
+ transitions: {
60
+ active: {
61
+ resolve: 'done',
62
+ dismiss: 'dismissed',
63
+ },
64
+ done: {},
65
+ dismissed: {},
66
+ },
67
+ },
68
+
69
+ surfaces: {
70
+ api: {
71
+ basePath: '/api/agenda',
72
+ routes: {
73
+ add: { method: 'POST', path: '/' },
74
+ resolve: { method: 'POST', path: '/:id/resolve' },
75
+ dismiss: { method: 'POST', path: '/:id/dismiss' },
76
+ escalate: { method: 'POST', path: '/:id/escalate' },
77
+ },
78
+ },
79
+ db: {
80
+ table: 'agent_agenda',
81
+ indexes: [
82
+ 'idx_agenda_status(status)',
83
+ 'idx_agenda_priority(priority)',
84
+ 'idx_agenda_bu(business_unit, status)',
85
+ ],
86
+ columnOverrides: {
87
+ createdAt: { default: "datetime('now')" },
88
+ },
89
+ },
90
+ },
91
+
92
+ authority: {
93
+ add: { requires: 'role', roles: ['operator', 'system'] },
94
+ resolve: { requires: 'role', roles: ['operator', 'system'] },
95
+ dismiss: { requires: 'role', roles: ['operator', 'system'] },
96
+ escalate: { requires: 'role', roles: ['system'] },
97
+ },
98
+
99
+ invariants: [
100
+ {
101
+ name: 'resolved_has_timestamp',
102
+ description: 'Done items must have a resolvedAt timestamp',
103
+ check: (entity: unknown) => {
104
+ const a = entity as { status?: string; resolvedAt?: string | null };
105
+ if (a.status === 'done' && !a.resolvedAt) {
106
+ return 'Done agenda item requires resolvedAt';
107
+ }
108
+ return true;
109
+ },
110
+ appliesTo: ['resolve'],
111
+ },
112
+ ],
113
+ });
@@ -0,0 +1,204 @@
1
+ import { z } from 'zod';
2
+ import { defineContract } from '@stackbilt/contracts';
3
+
4
+ const TaskStatus = z.enum(['pending', 'running', 'completed', 'failed', 'cancelled']);
5
+ const TaskAuthority = z.enum(['proposed', 'auto_safe', 'operator']);
6
+ const TaskCategory = z.enum(['docs', 'tests', 'research', 'bugfix', 'feature', 'refactor', 'deploy']);
7
+
8
+ export const CCTaskContract = defineContract({
9
+ name: 'CCTask',
10
+ version: '1.0.0',
11
+ description: 'Claude Code autonomous task — queued, governed, and executed by the task runner',
12
+
13
+ schema: z.object({
14
+ id: z.string().min(1),
15
+ title: z.string().min(1),
16
+ repo: z.string().min(1),
17
+ prompt: z.string().min(1),
18
+ completionSignal: z.string().nullable(),
19
+ status: TaskStatus.default('pending'),
20
+ priority: z.number().int().min(0).max(100).default(50),
21
+ dependsOn: z.string().nullable(),
22
+ blockedBy: z.string().nullable(),
23
+ maxTurns: z.number().int().positive().default(25),
24
+ allowedTools: z.string().nullable(),
25
+ sessionId: z.string().nullable(),
26
+ result: z.string().nullable(),
27
+ error: z.string().nullable(),
28
+ exitCode: z.number().int().nullable(),
29
+ preflightJson: z.string().nullable(),
30
+ failureKind: z.string().nullable(),
31
+ retryable: z.boolean().default(false),
32
+ autopsyJson: z.string().nullable(),
33
+ createdAt: z.string().datetime(),
34
+ startedAt: z.string().datetime().nullable(),
35
+ completedAt: z.string().datetime().nullable(),
36
+ createdBy: z.string().min(1).default('operator'),
37
+ authority: TaskAuthority.default('operator'),
38
+ category: TaskCategory.default('feature'),
39
+ branch: z.string().nullable(),
40
+ prUrl: z.string().nullable(),
41
+ utilityJson: z.string().nullable(),
42
+ githubIssueRepo: z.string().nullable(),
43
+ githubIssueNumber: z.number().int().positive().nullable(),
44
+ businessUnit: z.string().min(1).default('stackbilt'),
45
+ }),
46
+
47
+ operations: {
48
+ create: {
49
+ input: z.object({
50
+ id: z.string().min(1),
51
+ title: z.string().min(1),
52
+ repo: z.string().min(1),
53
+ prompt: z.string().min(1),
54
+ completionSignal: z.string().optional(),
55
+ priority: z.number().int().min(0).max(100).optional(),
56
+ dependsOn: z.string().optional(),
57
+ blockedBy: z.string().optional(),
58
+ maxTurns: z.number().int().positive().optional(),
59
+ allowedTools: z.string().optional(),
60
+ authority: TaskAuthority.optional(),
61
+ category: TaskCategory.optional(),
62
+ githubIssueRepo: z.string().optional(),
63
+ githubIssueNumber: z.number().int().positive().optional(),
64
+ businessUnit: z.string().min(1).optional(),
65
+ }),
66
+ output: 'self' as const,
67
+ emits: ['cc_task.created'],
68
+ },
69
+
70
+ start: {
71
+ input: z.object({
72
+ id: z.string().min(1),
73
+ sessionId: z.string().min(1),
74
+ }),
75
+ output: 'self' as const,
76
+ transition: { from: 'pending', to: 'running' },
77
+ emits: ['cc_task.started'],
78
+ },
79
+
80
+ complete: {
81
+ input: z.object({
82
+ id: z.string().min(1),
83
+ result: z.string().optional(),
84
+ exitCode: z.number().int().optional(),
85
+ prUrl: z.string().optional(),
86
+ utilityJson: z.string().optional(),
87
+ }),
88
+ output: 'self' as const,
89
+ transition: { from: 'running', to: 'completed' },
90
+ emits: ['cc_task.completed'],
91
+ },
92
+
93
+ fail: {
94
+ input: z.object({
95
+ id: z.string().min(1),
96
+ error: z.string().min(1),
97
+ exitCode: z.number().int().optional(),
98
+ failureKind: z.string().optional(),
99
+ retryable: z.boolean().optional(),
100
+ autopsyJson: z.string().optional(),
101
+ }),
102
+ output: 'self' as const,
103
+ transition: { from: 'running', to: 'failed' },
104
+ emits: ['cc_task.failed'],
105
+ },
106
+
107
+ cancel: {
108
+ input: z.object({ id: z.string().min(1) }),
109
+ output: 'self' as const,
110
+ transition: { from: ['pending', 'running'], to: 'cancelled' },
111
+ emits: ['cc_task.cancelled'],
112
+ },
113
+
114
+ approve: {
115
+ input: z.object({ id: z.string().min(1) }),
116
+ output: 'self' as const,
117
+ emits: ['cc_task.approved'],
118
+ },
119
+ },
120
+
121
+ states: {
122
+ field: 'status',
123
+ initial: 'pending',
124
+ transitions: {
125
+ pending: {
126
+ start: 'running',
127
+ cancel: 'cancelled',
128
+ },
129
+ running: {
130
+ complete: 'completed',
131
+ fail: 'failed',
132
+ cancel: 'cancelled',
133
+ },
134
+ completed: {},
135
+ failed: {},
136
+ cancelled: {},
137
+ },
138
+ },
139
+
140
+ surfaces: {
141
+ api: {
142
+ basePath: '/api/cc-tasks',
143
+ routes: {
144
+ create: { method: 'POST', path: '/' },
145
+ start: { method: 'POST', path: '/:id/start' },
146
+ complete: { method: 'POST', path: '/:id/complete' },
147
+ fail: { method: 'POST', path: '/:id/fail' },
148
+ cancel: { method: 'POST', path: '/:id/cancel' },
149
+ approve: { method: 'POST', path: '/:id/approve' },
150
+ },
151
+ },
152
+ db: {
153
+ table: 'cc_tasks',
154
+ indexes: [
155
+ 'idx_cc_tasks_status(status, priority)',
156
+ 'idx_cc_tasks_depends(depends_on)',
157
+ 'idx_cc_tasks_created(created_at)',
158
+ 'idx_cc_tasks_bu(business_unit, status)',
159
+ 'idx_cc_tasks_authority(authority)',
160
+ 'idx_cc_tasks_gh_issue(github_issue_repo, github_issue_number)',
161
+ 'idx_cc_tasks_failure_kind(failure_kind, completed_at)',
162
+ ],
163
+ columnOverrides: {
164
+ createdAt: { default: "datetime('now')" },
165
+ },
166
+ },
167
+ },
168
+
169
+ authority: {
170
+ create: { requires: 'role', roles: ['operator', 'system'] },
171
+ start: { requires: 'role', roles: ['system'] },
172
+ complete: { requires: 'role', roles: ['system'] },
173
+ fail: { requires: 'role', roles: ['system'] },
174
+ cancel: { requires: 'role', roles: ['operator', 'system'] },
175
+ approve: { requires: 'role', roles: ['operator'] },
176
+ },
177
+
178
+ invariants: [
179
+ {
180
+ name: 'proposed_task_needs_approval',
181
+ description: 'Proposed tasks must be approved before they can run',
182
+ check: (entity: unknown) => {
183
+ const t = entity as { authority?: string; status?: string };
184
+ if (t.authority === 'proposed' && t.status === 'running') {
185
+ return 'Proposed tasks require approval before execution';
186
+ }
187
+ return true;
188
+ },
189
+ appliesTo: ['start'],
190
+ },
191
+ {
192
+ name: 'completed_has_timestamp',
193
+ description: 'Completed or failed tasks must have a completedAt timestamp',
194
+ check: (entity: unknown) => {
195
+ const t = entity as { status?: string; completedAt?: string | null };
196
+ if ((t.status === 'completed' || t.status === 'failed') && !t.completedAt) {
197
+ return 'Terminal tasks require completedAt';
198
+ }
199
+ return true;
200
+ },
201
+ appliesTo: ['complete', 'fail'],
202
+ },
203
+ ],
204
+ });
@@ -0,0 +1,147 @@
1
+ import { z } from 'zod';
2
+ import { defineContract } from '@stackbilt/contracts';
3
+
4
+ const GoalStatus = z.enum(['active', 'paused', 'completed', 'failed']);
5
+ const AuthorityLevel = z.enum(['propose', 'auto_low', 'auto_high']);
6
+
7
+ export const GoalContract = defineContract({
8
+ name: 'Goal',
9
+ version: '1.0.0',
10
+ description: 'Autonomous agent goal with scheduled execution and authority-gated autonomy',
11
+
12
+ schema: z.object({
13
+ id: z.string().min(1),
14
+ title: z.string().min(1),
15
+ description: z.string().nullable(),
16
+ status: GoalStatus.default('active'),
17
+ authorityLevel: AuthorityLevel.default('propose'),
18
+ scheduleHours: z.number().int().positive().default(6),
19
+ createdAt: z.string().datetime(),
20
+ lastRunAt: z.string().datetime().nullable(),
21
+ nextRunAt: z.string().datetime().nullable(),
22
+ completedAt: z.string().datetime().nullable(),
23
+ runCount: z.number().int().nonnegative().default(0),
24
+ contextJson: z.string().nullable(),
25
+ businessUnit: z.string().min(1).default('stackbilt'),
26
+ }),
27
+
28
+ operations: {
29
+ create: {
30
+ input: z.object({
31
+ id: z.string().min(1),
32
+ title: z.string().min(1),
33
+ description: z.string().optional(),
34
+ authorityLevel: AuthorityLevel.optional(),
35
+ scheduleHours: z.number().int().positive().optional(),
36
+ contextJson: z.string().optional(),
37
+ businessUnit: z.string().min(1).optional(),
38
+ }),
39
+ output: 'self' as const,
40
+ emits: ['goal.created'],
41
+ },
42
+
43
+ pause: {
44
+ input: z.object({ id: z.string().min(1) }),
45
+ output: 'self' as const,
46
+ transition: { from: 'active', to: 'paused' },
47
+ emits: ['goal.paused'],
48
+ },
49
+
50
+ resume: {
51
+ input: z.object({ id: z.string().min(1) }),
52
+ output: 'self' as const,
53
+ transition: { from: 'paused', to: 'active' },
54
+ emits: ['goal.resumed'],
55
+ },
56
+
57
+ complete: {
58
+ input: z.object({ id: z.string().min(1) }),
59
+ output: 'self' as const,
60
+ transition: { from: ['active', 'paused'], to: 'completed' },
61
+ emits: ['goal.completed'],
62
+ },
63
+
64
+ fail: {
65
+ input: z.object({ id: z.string().min(1) }),
66
+ output: 'self' as const,
67
+ transition: { from: ['active', 'paused'], to: 'failed' },
68
+ emits: ['goal.failed'],
69
+ },
70
+
71
+ recordRun: {
72
+ input: z.object({
73
+ id: z.string().min(1),
74
+ nextRunAt: z.string().datetime().optional(),
75
+ }),
76
+ output: 'self' as const,
77
+ emits: ['goal.ran'],
78
+ },
79
+ },
80
+
81
+ states: {
82
+ field: 'status',
83
+ initial: 'active',
84
+ transitions: {
85
+ active: {
86
+ pause: 'paused',
87
+ complete: 'completed',
88
+ fail: 'failed',
89
+ },
90
+ paused: {
91
+ resume: 'active',
92
+ complete: 'completed',
93
+ fail: 'failed',
94
+ },
95
+ completed: {},
96
+ failed: {},
97
+ },
98
+ },
99
+
100
+ surfaces: {
101
+ api: {
102
+ basePath: '/api/goals',
103
+ routes: {
104
+ create: { method: 'POST', path: '/' },
105
+ pause: { method: 'POST', path: '/:id/pause' },
106
+ resume: { method: 'POST', path: '/:id/resume' },
107
+ complete: { method: 'POST', path: '/:id/complete' },
108
+ fail: { method: 'POST', path: '/:id/fail' },
109
+ },
110
+ },
111
+ db: {
112
+ table: 'agent_goals',
113
+ indexes: [
114
+ 'idx_goals_status(status)',
115
+ 'idx_goals_next_run(next_run_at)',
116
+ 'idx_goals_bu(business_unit, status)',
117
+ ],
118
+ columnOverrides: {
119
+ createdAt: { default: "datetime('now')" },
120
+ },
121
+ },
122
+ },
123
+
124
+ authority: {
125
+ create: { requires: 'role', roles: ['operator', 'system'] },
126
+ pause: { requires: 'role', roles: ['operator', 'system'] },
127
+ resume: { requires: 'role', roles: ['operator', 'system'] },
128
+ complete: { requires: 'role', roles: ['system'] },
129
+ fail: { requires: 'role', roles: ['system'] },
130
+ recordRun: { requires: 'role', roles: ['system'] },
131
+ },
132
+
133
+ invariants: [
134
+ {
135
+ name: 'completed_has_timestamp',
136
+ description: 'Completed goals must have a completedAt timestamp',
137
+ check: (entity: unknown) => {
138
+ const g = entity as { status?: string; completedAt?: string | null };
139
+ if (g.status === 'completed' && !g.completedAt) {
140
+ return 'Completed goal requires completedAt';
141
+ }
142
+ return true;
143
+ },
144
+ appliesTo: ['complete'],
145
+ },
146
+ ],
147
+ });