crewly 1.8.8 → 1.8.9

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 (164) hide show
  1. package/dist/backend/backend/src/constants.d.ts +12 -0
  2. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  3. package/dist/backend/backend/src/constants.js +12 -0
  4. package/dist/backend/backend/src/constants.js.map +1 -1
  5. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
  6. package/dist/backend/backend/src/controllers/browser/browser.controller.js +17 -0
  7. package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
  8. package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
  9. package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +8 -1
  10. package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -1
  11. package/dist/backend/backend/src/index.d.ts.map +1 -1
  12. package/dist/backend/backend/src/index.js +15 -7
  13. package/dist/backend/backend/src/index.js.map +1 -1
  14. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts.map +1 -1
  15. package/dist/backend/backend/src/services/browser/browser-bridge.service.js +15 -29
  16. package/dist/backend/backend/src/services/browser/browser-bridge.service.js.map +1 -1
  17. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts +97 -1
  18. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts.map +1 -1
  19. package/dist/backend/backend/src/services/browser/browser-proxy.service.js +174 -15
  20. package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
  21. package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.d.ts +12 -4
  22. package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.d.ts.map +1 -1
  23. package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.js +17 -5
  24. package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.js.map +1 -1
  25. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +75 -0
  26. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
  27. package/dist/backend/backend/src/services/cloud/cloud-client.service.js +164 -12
  28. package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
  29. package/dist/cli/backend/src/constants.d.ts +12 -0
  30. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  31. package/dist/cli/backend/src/constants.js +12 -0
  32. package/dist/cli/backend/src/constants.js.map +1 -1
  33. package/dist/cli/cli/src/index.js +0 -0
  34. package/package.json +1 -1
  35. package/config/constants.d.ts.map +0 -1
  36. package/config/index.d.ts.map +0 -1
  37. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +0 -169
  38. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +0 -1
  39. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +0 -1779
  40. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +0 -1
  41. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +0 -513
  42. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +0 -1
  43. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +0 -1568
  44. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +0 -1
  45. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.d.ts +0 -86
  46. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.d.ts.map +0 -1
  47. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.js +0 -147
  48. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.js.map +0 -1
  49. package/dist/backend/backend/src/services/agent/crewly-agent/api-client.d.ts +0 -68
  50. package/dist/backend/backend/src/services/agent/crewly-agent/api-client.d.ts.map +0 -1
  51. package/dist/backend/backend/src/services/agent/crewly-agent/api-client.js +0 -131
  52. package/dist/backend/backend/src/services/agent/crewly-agent/api-client.js.map +0 -1
  53. package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.d.ts +0 -130
  54. package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.d.ts.map +0 -1
  55. package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.js +0 -263
  56. package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.js.map +0 -1
  57. package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.d.ts +0 -74
  58. package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.d.ts.map +0 -1
  59. package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.js +0 -140
  60. package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.js.map +0 -1
  61. package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.d.ts +0 -29
  62. package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.d.ts.map +0 -1
  63. package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js +0 -279
  64. package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js.map +0 -1
  65. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts +0 -340
  66. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts.map +0 -1
  67. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js +0 -1176
  68. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js.map +0 -1
  69. package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.d.ts +0 -79
  70. package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.d.ts.map +0 -1
  71. package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.js +0 -145
  72. package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.js.map +0 -1
  73. package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.d.ts +0 -79
  74. package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.d.ts.map +0 -1
  75. package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.js +0 -218
  76. package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.js.map +0 -1
  77. package/dist/backend/backend/src/services/agent/crewly-agent/index.d.ts +0 -16
  78. package/dist/backend/backend/src/services/agent/crewly-agent/index.d.ts.map +0 -1
  79. package/dist/backend/backend/src/services/agent/crewly-agent/index.js +0 -16
  80. package/dist/backend/backend/src/services/agent/crewly-agent/index.js.map +0 -1
  81. package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.d.ts +0 -135
  82. package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.d.ts.map +0 -1
  83. package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.js +0 -185
  84. package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.js.map +0 -1
  85. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts +0 -141
  86. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +0 -1
  87. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +0 -310
  88. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +0 -1
  89. package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.d.ts +0 -91
  90. package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.d.ts.map +0 -1
  91. package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.js +0 -143
  92. package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.js.map +0 -1
  93. package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.d.ts +0 -103
  94. package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.d.ts.map +0 -1
  95. package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.js +0 -256
  96. package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.js.map +0 -1
  97. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts +0 -143
  98. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts.map +0 -1
  99. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js +0 -264
  100. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js.map +0 -1
  101. package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.d.ts +0 -13
  102. package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.d.ts.map +0 -1
  103. package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.js +0 -91
  104. package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.js.map +0 -1
  105. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts +0 -135
  106. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts.map +0 -1
  107. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js +0 -1937
  108. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js.map +0 -1
  109. package/dist/backend/backend/src/services/autonomous/auto-assign.service.d.ts +0 -429
  110. package/dist/backend/backend/src/services/autonomous/auto-assign.service.d.ts.map +0 -1
  111. package/dist/backend/backend/src/services/autonomous/auto-assign.service.js +0 -852
  112. package/dist/backend/backend/src/services/autonomous/auto-assign.service.js.map +0 -1
  113. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +0 -171
  114. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +0 -1
  115. package/dist/backend/backend/src/services/project/task-tracking.service.js +0 -725
  116. package/dist/backend/backend/src/services/project/task-tracking.service.js.map +0 -1
  117. package/dist/backend/backend/src/services/v3/project-task-watcher.service.d.ts +0 -118
  118. package/dist/backend/backend/src/services/v3/project-task-watcher.service.d.ts.map +0 -1
  119. package/dist/backend/backend/src/services/v3/project-task-watcher.service.js +0 -326
  120. package/dist/backend/backend/src/services/v3/project-task-watcher.service.js.map +0 -1
  121. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts +0 -74
  122. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts.map +0 -1
  123. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js +0 -154
  124. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js.map +0 -1
  125. package/dist/backend/backend/src/types/auto-assign.types.d.ts +0 -271
  126. package/dist/backend/backend/src/types/auto-assign.types.d.ts.map +0 -1
  127. package/dist/backend/backend/src/types/auto-assign.types.js +0 -136
  128. package/dist/backend/backend/src/types/auto-assign.types.js.map +0 -1
  129. package/dist/backend/backend/src/utils/esm-require.utils.d.ts +0 -111
  130. package/dist/backend/backend/src/utils/esm-require.utils.d.ts.map +0 -1
  131. package/dist/backend/backend/src/utils/esm-require.utils.js +0 -124
  132. package/dist/backend/backend/src/utils/esm-require.utils.js.map +0 -1
  133. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +0 -220
  134. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +0 -1
  135. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js +0 -37
  136. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +0 -1
  137. package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.d.ts +0 -56
  138. package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.d.ts.map +0 -1
  139. package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.js +0 -91
  140. package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.js.map +0 -1
  141. package/dist/cli/backend/src/services/knowledge/learnings-index.service.d.ts +0 -159
  142. package/dist/cli/backend/src/services/knowledge/learnings-index.service.d.ts.map +0 -1
  143. package/dist/cli/backend/src/services/knowledge/learnings-index.service.js +0 -304
  144. package/dist/cli/backend/src/services/knowledge/learnings-index.service.js.map +0 -1
  145. package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.d.ts +0 -115
  146. package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.d.ts.map +0 -1
  147. package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.js +0 -215
  148. package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.js.map +0 -1
  149. package/dist/cli/backend/src/services/memory/embedding-provider.d.ts +0 -78
  150. package/dist/cli/backend/src/services/memory/embedding-provider.d.ts.map +0 -1
  151. package/dist/cli/backend/src/services/memory/embedding-provider.js +0 -179
  152. package/dist/cli/backend/src/services/memory/embedding-provider.js.map +0 -1
  153. package/dist/cli/backend/src/services/memory/vector-store.service.d.ts +0 -331
  154. package/dist/cli/backend/src/services/memory/vector-store.service.d.ts.map +0 -1
  155. package/dist/cli/backend/src/services/memory/vector-store.service.js +0 -814
  156. package/dist/cli/backend/src/services/memory/vector-store.service.js.map +0 -1
  157. package/dist/cli/backend/src/services/project/task-tracking.service.d.ts +0 -171
  158. package/dist/cli/backend/src/services/project/task-tracking.service.d.ts.map +0 -1
  159. package/dist/cli/backend/src/services/project/task-tracking.service.js +0 -725
  160. package/dist/cli/backend/src/services/project/task-tracking.service.js.map +0 -1
  161. package/dist/cli/backend/src/types/auto-assign.types.d.ts +0 -271
  162. package/dist/cli/backend/src/types/auto-assign.types.d.ts.map +0 -1
  163. package/dist/cli/backend/src/types/auto-assign.types.js +0 -136
  164. package/dist/cli/backend/src/types/auto-assign.types.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"prompt-guard.service.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/prompt-guard.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,QAAQ,EAAE,gBAAgB,GAAG,UAAU,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;CACpF;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;IACpC,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,YAAY,EA2FjD,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,YAAY,EAqBnD,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAM,EAQnD,CAAC;AAEF;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0B;IAC1D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA0B;IAEzD;;;;;OAKG;gBAED,yBAAyB,CAAC,EAAE,YAAY,EAAE,EAC1C,wBAAwB,CAAC,EAAE,YAAY,EAAE;IAU3C;;;;;OAKG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB;IAmB/C;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB;IAmB7C;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAMrC;;;;;;;;OAQG;IACH,gBAAgB,CACd,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,gBAAgB,GAC5B,UAAU;CAiBd"}
