@relayflows/core 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-handle.d.ts +27 -0
- package/dist/agent-handle.d.ts.map +1 -0
- package/dist/agent-handle.js +32 -0
- package/dist/agent-handle.js.map +1 -0
- package/dist/api-executor.d.ts +16 -0
- package/dist/api-executor.d.ts.map +1 -0
- package/dist/api-executor.js +94 -0
- package/dist/api-executor.js.map +1 -0
- package/dist/barrier.d.ts +72 -0
- package/dist/barrier.d.ts.map +1 -0
- package/dist/barrier.js +162 -0
- package/dist/barrier.js.map +1 -0
- package/dist/budget-tracker.d.ts +75 -0
- package/dist/budget-tracker.d.ts.map +1 -0
- package/dist/budget-tracker.js +184 -0
- package/dist/budget-tracker.js.map +1 -0
- package/dist/builder.d.ts +229 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +430 -0
- package/dist/builder.js.map +1 -0
- package/dist/builtin-templates/bug-fix.yaml +139 -0
- package/dist/builtin-templates/code-review.yaml +137 -0
- package/dist/builtin-templates/competitive.yaml +107 -0
- package/dist/builtin-templates/documentation.yaml +128 -0
- package/dist/builtin-templates/feature-dev.yaml +146 -0
- package/dist/builtin-templates/refactor.yaml +145 -0
- package/dist/builtin-templates/review-loop.yaml +227 -0
- package/dist/builtin-templates/security-audit.yaml +139 -0
- package/dist/channel-messenger.d.ts +28 -0
- package/dist/channel-messenger.d.ts.map +1 -0
- package/dist/channel-messenger.js +275 -0
- package/dist/channel-messenger.js.map +1 -0
- package/dist/cli-registry.d.ts +77 -0
- package/dist/cli-registry.d.ts.map +1 -0
- package/dist/cli-registry.js +268 -0
- package/dist/cli-registry.js.map +1 -0
- package/dist/cli-session-collector.d.ts +39 -0
- package/dist/cli-session-collector.d.ts.map +1 -0
- package/dist/cli-session-collector.js +23 -0
- package/dist/cli-session-collector.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +395 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud-runner.d.ts +15 -0
- package/dist/cloud-runner.d.ts.map +1 -0
- package/dist/cloud-runner.js +41 -0
- package/dist/cloud-runner.js.map +1 -0
- package/dist/cloud-schedules.d.ts +3 -0
- package/dist/cloud-schedules.d.ts.map +1 -0
- package/dist/cloud-schedules.js +2 -0
- package/dist/cloud-schedules.js.map +1 -0
- package/dist/collectors/claude.d.ts +6 -0
- package/dist/collectors/claude.d.ts.map +1 -0
- package/dist/collectors/claude.js +330 -0
- package/dist/collectors/claude.js.map +1 -0
- package/dist/collectors/codex.d.ts +18 -0
- package/dist/collectors/codex.d.ts.map +1 -0
- package/dist/collectors/codex.js +265 -0
- package/dist/collectors/codex.js.map +1 -0
- package/dist/collectors/opencode.d.ts +6 -0
- package/dist/collectors/opencode.d.ts.map +1 -0
- package/dist/collectors/opencode.js +204 -0
- package/dist/collectors/opencode.js.map +1 -0
- package/dist/coordinator.d.ts +73 -0
- package/dist/coordinator.d.ts.map +1 -0
- package/dist/coordinator.js +647 -0
- package/dist/coordinator.js.map +1 -0
- package/dist/custom-steps.d.ts +73 -0
- package/dist/custom-steps.d.ts.map +1 -0
- package/dist/custom-steps.js +321 -0
- package/dist/custom-steps.js.map +1 -0
- package/dist/default-logger.d.ts +9 -0
- package/dist/default-logger.d.ts.map +1 -0
- package/dist/default-logger.js +104 -0
- package/dist/default-logger.js.map +1 -0
- package/dist/dry-run-format.d.ts +6 -0
- package/dist/dry-run-format.d.ts.map +1 -0
- package/dist/dry-run-format.js +76 -0
- package/dist/dry-run-format.js.map +1 -0
- package/dist/file-db.d.ts +85 -0
- package/dist/file-db.d.ts.map +1 -0
- package/dist/file-db.js +215 -0
- package/dist/file-db.js.map +1 -0
- package/dist/index.d.ts +37 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -3
- package/dist/index.js.map +1 -0
- package/dist/integrations/browser.d.ts +99 -0
- package/dist/integrations/browser.d.ts.map +1 -0
- package/dist/integrations/browser.js +419 -0
- package/dist/integrations/browser.js.map +1 -0
- package/dist/integrations/github.d.ts +79 -0
- package/dist/integrations/github.d.ts.map +1 -0
- package/dist/integrations/github.js +459 -0
- package/dist/integrations/github.js.map +1 -0
- package/dist/integrations/slack.d.ts +80 -0
- package/dist/integrations/slack.d.ts.map +1 -0
- package/dist/integrations/slack.js +355 -0
- package/dist/integrations/slack.js.map +1 -0
- package/dist/listr-renderer.d.ts +26 -0
- package/dist/listr-renderer.d.ts.map +1 -0
- package/dist/listr-renderer.js +230 -0
- package/dist/listr-renderer.js.map +1 -0
- package/dist/memory-db.d.ts +17 -0
- package/dist/memory-db.d.ts.map +1 -0
- package/dist/memory-db.js +33 -0
- package/dist/memory-db.js.map +1 -0
- package/dist/process-backend-executor.d.ts +18 -0
- package/dist/process-backend-executor.d.ts.map +1 -0
- package/dist/process-backend-executor.js +74 -0
- package/dist/process-backend-executor.js.map +1 -0
- package/dist/process-spawner.d.ts +35 -0
- package/dist/process-spawner.d.ts.map +1 -0
- package/dist/process-spawner.js +173 -0
- package/dist/process-spawner.js.map +1 -0
- package/dist/provisioner.d.ts +64 -0
- package/dist/provisioner.d.ts.map +1 -0
- package/dist/provisioner.js +269 -0
- package/dist/provisioner.js.map +1 -0
- package/dist/proxy-env.d.ts +52 -0
- package/dist/proxy-env.d.ts.map +1 -0
- package/dist/proxy-env.js +92 -0
- package/dist/proxy-env.js.map +1 -0
- package/dist/run-script.d.ts +82 -0
- package/dist/run-script.d.ts.map +1 -0
- package/dist/run-script.js +527 -0
- package/dist/run-script.js.map +1 -0
- package/dist/run-summary-table.d.ts +5 -0
- package/dist/run-summary-table.d.ts.map +1 -0
- package/dist/run-summary-table.js +132 -0
- package/dist/run-summary-table.js.map +1 -0
- package/dist/run.d.ts +45 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +37 -0
- package/dist/run.js.map +1 -0
- package/dist/runner.d.ts +528 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +6269 -0
- package/dist/runner.js.map +1 -0
- package/dist/schema.d.ts +275 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +27 -0
- package/dist/schema.js.map +1 -0
- package/dist/schema.json +940 -0
- package/dist/sibling-links.d.ts +100 -0
- package/dist/sibling-links.d.ts.map +1 -0
- package/dist/sibling-links.js +205 -0
- package/dist/sibling-links.js.map +1 -0
- package/dist/state.d.ts +77 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +140 -0
- package/dist/state.js.map +1 -0
- package/dist/step-executor.d.ts +95 -0
- package/dist/step-executor.d.ts.map +1 -0
- package/dist/step-executor.js +393 -0
- package/dist/step-executor.js.map +1 -0
- package/dist/template-resolver.d.ts +33 -0
- package/dist/template-resolver.d.ts.map +1 -0
- package/dist/template-resolver.js +144 -0
- package/dist/template-resolver.js.map +1 -0
- package/dist/templates.d.ts +47 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +405 -0
- package/dist/templates.js.map +1 -0
- package/dist/trajectory.d.ts +87 -0
- package/dist/trajectory.d.ts.map +1 -0
- package/dist/trajectory.js +412 -0
- package/dist/trajectory.js.map +1 -0
- package/dist/types.d.ts +471 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +37 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +11 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +186 -0
- package/dist/validator.js.map +1 -0
- package/dist/verification.d.ts +53 -0
- package/dist/verification.d.ts.map +1 -0
- package/dist/verification.js +238 -0
- package/dist/verification.js.map +1 -0
- 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
|