@relayflows/core 0.0.1 → 1.0.1

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 (182) hide show
  1. package/dist/agent-handle.d.ts +27 -0
  2. package/dist/agent-handle.d.ts.map +1 -0
  3. package/dist/agent-handle.js +32 -0
  4. package/dist/agent-handle.js.map +1 -0
  5. package/dist/api-executor.d.ts +16 -0
  6. package/dist/api-executor.d.ts.map +1 -0
  7. package/dist/api-executor.js +94 -0
  8. package/dist/api-executor.js.map +1 -0
  9. package/dist/barrier.d.ts +72 -0
  10. package/dist/barrier.d.ts.map +1 -0
  11. package/dist/barrier.js +162 -0
  12. package/dist/barrier.js.map +1 -0
  13. package/dist/budget-tracker.d.ts +75 -0
  14. package/dist/budget-tracker.d.ts.map +1 -0
  15. package/dist/budget-tracker.js +184 -0
  16. package/dist/budget-tracker.js.map +1 -0
  17. package/dist/builder.d.ts +229 -0
  18. package/dist/builder.d.ts.map +1 -0
  19. package/dist/builder.js +430 -0
  20. package/dist/builder.js.map +1 -0
  21. package/dist/builtin-templates/bug-fix.yaml +139 -0
  22. package/dist/builtin-templates/code-review.yaml +137 -0
  23. package/dist/builtin-templates/competitive.yaml +107 -0
  24. package/dist/builtin-templates/documentation.yaml +128 -0
  25. package/dist/builtin-templates/feature-dev.yaml +146 -0
  26. package/dist/builtin-templates/refactor.yaml +145 -0
  27. package/dist/builtin-templates/review-loop.yaml +227 -0
  28. package/dist/builtin-templates/security-audit.yaml +139 -0
  29. package/dist/channel-messenger.d.ts +28 -0
  30. package/dist/channel-messenger.d.ts.map +1 -0
  31. package/dist/channel-messenger.js +275 -0
  32. package/dist/channel-messenger.js.map +1 -0
  33. package/dist/cli-registry.d.ts +77 -0
  34. package/dist/cli-registry.d.ts.map +1 -0
  35. package/dist/cli-registry.js +268 -0
  36. package/dist/cli-registry.js.map +1 -0
  37. package/dist/cli-session-collector.d.ts +39 -0
  38. package/dist/cli-session-collector.d.ts.map +1 -0
  39. package/dist/cli-session-collector.js +23 -0
  40. package/dist/cli-session-collector.js.map +1 -0
  41. package/dist/cli.d.ts +11 -0
  42. package/dist/cli.d.ts.map +1 -0
  43. package/dist/cli.js +395 -0
  44. package/dist/cli.js.map +1 -0
  45. package/dist/cloud-runner.d.ts +15 -0
  46. package/dist/cloud-runner.d.ts.map +1 -0
  47. package/dist/cloud-runner.js +41 -0
  48. package/dist/cloud-runner.js.map +1 -0
  49. package/dist/cloud-schedules.d.ts +3 -0
  50. package/dist/cloud-schedules.d.ts.map +1 -0
  51. package/dist/cloud-schedules.js +2 -0
  52. package/dist/cloud-schedules.js.map +1 -0
  53. package/dist/collectors/claude.d.ts +6 -0
  54. package/dist/collectors/claude.d.ts.map +1 -0
  55. package/dist/collectors/claude.js +330 -0
  56. package/dist/collectors/claude.js.map +1 -0
  57. package/dist/collectors/codex.d.ts +18 -0
  58. package/dist/collectors/codex.d.ts.map +1 -0
  59. package/dist/collectors/codex.js +265 -0
  60. package/dist/collectors/codex.js.map +1 -0
  61. package/dist/collectors/opencode.d.ts +6 -0
  62. package/dist/collectors/opencode.d.ts.map +1 -0
  63. package/dist/collectors/opencode.js +204 -0
  64. package/dist/collectors/opencode.js.map +1 -0
  65. package/dist/coordinator.d.ts +73 -0
  66. package/dist/coordinator.d.ts.map +1 -0
  67. package/dist/coordinator.js +647 -0
  68. package/dist/coordinator.js.map +1 -0
  69. package/dist/custom-steps.d.ts +73 -0
  70. package/dist/custom-steps.d.ts.map +1 -0
  71. package/dist/custom-steps.js +321 -0
  72. package/dist/custom-steps.js.map +1 -0
  73. package/dist/default-logger.d.ts +9 -0
  74. package/dist/default-logger.d.ts.map +1 -0
  75. package/dist/default-logger.js +104 -0
  76. package/dist/default-logger.js.map +1 -0
  77. package/dist/dry-run-format.d.ts +6 -0
  78. package/dist/dry-run-format.d.ts.map +1 -0
  79. package/dist/dry-run-format.js +79 -0
  80. package/dist/dry-run-format.js.map +1 -0
  81. package/dist/file-db.d.ts +85 -0
  82. package/dist/file-db.d.ts.map +1 -0
  83. package/dist/file-db.js +215 -0
  84. package/dist/file-db.js.map +1 -0
  85. package/dist/index.d.ts +37 -1
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +34 -3
  88. package/dist/index.js.map +1 -0
  89. package/dist/integrations/browser.d.ts +99 -0
  90. package/dist/integrations/browser.d.ts.map +1 -0
  91. package/dist/integrations/browser.js +419 -0
  92. package/dist/integrations/browser.js.map +1 -0
  93. package/dist/integrations/github.d.ts +79 -0
  94. package/dist/integrations/github.d.ts.map +1 -0
  95. package/dist/integrations/github.js +459 -0
  96. package/dist/integrations/github.js.map +1 -0
  97. package/dist/integrations/slack.d.ts +80 -0
  98. package/dist/integrations/slack.d.ts.map +1 -0
  99. package/dist/integrations/slack.js +355 -0
  100. package/dist/integrations/slack.js.map +1 -0
  101. package/dist/listr-renderer.d.ts +26 -0
  102. package/dist/listr-renderer.d.ts.map +1 -0
  103. package/dist/listr-renderer.js +230 -0
  104. package/dist/listr-renderer.js.map +1 -0
  105. package/dist/memory-db.d.ts +17 -0
  106. package/dist/memory-db.d.ts.map +1 -0
  107. package/dist/memory-db.js +33 -0
  108. package/dist/memory-db.js.map +1 -0
  109. package/dist/process-backend-executor.d.ts +18 -0
  110. package/dist/process-backend-executor.d.ts.map +1 -0
  111. package/dist/process-backend-executor.js +74 -0
  112. package/dist/process-backend-executor.js.map +1 -0
  113. package/dist/process-spawner.d.ts +35 -0
  114. package/dist/process-spawner.d.ts.map +1 -0
  115. package/dist/process-spawner.js +173 -0
  116. package/dist/process-spawner.js.map +1 -0
  117. package/dist/provisioner.d.ts +64 -0
  118. package/dist/provisioner.d.ts.map +1 -0
  119. package/dist/provisioner.js +269 -0
  120. package/dist/provisioner.js.map +1 -0
  121. package/dist/proxy-env.d.ts +52 -0
  122. package/dist/proxy-env.d.ts.map +1 -0
  123. package/dist/proxy-env.js +92 -0
  124. package/dist/proxy-env.js.map +1 -0
  125. package/dist/run-script.d.ts +82 -0
  126. package/dist/run-script.d.ts.map +1 -0
  127. package/dist/run-script.js +527 -0
  128. package/dist/run-script.js.map +1 -0
  129. package/dist/run-summary-table.d.ts +5 -0
  130. package/dist/run-summary-table.d.ts.map +1 -0
  131. package/dist/run-summary-table.js +132 -0
  132. package/dist/run-summary-table.js.map +1 -0
  133. package/dist/run.d.ts +45 -0
  134. package/dist/run.d.ts.map +1 -0
  135. package/dist/run.js +37 -0
  136. package/dist/run.js.map +1 -0
  137. package/dist/runner.d.ts +528 -0
  138. package/dist/runner.d.ts.map +1 -0
  139. package/dist/runner.js +6269 -0
  140. package/dist/runner.js.map +1 -0
  141. package/dist/schema.d.ts +275 -0
  142. package/dist/schema.d.ts.map +1 -0
  143. package/dist/schema.js +27 -0
  144. package/dist/schema.js.map +1 -0
  145. package/dist/schema.json +940 -0
  146. package/dist/sibling-links.d.ts +100 -0
  147. package/dist/sibling-links.d.ts.map +1 -0
  148. package/dist/sibling-links.js +205 -0
  149. package/dist/sibling-links.js.map +1 -0
  150. package/dist/state.d.ts +77 -0
  151. package/dist/state.d.ts.map +1 -0
  152. package/dist/state.js +140 -0
  153. package/dist/state.js.map +1 -0
  154. package/dist/step-executor.d.ts +95 -0
  155. package/dist/step-executor.d.ts.map +1 -0
  156. package/dist/step-executor.js +393 -0
  157. package/dist/step-executor.js.map +1 -0
  158. package/dist/template-resolver.d.ts +33 -0
  159. package/dist/template-resolver.d.ts.map +1 -0
  160. package/dist/template-resolver.js +144 -0
  161. package/dist/template-resolver.js.map +1 -0
  162. package/dist/templates.d.ts +47 -0
  163. package/dist/templates.d.ts.map +1 -0
  164. package/dist/templates.js +405 -0
  165. package/dist/templates.js.map +1 -0
  166. package/dist/trajectory.d.ts +87 -0
  167. package/dist/trajectory.d.ts.map +1 -0
  168. package/dist/trajectory.js +412 -0
  169. package/dist/trajectory.js.map +1 -0
  170. package/dist/types.d.ts +471 -0
  171. package/dist/types.d.ts.map +1 -0
  172. package/dist/types.js +37 -0
  173. package/dist/types.js.map +1 -0
  174. package/dist/validator.d.ts +11 -0
  175. package/dist/validator.d.ts.map +1 -0
  176. package/dist/validator.js +186 -0
  177. package/dist/validator.js.map +1 -0
  178. package/dist/verification.d.ts +53 -0
  179. package/dist/verification.d.ts.map +1 -0
  180. package/dist/verification.js +238 -0
  181. package/dist/verification.js.map +1 -0
  182. package/package.json +12 -8