@@ -1,256 +0,0 @@
1
- /**
2
- * Prompt Guard Service — Prompt Injection Protection
3
- *
4
- * Detects and blocks prompt injection attempts that try to extract API keys,
5
- * secrets, or sensitive environment variables through agent commands.
6
- *
7
- * Integrates with the tool registry to block dangerous bash commands and
8
- * logs blocked attempts to the audit trail.
9
- *
10
- * @module services/agent/crewly-agent/prompt-guard.service
11
- *
12
- * @example
13
- * ```typescript
14
- * const guard = new PromptGuardService();
15
- * const result = guard.checkCommand('echo $ANTHROPIC_API_KEY');
16
- * // { blocked: true, reason: 'Key extraction attempt: echo env var', pattern: '...' }
17
- * ```
18
- */
19
- /**
20
- * Patterns that detect attempts to extract API keys or secrets via bash commands.
21
- */
22
- export const KEY_EXTRACTION_PATTERNS = [
23
- // Direct env var echo/print
24
- {
25
- pattern: /\becho\s+\$[A-Z_]*(?:KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|AUTH)/i,
26
- reason: 'Attempt to echo sensitive environment variable',
27
- category: 'env_extraction',
28
- },
29
- {
30
- pattern: /\bprintf\s+.*\$[A-Z_]*(?:KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|AUTH)/i,
31
- reason: 'Attempt to printf sensitive environment variable',
32
- category: 'env_extraction',
33
- },
34
- // env/printenv with grep for secrets
35
- {
36
- pattern: /\benv\b.*\|\s*grep\s+.*(?:KEY|SECRET|TOKEN|PASSWORD|API|AUTH)/i,
37
- reason: 'Attempt to grep env for secrets',
38
- category: 'env_extraction',
39
- },
40
- {
41
- pattern: /\bprintenv\b.*(?:KEY|SECRET|TOKEN|PASSWORD|API|AUTH)/i,
42
- reason: 'Attempt to printenv sensitive variable',
43
- category: 'env_extraction',
44
- },
45
- // set | grep (bash set command dumps all vars)
46
- {
47
- pattern: /\bset\b\s*\|\s*grep\s+.*(?:KEY|SECRET|TOKEN|PASSWORD|API|AUTH)/i,
48
- reason: 'Attempt to dump shell variables and grep for secrets',
49
- category: 'env_extraction',
50
- },
51
- // Reading sensitive config files (must come before bare env/printenv to avoid early match on "cat .env")
52
- {
53
- pattern: /\bcat\s+.*\.env\b/i,
54
- reason: 'Attempt to read .env file',
55
- category: 'file_exfiltration',
56
- },
57
- {
58
- pattern: /\bcat\s+.*(?:credentials|secrets|\.aws\/credentials|\.npmrc|\.netrc|\.pgpass)/i,
59
- reason: 'Attempt to read credentials file',
60
- category: 'file_exfiltration',
61
- },
62
- {
63
- pattern: /\bcat\s+.*\/etc\/shadow\b/i,
64
- reason: 'Attempt to read system password file',
65
- category: 'file_exfiltration',
66
- },
67
- // Direct env dump
68
- {
69
- pattern: /\benv\s*$/i,
70
- reason: 'Attempt to dump all environment variables',
71
- category: 'key_dump',
72
- },
73
- {
74
- pattern: /\bprintenv\s*$/i,
75
- reason: 'Attempt to dump all environment variables',
76
- category: 'key_dump',
77
- },
78
- // compgen dumps shell vars/functions
79
- {
80
- pattern: /\bcompgen\s+-[ev]/i,
81
- reason: 'Attempt to dump shell variables via compgen',
82
- category: 'key_dump',
83
- },
84
- // base64 encoding secrets for exfiltration
85
- {
86
- pattern: /\bbase64\b.*\$[A-Z_]*(?:KEY|SECRET|TOKEN)/i,
87
- reason: 'Attempt to base64 encode secret for exfiltration',
88
- category: 'file_exfiltration',
89
- },
90
- // curl/wget exfiltration of env vars
91
- {
92
- pattern: /\b(?:curl|wget)\b.*\$[A-Z_]*(?:KEY|SECRET|TOKEN)/i,
93
- reason: 'Attempt to exfiltrate secret via HTTP request',
94
- category: 'file_exfiltration',
95
- },
96
- // Python/Node one-liners to access env
97
- {
98
- pattern: /\bpython[23]?\s+-c\s+.*os\.environ/i,
99
- reason: 'Attempt to access env via Python subprocess',
100
- category: 'env_extraction',
101
- },
102
- {
103
- pattern: /\bnode\s+-e\s+.*process\.env/i,
104
- reason: 'Attempt to access env via Node subprocess',
105
- category: 'env_extraction',
106
- },
107
- // Specific key variable names in $() or backtick subshells
108
- {
109
- pattern: /\$\(.*(?:ANTHROPIC_API_KEY|OPENAI_API_KEY|GOOGLE_API_KEY|AWS_SECRET|STRIPE_SECRET)/i,
110
- reason: 'Attempt to expand sensitive env var in subshell',
111
- category: 'env_extraction',
112
- },
113
- ];
114
- /**
115
- * Prompt-level injection patterns (detected in natural language prompts, not just commands).
116
- */
117
- export const PROMPT_INJECTION_PATTERNS = [
118
- {
119
- pattern: /(?:print|show|reveal|tell\s+me|display|output|give\s+me|share)\s+(?:(?:your|the|my|me\s+the)\s+)?(?:api[_ ]?key|secret|token|password|credentials)/i,
120
- reason: 'Prompt injection: request to reveal API key/secret',
121
- category: 'prompt_injection',
122
- },
123
- {
124
- pattern: /(?:what\s+is|what's)\s+(?:your|the|my)\s+(?:api[_ ]?key|secret[_ ]?key|auth[_ ]?token|password)/i,
125
- reason: 'Prompt injection: question about API key/secret',
126
- category: 'prompt_injection',
127
- },
128
- {
129
- pattern: /ignore\s+(?:previous|all|your)\s+(?:instructions|rules|safety)/i,
130
- reason: 'Prompt injection: instruction override attempt',
131
- category: 'prompt_injection',
132
- },
133
- {
134
- pattern: /(?:override|bypass|disable|turn\s+off)\s+(?:security|safety|filter|guardrail|redaction)/i,
135
- reason: 'Prompt injection: attempt to disable security filters',
136
- category: 'prompt_injection',
137
- },
138
- ];
139
- /**
140
- * Additional blocked command patterns for tool-registry.ts integration.
141
- * These extend the existing BLOCKED_COMMAND_PATTERNS with key extraction blocks.
142
- */
143
- export const KEY_EXTRACTION_BLOCKED_COMMANDS = [
144
- /\benv\s*$/i,
145
- /\bprintenv\s*$/i,
146
- /\benv\b.*\|\s*grep\s+.*(?:KEY|SECRET|TOKEN|PASSWORD|API)/i,
147
- /\bset\b\s*\|\s*grep\s+.*(?:KEY|SECRET|TOKEN|PASSWORD|API)/i,
148
- /\bcompgen\s+-[ev]/i,
149
- /\bcat\s+.*\.env\b/i,
150
- /\bcat\s+.*(?:credentials|secrets|\.aws\/credentials|\.npmrc|\.netrc|\.pgpass)/i,
151
- ];
152
- /**
153
- * Service that detects and blocks prompt injection and key extraction attempts.
154
- */
155
- export class PromptGuardService {
156
- commandPatterns;
157
- promptPatterns;
158
- /**
159
- * Creates a new PromptGuardService.
160
- *
161
- * @param additionalCommandPatterns - Extra command-level patterns
162
- * @param additionalPromptPatterns - Extra prompt-level patterns
163
- */
164
- constructor(additionalCommandPatterns, additionalPromptPatterns) {
165
- this.commandPatterns = additionalCommandPatterns
166
- ? [...KEY_EXTRACTION_PATTERNS, ...additionalCommandPatterns]
167
- : KEY_EXTRACTION_PATTERNS;
168
- this.promptPatterns = additionalPromptPatterns
169
- ? [...PROMPT_INJECTION_PATTERNS, ...additionalPromptPatterns]
170
- : PROMPT_INJECTION_PATTERNS;
171
- }
172
- /**
173
- * Checks a bash command for key extraction attempts.
174
- *
175
- * @param command - Raw bash command string
176
- * @returns Guard check result
177
- */
178
- checkCommand(command) {
179
- if (!command) {
180
- return { blocked: false, reason: '' };
181
- }
182
- for (const guard of this.commandPatterns) {
183
- if (guard.pattern.test(command)) {
184
- return {
185
- blocked: true,
186
- reason: guard.reason,
187
- category: guard.category,
188
- matchedPattern: guard.pattern.source,
189
- };
190
- }
191
- }
192
- return { blocked: false, reason: '' };
193
- }
194
- /**
195
- * Checks a user/agent prompt for injection attempts targeting secrets.
196
- *
197
- * @param prompt - The text prompt or message
198
- * @returns Guard check result
199
- */
200
- checkPrompt(prompt) {
201
- if (!prompt) {
202
- return { blocked: false, reason: '' };
203
- }
204
- for (const guard of this.promptPatterns) {
205
- if (guard.pattern.test(prompt)) {
206
- return {
207
- blocked: true,
208
- reason: guard.reason,
209
- category: guard.category,
210
- matchedPattern: guard.pattern.source,
211
- };
212
- }
213
- }
214
- return { blocked: false, reason: '' };
215
- }
216
- /**
217
- * Checks both command and prompt patterns.
218
- * Use this for comprehensive scanning of any agent input.
219
- *
220
- * @param text - Text to check (command or prompt)
221
- * @returns Guard check result
222
- */
223
- check(text) {
224
- const cmdResult = this.checkCommand(text);
225
- if (cmdResult.blocked)
226
- return cmdResult;
227
- return this.checkPrompt(text);
228
- }
229
- /**
230
- * Creates an audit entry for a blocked attempt.
231
- *
232
- * @param sessionName - Agent session that triggered the block
233
- * @param toolName - Tool that was used (e.g. 'bash_exec')
234
- * @param command - The blocked command
235
- * @param guardResult - The guard check result
236
- * @returns AuditEntry suitable for the audit log
237
- */
238
- createAuditEntry(sessionName, toolName, command, guardResult) {
239
- return {
240
- timestamp: new Date().toISOString(),
241
- sessionName,
242
- toolName,
243
- sensitivity: 'destructive',
244
- args: {
245
- command,
246
- blockedReason: guardResult.reason,
247
- category: guardResult.category || 'unknown',
248
- matchedPattern: guardResult.matchedPattern || '',
249
- },
250
- success: false,
251
- error: `Blocked by prompt guard: ${guardResult.reason}`,
252
- durationMs: 0,
253
- };
254
- }
255
- }
256
- //# sourceMappingURL=prompt-guard.service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prompt-guard.service.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/prompt-guard.service.ts"],"names":[],"mappings":"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"}
@@ -1,143 +0,0 @@
1
- /**
2
- * Rate Limiter for Crewly Agent API Calls
3
- *
4
- * Provides token-bucket rate limiting, message coalescing, and 429 retry
5
- * logic to prevent Gemini API quota exhaustion when multiple agents are
6
- * actively generating messages.
7
- *
8
- * @module services/agent/crewly-agent/rate-limiter
9
- */
10
- /**
11
- * Configuration for the rate limiter.
12
- */
13
- export interface RateLimiterConfig {
14
- /** Maximum requests allowed per window */
15
- maxRequestsPerWindow: number;
16
- /** Time window in milliseconds */
17
- windowMs: number;
18
- /** Maximum retry attempts for 429 errors */
19
- maxRetries: number;
20
- /** Initial backoff delay in milliseconds for 429 retries */
21
- initialBackoffMs: number;
22
- /** Backoff multiplier for exponential retry */
23
- backoffMultiplier: number;
24
- /** Maximum backoff delay in milliseconds */
25
- maxBackoffMs: number;
26
- /** Coalescing window — how long to wait for additional messages before processing (ms) */
27
- coalesceWindowMs: number;
28
- }
29
- /**
30
- * Default rate limiter configuration.
31
- */
32
- export declare const RATE_LIMITER_DEFAULTS: RateLimiterConfig;
33
- /**
34
- * Token-bucket rate limiter with message coalescing and 429 retry.
35
- *
36
- * Features:
37
- * - **Rate limiting**: Enforces max requests per time window using a sliding window.
38
- * - **Message coalescing**: Groups messages arriving within a short window into one.
39
- * - **429 retry**: Wraps API calls with exponential backoff on quota errors.
40
- *
41
- * @example
42
- * ```typescript
43
- * const limiter = new RateLimiter<AgentRunResult>();
44
- * const result = await limiter.enqueue('Check status', undefined, async (msg) => {
45
- * return agentRunner.run(msg);
46
- * });
47
- * ```
48
- */
49
- export declare class RateLimiter<T> {
50
- private config;
51
- private requestTimestamps;
52
- private queue;
53
- private processing;
54
- private coalesceTimer;
55
- /**
56
- * Create a new RateLimiter instance.
57
- *
58
- * @param config - Optional partial config overrides
59
- */
60
- constructor(config?: Partial<RateLimiterConfig>);
61
- /**
62
- * Enqueue a message for rate-limited processing.
63
- *
64
- * If multiple messages arrive within the coalescing window, they are
65
- * merged into a single request to reduce API call count.
66
- *
67
- * @param message - Message to process
68
- * @param metadata - Optional metadata
69
- * @param handler - Async function that performs the actual API call
70
- * @returns Result from the handler
71
- */
72
- enqueue(message: string, metadata: Record<string, string> | undefined, handler: (message: string, metadata?: Record<string, string>) => Promise<T>): Promise<T>;
73
- /**
74
- * Get the current number of messages in the queue.
75
- *
76
- * @returns Queue length
77
- */
78
- getQueueLength(): number;
79
- /**
80
- * Check if the rate limiter is currently processing.
81
- *
82
- * @returns True if processing
83
- */
84
- isProcessing(): boolean;
85
- /**
86
- * Get the number of requests made in the current window.
87
- *
88
- * @returns Request count in current window
89
- */
90
- getRequestCountInWindow(): number;
91
- /**
92
- * Get the current configuration.
93
- *
94
- * @returns Rate limiter configuration
95
- */
96
- getConfig(): RateLimiterConfig;
97
- /**
98
- * Reset internal state (for testing).
99
- */
100
- reset(): void;
101
- /**
102
- * Process the queue: coalesce messages, enforce rate limit, execute with retry.
103
- *
104
- * @param handler - The actual API call handler
105
- */
106
- private processQueue;
107
- /**
108
- * Wait until we have capacity in the rate limit window.
109
- */
110
- private waitForCapacity;
111
- /**
112
- * Remove timestamps older than the current window.
113
- */
114
- private pruneOldTimestamps;
115
- /**
116
- * Coalesce multiple queued messages into a single message.
117
- *
118
- * If there's only one message, it passes through unchanged.
119
- * Multiple messages are joined with a separator and a header.
120
- *
121
- * @param batch - Array of queued messages to coalesce
122
- * @returns Single coalesced message and metadata from the most recent item
123
- */
124
- private coalesceMessages;
125
- /**
126
- * Execute the handler with exponential backoff retry on 429/quota errors.
127
- *
128
- * @param message - Message to send
129
- * @param metadata - Optional metadata
130
- * @param handler - The API call handler
131
- * @returns Handler result
132
- * @throws Error after max retries exhausted
133
- */
134
- private executeWithRetry;
135
- /**
136
- * Check if an error is retryable (429 or quota-related).
137
- *
138
- * @param error - The error to check
139
- * @returns True if the error should be retried
140
- */
141
- private isRetryableError;
142
- }
143
- //# sourceMappingURL=rate-limiter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,iBAQnC,CAAC;AAkBF;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,WAAW,CAAC,CAAC;IACxB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAA8C;IAEnE;;;;OAIG;gBACS,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAI/C;;;;;;;;;;OAUG;IACH,OAAO,CACL,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAC5C,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAC1E,OAAO,CAAC,CAAC,CAAC;IA0Bb;;;;OAIG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;OAIG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;OAIG;IACH,uBAAuB,IAAI,MAAM;IAKjC;;;;OAIG;IACH,SAAS,IAAI,iBAAiB;IAI9B;;OAEG;IACH,KAAK,IAAI,IAAI;IAUb;;;;OAIG;YACW,YAAY;IAiD1B;;OAEG;YACW,eAAe;IAgB7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;;;;;;;OAQG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;;;;;;;OAQG;YACW,gBAAgB;IAqC9B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;CAUzB"}
@@ -1,264 +0,0 @@
1
- /**
2
- * Rate Limiter for Crewly Agent API Calls
3
- *
4
- * Provides token-bucket rate limiting, message coalescing, and 429 retry
5
- * logic to prevent Gemini API quota exhaustion when multiple agents are
6
- * actively generating messages.
7
- *
8
- * @module services/agent/crewly-agent/rate-limiter
9
- */
10
- /**
11
- * Default rate limiter configuration.
12
- */
13
- export const RATE_LIMITER_DEFAULTS = {
14
- maxRequestsPerWindow: 10,
15
- windowMs: 60_000,
16
- maxRetries: 3,
17
- initialBackoffMs: 5_000,
18
- backoffMultiplier: 2,
19
- maxBackoffMs: 60_000,
20
- coalesceWindowMs: 2_000,
21
- };
22
- /**
23
- * Token-bucket rate limiter with message coalescing and 429 retry.
24
- *
25
- * Features:
26
- * - **Rate limiting**: Enforces max requests per time window using a sliding window.
27
- * - **Message coalescing**: Groups messages arriving within a short window into one.
28
- * - **429 retry**: Wraps API calls with exponential backoff on quota errors.
29
- *
30
- * @example
31
- * ```typescript
32
- * const limiter = new RateLimiter<AgentRunResult>();
33
- * const result = await limiter.enqueue('Check status', undefined, async (msg) => {
34
- * return agentRunner.run(msg);
35
- * });
36
- * ```
37
- */
38
- export class RateLimiter {
39
- config;
40
- requestTimestamps = [];
41
- queue = [];
42
- processing = false;
43
- coalesceTimer = null;
44
- /**
45
- * Create a new RateLimiter instance.
46
- *
47
- * @param config - Optional partial config overrides
48
- */
49
- constructor(config) {
50
- this.config = { ...RATE_LIMITER_DEFAULTS, ...config };
51
- }
52
- /**
53
- * Enqueue a message for rate-limited processing.
54
- *
55
- * If multiple messages arrive within the coalescing window, they are
56
- * merged into a single request to reduce API call count.
57
- *
58
- * @param message - Message to process
59
- * @param metadata - Optional metadata
60
- * @param handler - Async function that performs the actual API call
61
- * @returns Result from the handler
62
- */
63
- enqueue(message, metadata, handler) {
64
- return new Promise((resolve, reject) => {
65
- this.queue.push({
66
- message,
67
- metadata,
68
- resolve,
69
- reject,
70
- enqueuedAt: Date.now(),
71
- });
72
- // Reset coalesce timer — wait for more messages before processing
73
- if (this.coalesceTimer) {
74
- clearTimeout(this.coalesceTimer);
75
- }
76
- this.coalesceTimer = setTimeout(() => {
77
- this.coalesceTimer = null;
78
- if (!this.processing) {
79
- this.processQueue(handler).catch(() => {
80
- // Errors are already routed to individual promise reject callbacks
81
- });
82
- }
83
- }, this.config.coalesceWindowMs);
84
- });
85
- }
86
- /**
87
- * Get the current number of messages in the queue.
88
- *
89
- * @returns Queue length
90
- */
91
- getQueueLength() {
92
- return this.queue.length;
93
- }
94
- /**
95
- * Check if the rate limiter is currently processing.
96
- *
97
- * @returns True if processing
98
- */
99
- isProcessing() {
100
- return this.processing;
101
- }
102
- /**
103
- * Get the number of requests made in the current window.
104
- *
105
- * @returns Request count in current window
106
- */
107
- getRequestCountInWindow() {
108
- this.pruneOldTimestamps();
109
- return this.requestTimestamps.length;
110
- }
111
- /**
112
- * Get the current configuration.
113
- *
114
- * @returns Rate limiter configuration
115
- */
116
- getConfig() {
117
- return { ...this.config };
118
- }
119
- /**
120
- * Reset internal state (for testing).
121
- */
122
- reset() {
123
- this.requestTimestamps = [];
124
- this.queue = [];
125
- this.processing = false;
126
- if (this.coalesceTimer) {
127
- clearTimeout(this.coalesceTimer);
128
- this.coalesceTimer = null;
129
- }
130
- }
131
- /**
132
- * Process the queue: coalesce messages, enforce rate limit, execute with retry.
133
- *
134
- * @param handler - The actual API call handler
135
- */
136
- async processQueue(handler) {
137
- this.processing = true;
138
- try {
139
- while (this.queue.length > 0) {
140
- // Wait for rate limit window if needed
141
- await this.waitForCapacity();
142
- // Coalesce all pending messages into one
143
- const batch = this.queue.splice(0, this.queue.length);
144
- const coalesced = this.coalesceMessages(batch);
145
- // Record this request timestamp
146
- this.requestTimestamps.push(Date.now());
147
- // Execute with 429 retry
148
- try {
149
- const result = await this.executeWithRetry(coalesced.message, coalesced.metadata, handler);
150
- // Resolve all promises in the batch with the same result
151
- for (const item of batch) {
152
- item.resolve(result);
153
- }
154
- }
155
- catch (error) {
156
- // Reject all promises in the batch
157
- const err = error instanceof Error ? error : new Error(String(error));
158
- for (const item of batch) {
159
- item.reject(err);
160
- }
161
- }
162
- }
163
- }
164
- finally {
165
- this.processing = false;
166
- // Check if more messages arrived while processing
167
- if (this.queue.length > 0) {
168
- this.processQueue(handler).catch(() => {
169
- // Errors are already routed to individual promise reject callbacks
170
- });
171
- }
172
- }
173
- }
174
- /**
175
- * Wait until we have capacity in the rate limit window.
176
- */
177
- async waitForCapacity() {
178
- this.pruneOldTimestamps();
179
- while (this.requestTimestamps.length >= this.config.maxRequestsPerWindow) {
180
- // Calculate how long to wait until the oldest request falls out of the window
181
- const oldestTimestamp = this.requestTimestamps[0];
182
- const waitMs = (oldestTimestamp + this.config.windowMs) - Date.now() + 100; // +100ms buffer
183
- if (waitMs > 0) {
184
- await new Promise((resolve) => setTimeout(resolve, waitMs));
185
- }
186
- this.pruneOldTimestamps();
187
- }
188
- }
189
- /**
190
- * Remove timestamps older than the current window.
191
- */
192
- pruneOldTimestamps() {
193
- const cutoff = Date.now() - this.config.windowMs;
194
- this.requestTimestamps = this.requestTimestamps.filter((ts) => ts > cutoff);
195
- }
196
- /**
197
- * Coalesce multiple queued messages into a single message.
198
- *
199
- * If there's only one message, it passes through unchanged.
200
- * Multiple messages are joined with a separator and a header.
201
- *
202
- * @param batch - Array of queued messages to coalesce
203
- * @returns Single coalesced message and metadata from the most recent item
204
- */
205
- coalesceMessages(batch) {
206
- if (batch.length === 1) {
207
- return { message: batch[0].message, metadata: batch[0].metadata };
208
- }
209
- // Use metadata from the most recent message
210
- const latestMetadata = batch[batch.length - 1].metadata;
211
- // Coalesce messages with a numbered separator
212
- const parts = batch.map((item, index) => {
213
- return `[Message ${index + 1}/${batch.length}]\n${item.message}`;
214
- });
215
- const coalesced = `${batch.length} messages received while rate-limited. Process them together:\n\n${parts.join('\n\n---\n\n')}`;
216
- return { message: coalesced, metadata: latestMetadata };
217
- }
218
- /**
219
- * Execute the handler with exponential backoff retry on 429/quota errors.
220
- *
221
- * @param message - Message to send
222
- * @param metadata - Optional metadata
223
- * @param handler - The API call handler
224
- * @returns Handler result
225
- * @throws Error after max retries exhausted
226
- */
227
- async executeWithRetry(message, metadata, handler) {
228
- let lastError = null;
229
- for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
230
- try {
231
- return await handler(message, metadata);
232
- }
233
- catch (error) {
234
- lastError = error instanceof Error ? error : new Error(String(error));
235
- // Only retry on 429 / quota errors
236
- if (!this.isRetryableError(lastError)) {
237
- throw lastError;
238
- }
239
- if (attempt >= this.config.maxRetries) {
240
- break;
241
- }
242
- // Exponential backoff
243
- const backoffMs = Math.min(this.config.initialBackoffMs * Math.pow(this.config.backoffMultiplier, attempt), this.config.maxBackoffMs);
244
- await new Promise((resolve) => setTimeout(resolve, backoffMs));
245
- }
246
- }
247
- throw new Error(`Rate limit retries exhausted (${this.config.maxRetries} attempts). Last error: ${lastError?.message}`);
248
- }
249
- /**
250
- * Check if an error is retryable (429 or quota-related).
251
- *
252
- * @param error - The error to check
253
- * @returns True if the error should be retried
254
- */
255
- isRetryableError(error) {
256
- const message = error.message.toLowerCase();
257
- return (message.includes('429') ||
258
- message.includes('quota') ||
259
- message.includes('rate limit') ||
260
- message.includes('resource_exhausted') ||
261
- message.includes('too many requests'));
262
- }
263
- }
264
- //# sourceMappingURL=rate-limiter.js.map