crewly 1.5.10 → 1.5.12

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 (177) hide show
  1. package/config/constants.ts +3 -3
  2. package/config/orchestrator_tasks/prompts/orchestrator-prompt.md +73 -0
  3. package/config/roles/architect/prompt.md +9 -0
  4. package/config/roles/backend-developer/prompt.md +9 -0
  5. package/config/roles/content-strategist/prompt.md +10 -0
  6. package/config/roles/designer/prompt.md +9 -0
  7. package/config/roles/developer/prompt.md +9 -0
  8. package/config/roles/frontend-developer/prompt.md +9 -0
  9. package/config/roles/fullstack-dev/prompt.md +9 -0
  10. package/config/roles/generalist/prompt.md +9 -0
  11. package/config/roles/ops/prompt.md +9 -0
  12. package/config/roles/product-manager/prompt.md +9 -0
  13. package/config/roles/qa/prompt.md +9 -0
  14. package/config/roles/qa-engineer/prompt.md +9 -0
  15. package/config/roles/researcher/prompt.md +9 -0
  16. package/config/roles/sales/prompt.md +9 -0
  17. package/config/roles/support/prompt.md +9 -0
  18. package/config/roles/team-leader/prompt.md +11 -0
  19. package/config/roles/tpm/prompt.md +9 -0
  20. package/config/roles/ux-designer/prompt.md +9 -0
  21. package/config/skills/agent/core/block-task/execute.sh +3 -1
  22. package/config/skills/agent/core/pipe-to-sink/execute.sh +41 -0
  23. package/config/skills/agent/core/read-task/execute.sh +3 -1
  24. package/config/skills/agent/core/report-progress/execute.sh +3 -1
  25. package/config/skills/agent/screenshot-compare/SKILL.md +75 -0
  26. package/config/skills/agent/screenshot-compare/execute.sh +182 -0
  27. package/config/skills/agent/screenshot-compare/skill.json +10 -0
  28. package/config/skills/agent/xiaoyuzhoufm-transcript/SKILL.md +85 -0
  29. package/config/skills/agent/xiaoyuzhoufm-transcript/execute.sh +306 -0
  30. package/config/skills/agent/xiaoyuzhoufm-transcript/skill.json +10 -0
  31. package/config/skills/orchestrator/cancel-cron/SKILL.md +44 -0
  32. package/config/skills/orchestrator/create-cron/SKILL.md +58 -0
  33. package/config/skills/orchestrator/list-cron/SKILL.md +51 -0
  34. package/config/skills/orchestrator/update-cron/SKILL.md +52 -0
  35. package/config/skills/orchestrator/update-team-member/SKILL.md +36 -0
  36. package/config/skills/orchestrator/update-team-member/execute.sh +25 -0
  37. package/dist/backend/backend/src/constants.d.ts +7 -4
  38. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  39. package/dist/backend/backend/src/constants.js +6 -3
  40. package/dist/backend/backend/src/constants.js.map +1 -1
  41. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts +21 -2
  42. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
  43. package/dist/backend/backend/src/controllers/browser/browser.controller.js +167 -29
  44. package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
  45. package/dist/backend/backend/src/controllers/browser/browser.routes.d.ts +1 -1
  46. package/dist/backend/backend/src/controllers/browser/browser.routes.d.ts.map +1 -1
  47. package/dist/backend/backend/src/controllers/browser/browser.routes.js +7 -3
  48. package/dist/backend/backend/src/controllers/browser/browser.routes.js.map +1 -1
  49. package/dist/backend/backend/src/controllers/data/data.controller.d.ts +47 -0
  50. package/dist/backend/backend/src/controllers/data/data.controller.d.ts.map +1 -0
  51. package/dist/backend/backend/src/controllers/data/data.controller.js +201 -0
  52. package/dist/backend/backend/src/controllers/data/data.controller.js.map +1 -0
  53. package/dist/backend/backend/src/controllers/data/data.routes.d.ts +18 -0
  54. package/dist/backend/backend/src/controllers/data/data.routes.d.ts.map +1 -0
  55. package/dist/backend/backend/src/controllers/data/data.routes.js +44 -0
  56. package/dist/backend/backend/src/controllers/data/data.routes.js.map +1 -0
  57. package/dist/backend/backend/src/controllers/monitoring/token-usage.controller.d.ts +3 -2
  58. package/dist/backend/backend/src/controllers/monitoring/token-usage.controller.d.ts.map +1 -1
  59. package/dist/backend/backend/src/controllers/monitoring/token-usage.controller.js +5 -3
  60. package/dist/backend/backend/src/controllers/monitoring/token-usage.controller.js.map +1 -1
  61. package/dist/backend/backend/src/controllers/system/cron-task.controller.d.ts +4 -0
  62. package/dist/backend/backend/src/controllers/system/cron-task.controller.d.ts.map +1 -1
  63. package/dist/backend/backend/src/controllers/system/cron-task.controller.js +20 -0
  64. package/dist/backend/backend/src/controllers/system/cron-task.controller.js.map +1 -1
  65. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
  66. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +18 -0
  67. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
  68. package/dist/backend/backend/src/controllers/team/team-export.controller.d.ts +32 -0
  69. package/dist/backend/backend/src/controllers/team/team-export.controller.d.ts.map +1 -0
  70. package/dist/backend/backend/src/controllers/team/team-export.controller.js +61 -0
  71. package/dist/backend/backend/src/controllers/team/team-export.controller.js.map +1 -0
  72. package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
  73. package/dist/backend/backend/src/controllers/team/team.controller.js +66 -46
  74. package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
  75. package/dist/backend/backend/src/controllers/team/team.routes.d.ts.map +1 -1
  76. package/dist/backend/backend/src/controllers/team/team.routes.js +7 -0
  77. package/dist/backend/backend/src/controllers/team/team.routes.js.map +1 -1
  78. package/dist/backend/backend/src/index.d.ts.map +1 -1
  79. package/dist/backend/backend/src/index.js +37 -7
  80. package/dist/backend/backend/src/index.js.map +1 -1
  81. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  82. package/dist/backend/backend/src/routes/api.routes.js +4 -1
  83. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  84. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  85. package/dist/backend/backend/src/services/agent/agent-registration.service.js +6 -2
  86. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  87. package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts.map +1 -1
  88. package/dist/backend/backend/src/services/agent/idle-detection.service.js +17 -2
  89. package/dist/backend/backend/src/services/agent/idle-detection.service.js.map +1 -1
  90. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +1 -1
  91. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +2 -2
  92. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  93. package/dist/backend/backend/src/services/agent/task-planning.service.d.ts +134 -0
  94. package/dist/backend/backend/src/services/agent/task-planning.service.d.ts.map +1 -0
  95. package/dist/backend/backend/src/services/agent/task-planning.service.js +291 -0
  96. package/dist/backend/backend/src/services/agent/task-planning.service.js.map +1 -0
  97. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.d.ts.map +1 -1
  98. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js +8 -0
  99. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -1
  100. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  101. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +3 -3
  102. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  103. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts +13 -9
  104. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts.map +1 -1
  105. package/dist/backend/backend/src/services/browser/browser-bridge.service.js +44 -12
  106. package/dist/backend/backend/src/services/browser/browser-bridge.service.js.map +1 -1
  107. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts +176 -0
  108. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts.map +1 -0
  109. package/dist/backend/backend/src/services/browser/browser-proxy.service.js +441 -0
  110. package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -0
  111. package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.d.ts +162 -0
  112. package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.d.ts.map +1 -0
  113. package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.js +350 -0
  114. package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.js.map +1 -0
  115. package/dist/backend/backend/src/services/cloud/cloud-initializer.d.ts +8 -0
  116. package/dist/backend/backend/src/services/cloud/cloud-initializer.d.ts.map +1 -1
  117. package/dist/backend/backend/src/services/cloud/cloud-initializer.js +27 -0
  118. package/dist/backend/backend/src/services/cloud/cloud-initializer.js.map +1 -1
  119. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
  120. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
  121. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +2 -0
  122. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
  123. package/dist/backend/backend/src/services/core/team-export.service.d.ts +103 -0
  124. package/dist/backend/backend/src/services/core/team-export.service.d.ts.map +1 -0
  125. package/dist/backend/backend/src/services/core/team-export.service.js +182 -0
  126. package/dist/backend/backend/src/services/core/team-export.service.js.map +1 -0
  127. package/dist/backend/backend/src/services/data/data-object-store.service.d.ts +160 -0
  128. package/dist/backend/backend/src/services/data/data-object-store.service.d.ts.map +1 -0
  129. package/dist/backend/backend/src/services/data/data-object-store.service.js +434 -0
  130. package/dist/backend/backend/src/services/data/data-object-store.service.js.map +1 -0
  131. package/dist/backend/backend/src/services/data/data-object.types.d.ts +190 -0
  132. package/dist/backend/backend/src/services/data/data-object.types.d.ts.map +1 -0
  133. package/dist/backend/backend/src/services/data/data-object.types.js +143 -0
  134. package/dist/backend/backend/src/services/data/data-object.types.js.map +1 -0
  135. package/dist/backend/backend/src/services/data/schema-registry.service.d.ts +108 -0
  136. package/dist/backend/backend/src/services/data/schema-registry.service.d.ts.map +1 -0
  137. package/dist/backend/backend/src/services/data/schema-registry.service.js +290 -0
  138. package/dist/backend/backend/src/services/data/schema-registry.service.js.map +1 -0
  139. package/dist/backend/backend/src/services/data/sink-registry.service.d.ts +87 -0
  140. package/dist/backend/backend/src/services/data/sink-registry.service.d.ts.map +1 -0
  141. package/dist/backend/backend/src/services/data/sink-registry.service.js +188 -0
  142. package/dist/backend/backend/src/services/data/sink-registry.service.js.map +1 -0
  143. package/dist/backend/backend/src/services/messaging/message-router.service.d.ts.map +1 -1
  144. package/dist/backend/backend/src/services/messaging/message-router.service.js +7 -0
  145. package/dist/backend/backend/src/services/messaging/message-router.service.js.map +1 -1
  146. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts +55 -2
  147. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  148. package/dist/backend/backend/src/services/monitoring/token-usage.service.js +89 -5
  149. package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  150. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +1 -1
  151. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
  152. package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts +105 -14
  153. package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
  154. package/dist/backend/backend/src/services/workflow/cron-task.service.js +400 -123
  155. package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
  156. package/dist/backend/backend/src/types/cron-task.types.d.ts +1 -1
  157. package/dist/backend/backend/src/types/data-object.types.d.ts +117 -0
  158. package/dist/backend/backend/src/types/data-object.types.d.ts.map +1 -0
  159. package/dist/backend/backend/src/types/data-object.types.js +23 -0
  160. package/dist/backend/backend/src/types/data-object.types.js.map +1 -0
  161. package/dist/backend/backend/src/types/settings.types.js +1 -1
  162. package/dist/backend/config/constants.d.ts +3 -3
  163. package/dist/backend/config/constants.js +3 -3
  164. package/dist/backend/config/constants.js.map +1 -1
  165. package/dist/cli/backend/src/constants.d.ts +7 -4
  166. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  167. package/dist/cli/backend/src/constants.js +6 -3
  168. package/dist/cli/backend/src/constants.js.map +1 -1
  169. package/dist/cli/backend/src/types/settings.types.js +1 -1
  170. package/dist/cli/config/constants.d.ts +3 -3
  171. package/dist/cli/config/constants.js +3 -3
  172. package/dist/cli/config/constants.js.map +1 -1
  173. package/frontend/dist/assets/index-371b68d4.css +33 -0
  174. package/frontend/dist/assets/{index-76782e9e.js → index-506f70da.js} +321 -321
  175. package/frontend/dist/index.html +2 -2
  176. package/package.json +1 -1
  177. package/frontend/dist/assets/index-b19b2478.css +0 -33
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Data Architecture V2.2 — Unified DataObject Model (UDM)
3
+ *
4
+ * Defines the core types for the structured data fabric:
5
+ * DataObject, SchemaDefinition, SinkDefinition, and related types.
6
+ *
7
+ * @see specs/crewly-data-architecture-v2.md
8
+ */
9
+ // ---------------------------------------------------------------------------
10
+ // Type Guards
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * Runtime check that a value is a valid DataObject.
14
+ *
15
+ * Validates the presence and types of all required top-level fields
16
+ * and the nested metadata structure.
17
+ *
18
+ * @param value - The value to check
19
+ * @returns true if value satisfies the DataObject interface
20
+ */
21
+ export function isDataObject(value) {
22
+ if (typeof value !== 'object' || value === null)
23
+ return false;
24
+ const obj = value;
25
+ // Top-level required strings
26
+ if (typeof obj.id !== 'string')
27
+ return false;
28
+ if (!isDataObjectType(obj.type))
29
+ return false;
30
+ if (!isDataObjectScope(obj.scope))
31
+ return false;
32
+ if (typeof obj.schema_id !== 'string')
33
+ return false;
34
+ if (!isDataObjectStatus(obj.status))
35
+ return false;
36
+ if (typeof obj.owner_id !== 'string')
37
+ return false;
38
+ if (typeof obj.namespace !== 'string')
39
+ return false;
40
+ if (!isSyncState(obj.sync_state))
41
+ return false;
42
+ // payload
43
+ if (typeof obj.payload !== 'object' || obj.payload === null)
44
+ return false;
45
+ // metadata
46
+ if (typeof obj.metadata !== 'object' || obj.metadata === null)
47
+ return false;
48
+ const meta = obj.metadata;
49
+ if (typeof meta.created_at !== 'string')
50
+ return false;
51
+ if (typeof meta.updated_at !== 'string')
52
+ return false;
53
+ if (!Array.isArray(meta.tags))
54
+ return false;
55
+ return true;
56
+ }
57
+ /**
58
+ * Runtime check that a value is a valid SchemaDefinition.
59
+ *
60
+ * @param value - The value to check
61
+ * @returns true if value satisfies the SchemaDefinition interface
62
+ */
63
+ export function isSchemaDefinition(value) {
64
+ if (typeof value !== 'object' || value === null)
65
+ return false;
66
+ const obj = value;
67
+ if (typeof obj.id !== 'string')
68
+ return false;
69
+ if (typeof obj.name !== 'string')
70
+ return false;
71
+ if (typeof obj.version !== 'string')
72
+ return false;
73
+ if (typeof obj.fields !== 'object' || obj.fields === null)
74
+ return false;
75
+ if (typeof obj.write_policy !== 'object' || obj.write_policy === null)
76
+ return false;
77
+ const wp = obj.write_policy;
78
+ if (typeof wp.allow_unstructured !== 'boolean')
79
+ return false;
80
+ if (!isValidationLevel(wp.validation_level))
81
+ return false;
82
+ return true;
83
+ }
84
+ /**
85
+ * Runtime check that a value is a valid SinkDefinition.
86
+ *
87
+ * @param value - The value to check
88
+ * @returns true if value satisfies the SinkDefinition interface
89
+ */
90
+ export function isSinkDefinition(value) {
91
+ if (typeof value !== 'object' || value === null)
92
+ return false;
93
+ const obj = value;
94
+ if (typeof obj.id !== 'string')
95
+ return false;
96
+ if (typeof obj.name !== 'string')
97
+ return false;
98
+ if (!isSinkType(obj.type))
99
+ return false;
100
+ if (typeof obj.path !== 'string')
101
+ return false;
102
+ if (!isSinkFormat(obj.format))
103
+ return false;
104
+ if (typeof obj.responsible_agent !== 'string')
105
+ return false;
106
+ if (!Array.isArray(obj.notify))
107
+ return false;
108
+ if (typeof obj.description !== 'string')
109
+ return false;
110
+ return true;
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // Internal helpers — narrow literal unions
114
+ // ---------------------------------------------------------------------------
115
+ /** @internal */
116
+ function isDataObjectType(v) {
117
+ return v === 'memory' || v === 'knowledge' || v === 'sink_entry';
118
+ }
119
+ /** @internal */
120
+ function isDataObjectScope(v) {
121
+ return v === 'agent' || v === 'project' || v === 'global';
122
+ }
123
+ /** @internal */
124
+ function isDataObjectStatus(v) {
125
+ return v === 'new' || v === 'processed' || v === 'archived';
126
+ }
127
+ /** @internal */
128
+ function isSyncState(v) {
129
+ return v === 'local' || v === 'synced' || v === 'conflict';
130
+ }
131
+ /** @internal */
132
+ function isValidationLevel(v) {
133
+ return v === 'strict' || v === 'loose' || v === 'none';
134
+ }
135
+ /** @internal */
136
+ function isSinkType(v) {
137
+ return v === 'collection' || v === 'log';
138
+ }
139
+ /** @internal */
140
+ function isSinkFormat(v) {
141
+ return v === 'markdown' || v === 'json' || v === 'jsonl';
142
+ }
143
+ //# sourceMappingURL=data-object.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-object.types.js","sourceRoot":"","sources":["../../../../../../backend/src/services/data/data-object.types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Schema Registry Service
3
+ *
4
+ * Loads schema definitions from project sink directories and validates
5
+ * data payloads against those schemas. Central to the Data Architecture V2
6
+ * governance layer — ensures every piece of data entering a sink conforms
7
+ * to its declared structure.
8
+ *
9
+ * @module services/data/schema-registry.service
10
+ */
11
+ import type { SchemaDefinition, ValidationResult } from '../../types/data-object.types.js';
12
+ /**
13
+ * Singleton service that manages schema definitions and validates payloads.
14
+ *
15
+ * Schemas are loaded from `{projectPath}/sinks/{sinkDir}/_schema.json` for
16
+ * each registered sink, or from a consolidated registry file. The validate()
17
+ * method applies all declared field rules and returns a structured result.
18
+ */
19
+ export declare class SchemaRegistryService {
20
+ private static instance;
21
+ private readonly logger;
22
+ private readonly schemas;
23
+ private constructor();
24
+ /**
25
+ * Get the singleton instance.
26
+ *
27
+ * @returns SchemaRegistryService singleton
28
+ */
29
+ static getInstance(): SchemaRegistryService;
30
+ /**
31
+ * Reset the singleton (for testing).
32
+ */
33
+ static resetInstance(): void;
34
+ /**
35
+ * Load schemas from a project's sinks directory.
36
+ *
37
+ * Scans `{projectPath}/sinks/` for sub-directories containing a
38
+ * `_schema.json` file and registers each valid schema.
39
+ *
40
+ * @param projectPath - Absolute path to the Crewly project root
41
+ */
42
+ loadSchemas(projectPath: string): Promise<void>;
43
+ /**
44
+ * Register a schema definition directly (e.g. from tests or programmatic setup).
45
+ *
46
+ * @param schema - The schema to register
47
+ */
48
+ registerSchema(schema: SchemaDefinition): void;
49
+ /**
50
+ * Get a schema by its ID.
51
+ *
52
+ * @param schemaId - Unique schema identifier
53
+ * @returns The schema, or null if not found
54
+ */
55
+ getSchema(schemaId: string): SchemaDefinition | null;
56
+ /**
57
+ * List all loaded schemas.
58
+ *
59
+ * @returns Array of all registered SchemaDefinitions
60
+ */
61
+ listSchemas(): SchemaDefinition[];
62
+ /**
63
+ * Validate a payload against a registered schema.
64
+ *
65
+ * Applies the following rules per field:
66
+ * - **required**: field must exist and not be null/undefined
67
+ * - **type**: JS typeof must match (with special handling for array, datetime, enum)
68
+ * - **max_length**: string length must not exceed limit
69
+ * - **enum options**: value must be one of the declared options
70
+ * - **array min_items**: array length must meet minimum
71
+ * - **datetime**: value must match ISO 8601 format
72
+ *
73
+ * @param schemaId - ID of the schema to validate against
74
+ * @param payload - Key-value data to validate
75
+ * @returns Structured validation result with any errors
76
+ */
77
+ validate(schemaId: string, payload: Record<string, unknown>): ValidationResult;
78
+ /**
79
+ * Validate a single field against its definition, pushing errors into the array.
80
+ *
81
+ * @param fieldName - Name of the field being validated
82
+ * @param fieldDef - Schema field definition
83
+ * @param value - Actual value from the payload
84
+ * @param errors - Mutable array to collect validation errors
85
+ */
86
+ private validateField;
87
+ /**
88
+ * Validate a string field (typeof + max_length).
89
+ */
90
+ private validateString;
91
+ /**
92
+ * Validate a primitive type via typeof.
93
+ */
94
+ private validateType;
95
+ /**
96
+ * Validate an array field (isArray + min_items).
97
+ */
98
+ private validateArray;
99
+ /**
100
+ * Validate a datetime field (must be a string matching ISO 8601).
101
+ */
102
+ private validateDatetime;
103
+ /**
104
+ * Validate an enum field (value must be one of options).
105
+ */
106
+ private validateEnum;
107
+ }
108
+ //# sourceMappingURL=schema-registry.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-registry.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/data/schema-registry.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EACV,gBAAgB,EAEhB,gBAAgB,EAEjB,MAAM,kCAAkC,CAAC;AAM1C;;;;;;GAMG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAsC;IAC7D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4C;IAEpE,OAAO;IAIP;;;;OAIG;IACH,MAAM,CAAC,WAAW,IAAI,qBAAqB;IAO3C;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI;IAQ5B;;;;;;;OAOG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCrD;;;;OAIG;IACH,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAQ9C;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAIpD;;;;OAIG;IACH,WAAW,IAAI,gBAAgB,EAAE;IAQjC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB;IAwB9E;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAwCrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAwBtB;;OAEG;IACH,OAAO,CAAC,YAAY;IAepB;;OAEG;IACH,OAAO,CAAC,aAAa;IAwBrB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuBxB;;OAEG;IACH,OAAO,CAAC,YAAY;CAuBrB"}
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Schema Registry Service
3
+ *
4
+ * Loads schema definitions from project sink directories and validates
5
+ * data payloads against those schemas. Central to the Data Architecture V2
6
+ * governance layer — ensures every piece of data entering a sink conforms
7
+ * to its declared structure.
8
+ *
9
+ * @module services/data/schema-registry.service
10
+ */
11
+ import * as path from 'path';
12
+ import * as fs from 'fs/promises';
13
+ import { existsSync } from 'fs';
14
+ import { LoggerService } from '../core/logger.service.js';
15
+ import { DATA_CONSTANTS } from '../../types/data-object.types.js';
16
+ /** ISO 8601 date-time regex (accepts both Z and +/-offset) */
17
+ const ISO8601_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
18
+ /**
19
+ * Singleton service that manages schema definitions and validates payloads.
20
+ *
21
+ * Schemas are loaded from `{projectPath}/sinks/{sinkDir}/_schema.json` for
22
+ * each registered sink, or from a consolidated registry file. The validate()
23
+ * method applies all declared field rules and returns a structured result.
24
+ */
25
+ export class SchemaRegistryService {
26
+ static instance = null;
27
+ logger;
28
+ schemas = new Map();
29
+ constructor() {
30
+ this.logger = LoggerService.getInstance().createComponentLogger('SchemaRegistryService');
31
+ }
32
+ /**
33
+ * Get the singleton instance.
34
+ *
35
+ * @returns SchemaRegistryService singleton
36
+ */
37
+ static getInstance() {
38
+ if (!SchemaRegistryService.instance) {
39
+ SchemaRegistryService.instance = new SchemaRegistryService();
40
+ }
41
+ return SchemaRegistryService.instance;
42
+ }
43
+ /**
44
+ * Reset the singleton (for testing).
45
+ */
46
+ static resetInstance() {
47
+ SchemaRegistryService.instance = null;
48
+ }
49
+ // ---------------------------------------------------------------------------
50
+ // Loading
51
+ // ---------------------------------------------------------------------------
52
+ /**
53
+ * Load schemas from a project's sinks directory.
54
+ *
55
+ * Scans `{projectPath}/sinks/` for sub-directories containing a
56
+ * `_schema.json` file and registers each valid schema.
57
+ *
58
+ * @param projectPath - Absolute path to the Crewly project root
59
+ */
60
+ async loadSchemas(projectPath) {
61
+ const sinksDir = path.join(projectPath, DATA_CONSTANTS.SINKS_DIR);
62
+ if (!existsSync(sinksDir)) {
63
+ this.logger.warn('Sinks directory does not exist, no schemas loaded', { sinksDir });
64
+ return;
65
+ }
66
+ const entries = await fs.readdir(sinksDir, { withFileTypes: true });
67
+ for (const entry of entries) {
68
+ if (!entry.isDirectory() || entry.name.startsWith('_')) {
69
+ continue;
70
+ }
71
+ const schemaPath = path.join(sinksDir, entry.name, DATA_CONSTANTS.SCHEMA_FILE);
72
+ if (!existsSync(schemaPath)) {
73
+ continue;
74
+ }
75
+ try {
76
+ const raw = await fs.readFile(schemaPath, 'utf-8');
77
+ const schema = JSON.parse(raw);
78
+ if (!schema.id || !schema.fields) {
79
+ this.logger.warn('Skipping invalid schema file (missing id or fields)', { schemaPath });
80
+ continue;
81
+ }
82
+ this.schemas.set(schema.id, schema);
83
+ this.logger.debug?.(`Loaded schema: ${schema.id}`, { name: schema.name });
84
+ }
85
+ catch (err) {
86
+ this.logger.warn('Failed to parse schema file', {
87
+ schemaPath,
88
+ error: err.message,
89
+ });
90
+ }
91
+ }
92
+ }
93
+ /**
94
+ * Register a schema definition directly (e.g. from tests or programmatic setup).
95
+ *
96
+ * @param schema - The schema to register
97
+ */
98
+ registerSchema(schema) {
99
+ this.schemas.set(schema.id, schema);
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // Accessors
103
+ // ---------------------------------------------------------------------------
104
+ /**
105
+ * Get a schema by its ID.
106
+ *
107
+ * @param schemaId - Unique schema identifier
108
+ * @returns The schema, or null if not found
109
+ */
110
+ getSchema(schemaId) {
111
+ return this.schemas.get(schemaId) ?? null;
112
+ }
113
+ /**
114
+ * List all loaded schemas.
115
+ *
116
+ * @returns Array of all registered SchemaDefinitions
117
+ */
118
+ listSchemas() {
119
+ return Array.from(this.schemas.values());
120
+ }
121
+ // ---------------------------------------------------------------------------
122
+ // Validation
123
+ // ---------------------------------------------------------------------------
124
+ /**
125
+ * Validate a payload against a registered schema.
126
+ *
127
+ * Applies the following rules per field:
128
+ * - **required**: field must exist and not be null/undefined
129
+ * - **type**: JS typeof must match (with special handling for array, datetime, enum)
130
+ * - **max_length**: string length must not exceed limit
131
+ * - **enum options**: value must be one of the declared options
132
+ * - **array min_items**: array length must meet minimum
133
+ * - **datetime**: value must match ISO 8601 format
134
+ *
135
+ * @param schemaId - ID of the schema to validate against
136
+ * @param payload - Key-value data to validate
137
+ * @returns Structured validation result with any errors
138
+ */
139
+ validate(schemaId, payload) {
140
+ const schema = this.schemas.get(schemaId);
141
+ if (!schema) {
142
+ return {
143
+ valid: false,
144
+ errors: [{ field: '_schema', message: `Schema '${schemaId}' not found`, rule: 'schema_exists' }],
145
+ };
146
+ }
147
+ const errors = [];
148
+ for (const [fieldName, fieldDef] of Object.entries(schema.fields)) {
149
+ const value = payload[fieldName];
150
+ this.validateField(fieldName, fieldDef, value, errors);
151
+ }
152
+ return { valid: errors.length === 0, errors };
153
+ }
154
+ // ---------------------------------------------------------------------------
155
+ // Private helpers
156
+ // ---------------------------------------------------------------------------
157
+ /**
158
+ * Validate a single field against its definition, pushing errors into the array.
159
+ *
160
+ * @param fieldName - Name of the field being validated
161
+ * @param fieldDef - Schema field definition
162
+ * @param value - Actual value from the payload
163
+ * @param errors - Mutable array to collect validation errors
164
+ */
165
+ validateField(fieldName, fieldDef, value, errors) {
166
+ // Required check
167
+ if (fieldDef.required && (value === undefined || value === null)) {
168
+ errors.push({ field: fieldName, message: `Field '${fieldName}' is required`, rule: 'required' });
169
+ return; // Skip further checks if missing
170
+ }
171
+ // If field is absent and not required, skip remaining rules
172
+ if (value === undefined || value === null) {
173
+ return;
174
+ }
175
+ // Type-specific checks
176
+ switch (fieldDef.type) {
177
+ case 'string':
178
+ this.validateString(fieldName, fieldDef, value, errors);
179
+ break;
180
+ case 'number':
181
+ this.validateType(fieldName, 'number', value, errors);
182
+ break;
183
+ case 'boolean':
184
+ this.validateType(fieldName, 'boolean', value, errors);
185
+ break;
186
+ case 'array':
187
+ this.validateArray(fieldName, fieldDef, value, errors);
188
+ break;
189
+ case 'datetime':
190
+ this.validateDatetime(fieldName, value, errors);
191
+ break;
192
+ case 'enum':
193
+ this.validateEnum(fieldName, fieldDef, value, errors);
194
+ break;
195
+ }
196
+ }
197
+ /**
198
+ * Validate a string field (typeof + max_length).
199
+ */
200
+ validateString(fieldName, fieldDef, value, errors) {
201
+ if (typeof value !== 'string') {
202
+ errors.push({
203
+ field: fieldName,
204
+ message: `Expected type 'string', got '${typeof value}'`,
205
+ rule: 'type',
206
+ });
207
+ return;
208
+ }
209
+ if (fieldDef.max_length !== undefined && value.length > fieldDef.max_length) {
210
+ errors.push({
211
+ field: fieldName,
212
+ message: `String exceeds max length of ${fieldDef.max_length} (got ${value.length})`,
213
+ rule: 'max_length',
214
+ });
215
+ }
216
+ }
217
+ /**
218
+ * Validate a primitive type via typeof.
219
+ */
220
+ validateType(fieldName, expectedType, value, errors) {
221
+ if (typeof value !== expectedType) {
222
+ errors.push({
223
+ field: fieldName,
224
+ message: `Expected type '${expectedType}', got '${typeof value}'`,
225
+ rule: 'type',
226
+ });
227
+ }
228
+ }
229
+ /**
230
+ * Validate an array field (isArray + min_items).
231
+ */
232
+ validateArray(fieldName, fieldDef, value, errors) {
233
+ if (!Array.isArray(value)) {
234
+ errors.push({
235
+ field: fieldName,
236
+ message: `Expected type 'array', got '${typeof value}'`,
237
+ rule: 'type',
238
+ });
239
+ return;
240
+ }
241
+ if (fieldDef.min_items !== undefined && value.length < fieldDef.min_items) {
242
+ errors.push({
243
+ field: fieldName,
244
+ message: `Array must have at least ${fieldDef.min_items} item(s), got ${value.length}`,
245
+ rule: 'min_items',
246
+ });
247
+ }
248
+ }
249
+ /**
250
+ * Validate a datetime field (must be a string matching ISO 8601).
251
+ */
252
+ validateDatetime(fieldName, value, errors) {
253
+ if (typeof value !== 'string') {
254
+ errors.push({
255
+ field: fieldName,
256
+ message: `Expected type 'datetime' (ISO8601 string), got '${typeof value}'`,
257
+ rule: 'type',
258
+ });
259
+ return;
260
+ }
261
+ if (!ISO8601_REGEX.test(value)) {
262
+ errors.push({
263
+ field: fieldName,
264
+ message: `Value '${value}' is not a valid ISO8601 datetime`,
265
+ rule: 'datetime',
266
+ });
267
+ }
268
+ }
269
+ /**
270
+ * Validate an enum field (value must be one of options).
271
+ */
272
+ validateEnum(fieldName, fieldDef, value, errors) {
273
+ if (typeof value !== 'string') {
274
+ errors.push({
275
+ field: fieldName,
276
+ message: `Expected type 'string' for enum, got '${typeof value}'`,
277
+ rule: 'type',
278
+ });
279
+ return;
280
+ }
281
+ if (fieldDef.options && !fieldDef.options.includes(value)) {
282
+ errors.push({
283
+ field: fieldName,
284
+ message: `Value '${value}' is not in allowed options: [${fieldDef.options.join(', ')}]`,
285
+ rule: 'enum',
286
+ });
287
+ }
288
+ }
289
+ }
290
+ //# sourceMappingURL=schema-registry.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-registry.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/data/schema-registry.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Sink Registry Service
3
+ *
4
+ * Manages sink definitions loaded from a project's `_sinks.json` file.
5
+ * Provides lookup, listing, tag-based matching, and registration of new sinks.
6
+ * Works alongside SchemaRegistryService to form the Data Architecture V2
7
+ * ingestion layer.
8
+ *
9
+ * @module services/data/sink-registry.service
10
+ */
11
+ import type { SinkDefinition } from '../../types/data-object.types.js';
12
+ /**
13
+ * Singleton service that manages data sink definitions.
14
+ *
15
+ * Sinks are loaded from `{projectPath}/sinks/_sinks.json`. Each sink declares
16
+ * a name, schema reference, tags, and a directory for storage. The matchSink()
17
+ * method enables content-aware routing of incoming data.
18
+ */
19
+ export declare class SinkRegistryService {
20
+ private static instance;
21
+ private readonly logger;
22
+ private readonly sinks;
23
+ private constructor();
24
+ /**
25
+ * Get the singleton instance.
26
+ *
27
+ * @returns SinkRegistryService singleton
28
+ */
29
+ static getInstance(): SinkRegistryService;
30
+ /**
31
+ * Reset the singleton (for testing).
32
+ */
33
+ static resetInstance(): void;
34
+ /**
35
+ * Load sink definitions from a project's `_sinks.json` file.
36
+ *
37
+ * If the file does not exist, the service starts with an empty registry
38
+ * (no error thrown). Invalid entries (missing id) are skipped with a warning.
39
+ *
40
+ * @param projectPath - Absolute path to the Crewly project root
41
+ */
42
+ loadSinks(projectPath: string): Promise<void>;
43
+ /**
44
+ * Get a sink by its ID.
45
+ *
46
+ * @param sinkId - Unique sink identifier
47
+ * @returns The sink definition, or null if not found
48
+ */
49
+ getSink(sinkId: string): SinkDefinition | null;
50
+ /**
51
+ * List all registered sinks.
52
+ *
53
+ * @returns Array of all SinkDefinitions
54
+ */
55
+ listSinks(): SinkDefinition[];
56
+ /**
57
+ * Match incoming data to the best sink based on tag overlap.
58
+ *
59
+ * Scores each sink by the number of matching tags (intersection with the
60
+ * provided tags array). If `content` is provided and a sink name appears
61
+ * in the content, that sink gets a bonus point. Returns the highest-scoring
62
+ * sink, or null if no sink has any overlap.
63
+ *
64
+ * @param tags - Tags from the incoming data
65
+ * @param content - Optional content string for keyword matching
66
+ * @returns Best-matching SinkDefinition, or null
67
+ */
68
+ matchSink(tags: string[], content?: string): SinkDefinition | null;
69
+ /**
70
+ * Register a new sink definition and persist it to `_sinks.json`.
71
+ *
72
+ * Creates the sinks directory and registry file if they don't exist.
73
+ * If a sink with the same ID already exists, it is overwritten.
74
+ *
75
+ * @param projectPath - Absolute path to the Crewly project root
76
+ * @param sink - The sink definition to register
77
+ */
78
+ registerSink(projectPath: string, sink: SinkDefinition): Promise<void>;
79
+ /**
80
+ * Compute the absolute path to the _sinks.json registry file.
81
+ *
82
+ * @param projectPath - Project root
83
+ * @returns Absolute path to _sinks.json
84
+ */
85
+ private registryPath;
86
+ }
87
+ //# sourceMappingURL=sink-registry.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sink-registry.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/data/sink-registry.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAWvE;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0C;IAEhE,OAAO;IAIP;;;;OAIG;IACH,MAAM,CAAC,WAAW,IAAI,mBAAmB;IAOzC;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI;IAQ5B;;;;;;;OAOG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCnD;;;;;OAKG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAI9C;;;;OAIG;IACH,SAAS,IAAI,cAAc,EAAE;IAQ7B;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAkClE;;;;;;;;OAQG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B5E;;;;;OAKG;IACH,OAAO,CAAC,YAAY;CAGrB"}