@@ -0,0 +1,227 @@
1
+ version: '1.0'
2
+ name: review-loop
3
+ description: 'Implement a task with automated multi-perspective code review loop. Inspired by claude-review-loop pattern.'
4
+ swarm:
5
+ pattern: review-loop
6
+ maxConcurrency: 4
7
+ timeoutMs: 3600000
8
+ channel: swarm-review-loop
9
+ idleNudge:
10
+ nudgeAfterMs: 180000
11
+ escalateAfterMs: 180000
12
+ maxNudges: 2
13
+ agents:
14
+ - name: implementer
15
+ cli: claude
16
+ role: 'Senior developer implementing the task and addressing review feedback'
17
+ permissions: { access: full }
18
+ - name: reviewer-diff
19
+ cli: codex
20
+ role: 'Code quality reviewer focusing on git diff, tests, and potential bugs'
21
+ permissions: { access: readonly }
22
+ interactive: false
23
+ - name: reviewer-architecture
24
+ cli: claude
25
+ role: 'Architecture and design reviewer assessing structure and maintainability'
26
+ permissions: { access: readonly }
27
+ interactive: false
28
+ - name: reviewer-security
29
+ cli: codex
30
+ role: 'Security reviewer checking for OWASP Top 10 vulnerabilities'
31
+ permissions: { access: readonly }
32
+ interactive: false
33
+ workflows:
34
+ - name: review-loop-workflow
35
+ description: 'Implement task, run parallel reviews, consolidate feedback, and address issues.'
36
+ onError: fail
37
+ steps:
38
+ # Phase 1: Implementation
39
+ - name: implement
40
+ type: agent
41
+ agent: implementer
42
+ task: |
43
+ Implement the following task:
44
+ {{task}}
45
+
46
+ When complete, output: IMPLEMENTATION COMPLETE
47
+ verification:
48
+ type: output_contains
49
+ value: IMPLEMENTATION COMPLETE
50
+
51
+ # Deterministic: Capture diff for review
52
+ - name: capture-diff
53
+ type: deterministic
54
+ dependsOn: [implement]
55
+ command: git diff HEAD~1 2>/dev/null || git diff 2>/dev/null || echo "No changes"
56
+ captureOutput: true
57
+
58
+ # Deterministic: Capture file list
59
+ - name: capture-files
60
+ type: deterministic
61
+ dependsOn: [capture-diff]
62
+ command: git diff --name-only HEAD~1 2>/dev/null || git diff --name-only 2>/dev/null || echo "No files"
63
+ captureOutput: true
64
+
65
+ # Phase 2: Parallel Reviews (fan-out)
66
+ - name: review-diff
67
+ type: agent
68
+ agent: reviewer-diff
69
+ dependsOn: [capture-files]
70
+ task: |
71
+ Review the git diff for code quality issues:
72
+
73
+ Focus areas:
74
+ - Code readability and clarity
75
+ - Test coverage (are new features tested?)
76
+ - Potential bugs or edge cases
77
+ - Error handling completeness
78
+
79
+ Changed files: {{steps.capture-files.output}}
80
+
81
+ Diff:
82
+ {{steps.capture-diff.output}}
83
+
84
+ Output format:
85
+ - If all looks good: REVIEW:PASS
86
+ - If issues found: REVIEW:ISSUES followed by numbered list of issues
87
+ verification:
88
+ type: output_contains
89
+ value: 'REVIEW:'
90
+
91
+ - name: review-architecture
92
+ type: agent
93
+ agent: reviewer-architecture
94
+ dependsOn: [capture-files]
95
+ task: |
96
+ Review the architecture and design:
97
+
98
+ Focus areas:
99
+ - Design patterns and best practices
100
+ - Separation of concerns
101
+ - Code organization and maintainability
102
+ - API design (if applicable)
103
+
104
+ Changed files: {{steps.capture-files.output}}
105
+
106
+ Diff:
107
+ {{steps.capture-diff.output}}
108
+
109
+ Output format:
110
+ - If all looks good: REVIEW:PASS
111
+ - If issues found: REVIEW:ISSUES followed by numbered list of issues
112
+ verification:
113
+ type: output_contains
114
+ value: 'REVIEW:'
115
+
116
+ - name: review-security
117
+ type: agent
118
+ agent: reviewer-security
119
+ dependsOn: [capture-files]
120
+ task: |
121
+ Security review for OWASP Top 10 vulnerabilities:
122
+
123
+ Focus areas:
124
+ - Injection vulnerabilities (SQL, command, XSS)
125
+ - Authentication and authorization issues
126
+ - Sensitive data exposure
127
+ - Security misconfiguration
128
+ - Input validation
129
+
130
+ Changed files: {{steps.capture-files.output}}
131
+
132
+ Diff:
133
+ {{steps.capture-diff.output}}
134
+
135
+ Output format:
136
+ - If secure: REVIEW:PASS
137
+ - If vulnerabilities found: REVIEW:ISSUES followed by numbered list with severity
138
+ verification:
139
+ type: output_contains
140
+ value: 'REVIEW:'
141
+
142
+ # Phase 3: Consolidate reviews
143
+ - name: consolidate
144
+ type: agent
145
+ agent: implementer
146
+ dependsOn: [review-diff, review-architecture, review-security]
147
+ task: |
148
+ Review all feedback from the code reviewers and consolidate findings:
149
+
150
+ ## Diff Review
151
+ {{steps.review-diff.output}}
152
+
153
+ ## Architecture Review
154
+ {{steps.review-architecture.output}}
155
+
156
+ ## Security Review
157
+ {{steps.review-security.output}}
158
+
159
+ Tasks:
160
+ 1. Analyze each review's findings
161
+ 2. Identify which issues are valid and should be addressed
162
+ 3. Note any conflicting feedback
163
+ 4. Create a prioritized action plan
164
+
165
+ Output: CONSOLIDATED with summary of issues to address (or NO_ISSUES if all reviews passed)
166
+ verification:
167
+ type: output_contains
168
+ value: CONSOLIDATED
169
+
170
+ # Phase 4: Address feedback (the loop)
171
+ - name: address-feedback
172
+ type: agent
173
+ agent: implementer
174
+ dependsOn: [consolidate]
175
+ task: |
176
+ Address the consolidated review feedback:
177
+
178
+ {{steps.consolidate.output}}
179
+
180
+ For each valid issue:
181
+ 1. Make the necessary code changes
182
+ 2. Explain what was fixed and why
183
+
184
+ If there were no issues to address, confirm the implementation is complete.
185
+
186
+ Output: ADDRESSED followed by summary of changes made (or NO_CHANGES_NEEDED)
187
+ verification:
188
+ type: output_contains
189
+ value: ADDRESSED
190
+ retries: 2
191
+ maxIterations: 3
192
+
193
+ # Final step: Completion summary
194
+ - name: complete
195
+ type: agent
196
+ agent: implementer
197
+ dependsOn: [address-feedback]
198
+ task: |
199
+ Provide a final summary of the completed work:
200
+
201
+ Original task: {{task}}
202
+
203
+ Include:
204
+ 1. What was implemented
205
+ 2. Key decisions made
206
+ 3. Review feedback that was addressed
207
+ 4. Any remaining considerations or follow-up items
208
+
209
+ Output: DONE
210
+ verification:
211
+ type: output_contains
212
+ value: DONE
213
+
214
+ coordination:
215
+ barriers:
216
+ - name: reviews-complete
217
+ waitFor: [review-diff, review-architecture, review-security]
218
+ timeoutMs: 900000
219
+ consensusStrategy: majority
220
+ state:
221
+ backend: memory
222
+ ttlMs: 21600000
223
+ namespace: review-loop
224
+ errorHandling:
225
+ strategy: continue
226
+ maxRetries: 2
227
+ notifyChannel: swarm-review-loop
@@ -0,0 +1,139 @@
1
+ version: '1.0'
2
+ name: security-audit
3
+ description: 'Blueprint-style security assessment with deterministic scanning and agent triage.'
4
+ swarm:
5
+ pattern: pipeline
6
+ maxConcurrency: 1
7
+ timeoutMs: 5400000
8
+ channel: swarm-security-audit
9
+ idleNudge:
10
+ nudgeAfterMs: 120000
11
+ escalateAfterMs: 120000
12
+ maxNudges: 1
13
+ agents:
14
+ - name: lead
15
+ cli: claude
16
+ role: 'Owns final risk sign-off and recommendations'
17
+ permissions: { access: full }
18
+ - name: analyst
19
+ cli: claude
20
+ role: 'Prioritizes findings and recommends mitigations'
21
+ permissions:
22
+ access: readonly
23
+ files:
24
+ deny: ['.env', 'secrets/**', '*.pem', '*.key']
25
+ - name: remediator
26
+ cli: codex
27
+ role: 'Implements approved remediations'
28
+ permissions: { access: readwrite }
29
+ interactive: false
30
+ - name: verifier
31
+ cli: gemini
32
+ role: 'Verifies fixes and residual exposure'
33
+ permissions:
34
+ access: readonly
35
+ files:
36
+ deny: ['.env', 'secrets/**', '*.pem', '*.key']
37
+ workflows:
38
+ - name: audit-pipeline
39
+ description: 'Scan, triage, remediate, verify, and report security posture.'
40
+ onError: fail
41
+ preflight:
42
+ - command: npm audit --json 2>/dev/null | head -100 || echo "{}"
43
+ description: 'Run npm audit preflight check'
44
+ - command: git diff --check 2>/dev/null || echo "clean"
45
+ description: 'Check for whitespace errors'
46
+ steps:
47
+ # Deterministic: Run npm audit
48
+ - name: scan-npm
49
+ type: deterministic
50
+ command: npm audit --json 2>/dev/null || echo '{"vulnerabilities":{}}'
51
+ captureOutput: true
52
+
53
+ # Deterministic: Run additional security scans if available
54
+ - name: scan-extra
55
+ type: deterministic
56
+ dependsOn: [scan-npm]
57
+ command: |
58
+ if command -v semgrep &> /dev/null; then
59
+ semgrep --config auto --json . 2>/dev/null || echo '{"results":[]}'
60
+ else
61
+ echo '{"results":[],"note":"semgrep not installed"}'
62
+ fi
63
+
64
+ # Agent: Triage findings
65
+ - name: triage
66
+ type: agent
67
+ agent: analyst
68
+ dependsOn: [scan-npm, scan-extra]
69
+ task: |
70
+ Prioritize security findings by severity and exploitability:
71
+
72
+ NPM Audit: {{steps.scan-npm.output}}
73
+ Additional Scans: {{steps.scan-extra.output}}
74
+
75
+ Task context: {{task}}
76
+ verification:
77
+ type: output_contains
78
+ value: TRIAGE_COMPLETE
79
+
80
+ # Agent: Implement remediations
81
+ - name: remediate
82
+ type: agent
83
+ agent: remediator
84
+ dependsOn: [triage]
85
+ task: |
86
+ Implement mitigations for approved findings:
87
+ {{steps.triage.output}}
88
+ retries: 1
89
+ verification:
90
+ type: output_contains
91
+ value: REMEDIATION_COMPLETE
92
+
93
+ # Deterministic: Re-run tests
94
+ - name: test
95
+ type: deterministic
96
+ dependsOn: [remediate]
97
+ command: npm test 2>/dev/null || echo "No tests configured"
98
+
99
+ # Agent: Verify fixes
100
+ - name: verify
101
+ type: agent
102
+ agent: verifier
103
+ dependsOn: [test]
104
+ task: |
105
+ Re-test security posture and confirm mitigations hold:
106
+ {{steps.remediate.output}}
107
+ Test results: {{steps.test.output}}
108
+ verification:
109
+ type: output_contains
110
+ value: VERIFICATION_COMPLETE
111
+
112
+ # Deterministic: Commit security fixes
113
+ - name: commit
114
+ type: deterministic
115
+ dependsOn: [verify]
116
+ command: 'git add -A && git commit -m "security: address vulnerabilities from audit" 2>/dev/null || echo "No changes to commit"'
117
+
118
+ # Agent: Final report
119
+ - name: report
120
+ type: agent
121
+ agent: lead
122
+ dependsOn: [commit]
123
+ task: |
124
+ Produce final audit report with residual risk and next actions.
125
+ verification:
126
+ type: output_contains
127
+ value: DONE
128
+ coordination:
129
+ barriers:
130
+ - name: audit-complete
131
+ waitFor: [scan-npm, triage, remediate, verify]
132
+ timeoutMs: 1200000
133
+ state:
134
+ backend: memory
135
+ ttlMs: 86400000
136
+ namespace: security-audit
137
+ errorHandling:
138
+ strategy: fail-fast
139
+ notifyChannel: swarm-security-audit
@@ -0,0 +1,28 @@
1
+ import type { StepOutcome } from './trajectory.js';
2
+ import type { AgentDefinition, WorkflowStepRow } from './types.js';
3
+ type StepStateLike = {
4
+ row: Pick<WorkflowStepRow, 'agentName' | 'status'>;
5
+ };
6
+ export interface ChannelRelayLike {
7
+ send(to: string, text: string): Promise<unknown>;
8
+ }
9
+ export interface ChannelMessengerOptions {
10
+ postFn?: (text: string) => void;
11
+ }
12
+ export declare function sendToChannel(relay: ChannelRelayLike, channel: string, message: string): Promise<void>;
13
+ export declare function truncateMessage(message: string, maxLength: number): string;
14
+ export declare function formatStepOutput(stepName: string, output: string, maxLength?: number): string;
15
+ export declare function formatError(stepName: string, error: unknown): string;
16
+ export declare function scrubSecrets(text: string): string;
17
+ export declare function scrubForChannel(text: string): string;
18
+ export declare class ChannelMessenger {
19
+ private readonly postFn?;
20
+ constructor(options?: ChannelMessengerOptions);
21
+ buildNonInteractiveAwareness(agentMap: Map<string, AgentDefinition>, stepStates: Map<string, StepStateLike>): string | undefined;
22
+ buildRelayRegistrationNote(cli: string, agentName: string): string;
23
+ buildDelegationGuidance(cli: string, timeoutMs?: number): string;
24
+ postCompletionReport(workflowName: string, outcomes: StepOutcome[], summary: string, confidence: number): void;
25
+ postFailureReport(workflowName: string, outcomes: StepOutcome[], errorMsg: string): void;
26
+ }
27
+ export {};
28
+ //# sourceMappingURL=channel-messenger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-messenger.d.ts","sourceRoot":"","sources":["../src/channel-messenger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnE,KAAK,aAAa,GAAG;IACnB,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,QAAQ,CAAC,CAAC;CACpD,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG1E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,MAAM,CAQ3F;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAKpE;AA+CD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMjD;AAWD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmFpD;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAyB;gBAErC,OAAO,GAAE,uBAA4B;IAIjD,4BAA4B,CAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACtC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GACrC,MAAM,GAAG,SAAS;IA6BrB,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAalE,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAmChE,oBAAoB,CAClB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,IAAI;IA6BP,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAoBzF"}
@@ -0,0 +1,275 @@
1
+ import stripAnsiFn from 'strip-ansi';
2
+ export async function sendToChannel(relay, channel, message) {
3
+ await relay.send(channel, message);
4
+ }
5
+ export function truncateMessage(message, maxLength) {
6
+ if (maxLength <= 0)
7
+ return '';
8
+ return message.length > maxLength ? message.slice(-maxLength) : message;
9
+ }
10
+ export function formatStepOutput(stepName, output, maxLength = 2000) {
11
+ const scrubbed = scrubForChannel(output);
12
+ if (scrubbed.length === 0) {
13
+ return `**[${stepName}]** Step completed — output written to disk`;
14
+ }
15
+ const preview = truncateMessage(scrubbed, maxLength);
16
+ return `**[${stepName}] Output:**\n\`\`\`\n${preview}\n\`\`\``;
17
+ }
18
+ export function formatError(stepName, error) {
19
+ const raw = error instanceof Error ? error.message : String(error);
20
+ // Strip absolute paths that could leak internal directory structure
21
+ const message = raw.replace(/(?:\/[\w.-]+){3,}/g, '[path]');
22
+ return `**[${stepName}]** Failed: ${message}`;
23
+ }
24
+ // Common secret patterns to redact from channel output.
25
+ const SECRET_PATTERNS = [
26
+ /(?:api[_-]?key|apikey|secret[_-]?key|access[_-]?token|auth[_-]?token|bearer)\s*[:=]\s*\S+/gi,
27
+ /(?:sk|pk|rk|ak)[-_][a-zA-Z0-9]{20,}/g,
28
+ /ghp_[a-zA-Z0-9]{36,}/g,
29
+ /gho_[a-zA-Z0-9]{36,}/g,
30
+ /github_pat_[a-zA-Z0-9_]{22,}/g,
31
+ /xox[bpors]-[a-zA-Z0-9-]+/g,
32
+ /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----[\s\S]*?-----END/g,
33
+ ];
34
+ // Unicode spinner / ornament characters used by Claude TUI animations.
35
+ // Includes block-element chars (▗▖▘▝) used in the Claude Code header bar.
36
+ const SPINNER = '\\u2756\\u2738\\u2739\\u273a\\u273b\\u273c\\u273d\\u2731\\u2732\\u2733\\u2734\\u2735\\u2736\\u2737\\u2743\\u2745\\u2746\\u25d6\\u25d7\\u25d8\\u25d9\\u2022\\u25cf\\u25cb\\u25a0\\u25a1\\u25b6\\u25c0\\u23f5\\u23f6\\u23f7\\u23f8\\u23f9\\u25e2\\u25e3\\u25e4\\u25e5\\u2597\\u2596\\u2598\\u259d\\u2bc8\\u2bc7\\u2bc5\\u2bc6\\u00b7' +
37
+ '\\u2590\\u258c\\u2588\\u2584\\u2580\\u259a\\u259e' +
38
+ '\\u2b21\\u2b22';
39
+ // Pre-compiled regex constants — hoisted to module level to avoid recompilation per call.
40
+ const SPINNER_RE = new RegExp(`[${SPINNER}]`, 'gu');
41
+ const SPINNER_CLASS_RE = new RegExp(`^[\\s${SPINNER}]*$`, 'u');
42
+ const BOX_DRAWING_ONLY_RE = /^[\s\u2500-\u257f\u2580-\u259f\u25a0-\u25ff\-_=~]{3,}$/u;
43
+ const BROKER_LOG_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z\s+(?:INFO|WARN|ERROR|DEBUG)\s/u;
44
+ const CLAUDE_HEADER_RE = /^(?:[\s\u2580-\u259f✢*·▗▖▘▝]+\s*)?(?:Claude\s+Code(?:\s+v?[\d.]+)?|(?:Sonnet|Haiku|Opus)\s*[\d.]+|claude-(?:sonnet|haiku|opus)-[\w.-]+|Running\s+on\s+claude)/iu;
45
+ const DIR_BREADCRUMB_RE = /^\s*~[\\/]/u;
46
+ const UI_HINT_RE = /\b(?:Press\s*up\s*to\s*edit|tab\s*to\s*queue|bypass\s*permissions|esc\s*to\s*interrupt|paste\s*again\s*to\s*expand|shift\s*[+]?\s*tab\s*to\s*cycle|running\s+stop\s+hook|fan\s+out\s+subagents)/iu;
47
+ const VIM_MODE_RE = /^[-\s]*--?(?:INSERT|NORMAL|VISUAL|REPLACE)--?[-\s]*$|--?(?:INSERT|NORMAL|VISUAL|REPLACE)--/u;
48
+ const CLAUDE_FOOTER_RE = /(?:Opus|Sonnet|Haiku)\s*\d[\d.]*\s*\(?(?:1M\s*context|context)?\)?\s*ctx\s*:\s*\d+%/iu;
49
+ const THINKING_LINE_RE = new RegExp(`^[\\s${SPINNER}]*\\s*\\w[\\w\\s]*\\u2026\\s*$`, 'u');
50
+ const THINKING_STATUS_RE = /\b(?:thinking\s+(?:with\s+\w+\s+effort|more\s+with|harder)|↓\s*\d+\s*tokens?\b|↑\s*\d+\s*tokens?\b|crunched\s+for\s+\d|sautéed\s+for\s+\d|befuddl|flibbertigib|gitifying|flowing\s*…)/iu;
51
+ const CURSOR_ONLY_RE = /^[\s❯⎿›»◀▶←→↑↓⟨⟩⟪⟫·]+$/u;
52
+ const CURSOR_AGENT_RE = /^(?:Cursor Agent|[\s⬡⬢]*Generating[.\s]|\[Pasted text|Auto-run all|Add a follow-up|ctrl\+c to stop|shift\+tab|Auto$|\/\s*commands|@\s*files|!\s*shell|follow-ups?\s|The user ha)/iu;
53
+ const SLASH_COMMAND_RE = /^\/\w+\s*$/u;
54
+ const MCP_JSON_KV_RE = /^\s*"(?:type|method|params|result|id|jsonrpc|tool|name|arguments|content|role|metadata)"\s*:/u;
55
+ const MEANINGFUL_CONTENT_RE = /[a-zA-Z0-9]/u;
56
+ const MALFORMED_PTY_FRAME_RUN_RE = /(?:(?:qW0|q[A-Za-z]?0|[lmjkx]q{2,}|q{2,}[lmjkx]?)[\s|/_=\-~]*){4,}/giu;
57
+ const MALFORMED_PTY_FRAME_ONLY_RE = /^[\s|/_=\-~lmjkxqtwuvn0W]{12,}$/iu;
58
+ export function scrubSecrets(text) {
59
+ let result = text;
60
+ for (const pattern of SECRET_PATTERNS) {
61
+ result = result.replace(pattern, '[REDACTED]');
62
+ }
63
+ return result;
64
+ }
65
+ function stripMalformedPtyFrameGarbage(line) {
66
+ const strippedRuns = line.replace(MALFORMED_PTY_FRAME_RUN_RE, ' ');
67
+ const compact = strippedRuns.replace(SPINNER_RE, '').replace(/\s+/g, '');
68
+ if (compact.length >= 12 && MALFORMED_PTY_FRAME_ONLY_RE.test(compact)) {
69
+ return '';
70
+ }
71
+ return strippedRuns;
72
+ }
73
+ export function scrubForChannel(text) {
74
+ // Strip system-reminder blocks (closed or unclosed) iteratively to avoid
75
+ // polynomial backtracking (ReDoS) with [\s\S]*? on adversarial input.
76
+ let withoutSystemReminders = text;
77
+ const openTag = '<system-reminder>';
78
+ const closeTag = '</system-reminder>';
79
+ let idx;
80
+ while ((idx = withoutSystemReminders.toLowerCase().indexOf(openTag)) !== -1) {
81
+ const closeIdx = withoutSystemReminders.toLowerCase().indexOf(closeTag, idx + openTag.length);
82
+ if (closeIdx !== -1) {
83
+ withoutSystemReminders =
84
+ withoutSystemReminders.slice(0, idx) + withoutSystemReminders.slice(closeIdx + closeTag.length);
85
+ }
86
+ else {
87
+ // Unclosed tag — strip everything from the opening tag onward
88
+ withoutSystemReminders = withoutSystemReminders.slice(0, idx);
89
+ break;
90
+ }
91
+ }
92
+ // Normalize CRLF and bare \r before stripping ANSI — PTY output often
93
+ // contains \r\r\n which leaves stray \r after stripping that confuse line splitting.
94
+ const normalized = withoutSystemReminders.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
95
+ const ansiStripped = stripAnsiFn(normalized);
96
+ // Redact secrets before further processing
97
+ const secretsRedacted = scrubSecrets(ansiStripped);
98
+ const countJsonDepth = (line) => {
99
+ let depth = 0;
100
+ for (const ch of line) {
101
+ if (ch === '{' || ch === '[')
102
+ depth += 1;
103
+ if (ch === '}' || ch === ']')
104
+ depth -= 1;
105
+ }
106
+ return depth;
107
+ };
108
+ const lines = secretsRedacted.split('\n');
109
+ const meaningful = [];
110
+ let jsonDepth = 0;
111
+ for (const line of lines) {
112
+ const cleanedLine = stripMalformedPtyFrameGarbage(line);
113
+ const trimmed = cleanedLine.trim();
114
+ if (jsonDepth > 0) {
115
+ jsonDepth += countJsonDepth(cleanedLine);
116
+ if (jsonDepth <= 0)
117
+ jsonDepth = 0;
118
+ continue;
119
+ }
120
+ if (trimmed.length === 0)
121
+ continue;
122
+ if (trimmed.startsWith('{') || /^\[\s*\{/.test(trimmed)) {
123
+ jsonDepth = Math.max(countJsonDepth(cleanedLine), 0);
124
+ continue;
125
+ }
126
+ if (MCP_JSON_KV_RE.test(cleanedLine))
127
+ continue;
128
+ if (SPINNER_CLASS_RE.test(trimmed))
129
+ continue;
130
+ if (BOX_DRAWING_ONLY_RE.test(trimmed))
131
+ continue;
132
+ if (BROKER_LOG_RE.test(trimmed))
133
+ continue;
134
+ if (CLAUDE_HEADER_RE.test(trimmed))
135
+ continue;
136
+ if (DIR_BREADCRUMB_RE.test(trimmed))
137
+ continue;
138
+ if (UI_HINT_RE.test(trimmed))
139
+ continue;
140
+ if (VIM_MODE_RE.test(trimmed))
141
+ continue;
142
+ if (CLAUDE_FOOTER_RE.test(trimmed))
143
+ continue;
144
+ if (THINKING_LINE_RE.test(trimmed))
145
+ continue;
146
+ if (THINKING_STATUS_RE.test(trimmed))
147
+ continue;
148
+ if (CURSOR_ONLY_RE.test(trimmed))
149
+ continue;
150
+ if (CURSOR_AGENT_RE.test(trimmed))
151
+ continue;
152
+ if (SLASH_COMMAND_RE.test(trimmed))
153
+ continue;
154
+ if (!MEANINGFUL_CONTENT_RE.test(trimmed))
155
+ continue;
156
+ const alphanum = trimmed.replace(SPINNER_RE, '').replace(/\s+/g, '');
157
+ if (alphanum.replace(/[^a-zA-Z0-9]/g, '').length <= 3)
158
+ continue;
159
+ meaningful.push(cleanedLine);
160
+ }
161
+ return meaningful
162
+ .join('\n')
163
+ .replace(/\n{3,}/g, '\n\n')
164
+ .trim();
165
+ }
166
+ export class ChannelMessenger {
167
+ postFn;
168
+ constructor(options = {}) {
169
+ this.postFn = options.postFn;
170
+ }
171
+ buildNonInteractiveAwareness(agentMap, stepStates) {
172
+ const nonInteractive = [...agentMap.values()].filter((agent) => agent.interactive === false);
173
+ if (nonInteractive.length === 0)
174
+ return undefined;
175
+ const agentToSteps = new Map();
176
+ for (const [stepName, state] of stepStates) {
177
+ const agentName = state.row.agentName;
178
+ if (!agentName)
179
+ continue;
180
+ if (!agentToSteps.has(agentName))
181
+ agentToSteps.set(agentName, []);
182
+ agentToSteps.get(agentName).push(stepName);
183
+ }
184
+ const lines = nonInteractive.map((agent) => {
185
+ const stepRefs = (agentToSteps.get(agent.name) ?? []).map((stepName) => `{{steps.${stepName}.output}}`);
186
+ return (`- ${agent.name} (${agent.cli}) — will return output when complete` +
187
+ (stepRefs.length > 0 ? `. Access via: ${stepRefs.join(', ')}` : ''));
188
+ });
189
+ return ('\n\n---\n' +
190
+ 'Note: The following agents are non-interactive workers and cannot receive messages:\n' +
191
+ lines.join('\n') +
192
+ '\n' +
193
+ 'Do NOT attempt to message these agents. Use the {{steps.<name>.output}} references above to access their results.');
194
+ }
195
+ buildRelayRegistrationNote(cli, agentName) {
196
+ if (cli === 'claude')
197
+ return '';
198
+ return ('---\n' +
199
+ 'RELAY SETUP — do this FIRST before any other relay tool:\n' +
200
+ `1. Call: register_agent(name="${agentName}")\n` +
201
+ ' This authenticates you in the Relaycast workspace.\n' +
202
+ ' ALL relay tools (mcp__relaycast__send_dm, mcp__relaycast__check_inbox, mcp__relaycast__post_message, etc.) require\n' +
203
+ ' registration first — they will fail with "Not registered" otherwise.\n' +
204
+ `2. Your agent name is "${agentName}" — use this exact name when registering.`);
205
+ }
206
+ buildDelegationGuidance(cli, timeoutMs) {
207
+ const timeoutNote = timeoutMs
208
+ ? `You have approximately ${Math.round(timeoutMs / 60000)} minutes before this step times out. ` +
209
+ 'Plan accordingly — delegate early if the work is substantial.\n\n'
210
+ : '';
211
+ const subAgentOption = cli === 'claude'
212
+ ? 'Option 2 — Use built-in sub-agents (Task tool) for research or scoped work:\n' +
213
+ ' - Good for exploring code, reading files, or making targeted changes\n' +
214
+ ' - Can run multiple sub-agents in parallel\n\n'
215
+ : '';
216
+ return ('---\n' +
217
+ 'AUTONOMOUS DELEGATION — READ THIS BEFORE STARTING:\n' +
218
+ timeoutNote +
219
+ 'Before diving in, assess whether this task is too large or complex for a single agent. ' +
220
+ 'If it involves multiple independent subtasks, touches many files, or could take a long time, ' +
221
+ 'you should break it down and delegate to helper agents to avoid timeouts.\n\n' +
222
+ 'Option 1 — Spawn relay agents (for real parallel coding work):\n' +
223
+ ' - mcp__relaycast__add_agent(name="helper-1", cli="claude", task="Specific subtask description")\n' +
224
+ ' - Coordinate via mcp__relaycast__send_dm(to="helper-1", text="...")\n' +
225
+ ' - Check on them with mcp__relaycast__check_inbox()\n' +
226
+ ' - Clean up when done: mcp__relaycast__remove_agent(name="helper-1")\n\n' +
227
+ subAgentOption +
228
+ 'Guidelines:\n' +
229
+ '- You are the lead — delegate but stay in control, track progress, integrate results\n' +
230
+ '- Give each helper a clear, self-contained task with enough context to work independently\n' +
231
+ "- For simple or quick work, just do it yourself — don't over-delegate\n" +
232
+ '- Always release spawned relay agents when their work is complete\n' +
233
+ '- When spawning non-claude agents (codex, gemini, etc.), prepend to their task:\n' +
234
+ ' "RELAY SETUP: First call register_agent(name=\'<exact-agent-name>\') before any other relay tool."');
235
+ }
236
+ postCompletionReport(workflowName, outcomes, summary, confidence) {
237
+ const completed = outcomes.filter((outcome) => outcome.status === 'completed');
238
+ const skipped = outcomes.filter((outcome) => outcome.status === 'skipped');
239
+ const retried = outcomes.filter((outcome) => outcome.attempts > 1);
240
+ const lines = [
241
+ `## Workflow **${workflowName}** — Complete`,
242
+ '',
243
+ summary,
244
+ `Confidence: ${Math.round(confidence * 100)}%`,
245
+ '',
246
+ '### Steps',
247
+ ...completed.map((outcome) => `- **${outcome.name}** (${outcome.agent}) — passed${outcome.verificationPassed ? ' (verified)' : ''}${outcome.attempts > 1 ? ` after ${outcome.attempts} attempts` : ''}`),
248
+ ...skipped.map((outcome) => `- **${outcome.name}** — skipped`),
249
+ ];
250
+ if (retried.length > 0) {
251
+ lines.push('', '### Retries');
252
+ for (const outcome of retried) {
253
+ lines.push(`- ${outcome.name}: ${outcome.attempts} attempts`);
254
+ }
255
+ }
256
+ this.postFn?.(lines.join('\n'));
257
+ }
258
+ postFailureReport(workflowName, outcomes, errorMsg) {
259
+ const completed = outcomes.filter((outcome) => outcome.status === 'completed');
260
+ const failed = outcomes.filter((outcome) => outcome.status === 'failed');
261
+ const skipped = outcomes.filter((outcome) => outcome.status === 'skipped');
262
+ const lines = [
263
+ `## Workflow **${workflowName}** — Failed`,
264
+ '',
265
+ `${completed.length}/${outcomes.length} steps passed. Error: ${errorMsg}`,
266
+ '',
267
+ '### Steps',
268
+ ...completed.map((outcome) => `- **${outcome.name}** (${outcome.agent}) — passed`),
269
+ ...failed.map((outcome) => `- **${outcome.name}** (${outcome.agent}) — FAILED: ${outcome.error ?? 'unknown'}`),
270
+ ...skipped.map((outcome) => `- **${outcome.name}** — skipped`),
271
+ ];
272
+ this.postFn?.(lines.join('\n'));
273
+ }
274
+ }
275
+ //# sourceMappingURL=channel-messenger.js.map