@renseiai/agentfactory-linear 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +91 -0
  3. package/dist/src/agent-client-project-repo.test.d.ts +2 -0
  4. package/dist/src/agent-client-project-repo.test.d.ts.map +1 -0
  5. package/dist/src/agent-client-project-repo.test.js +153 -0
  6. package/dist/src/agent-client.d.ts +261 -0
  7. package/dist/src/agent-client.d.ts.map +1 -0
  8. package/dist/src/agent-client.js +902 -0
  9. package/dist/src/agent-session.d.ts +303 -0
  10. package/dist/src/agent-session.d.ts.map +1 -0
  11. package/dist/src/agent-session.js +969 -0
  12. package/dist/src/checkbox-utils.d.ts +88 -0
  13. package/dist/src/checkbox-utils.d.ts.map +1 -0
  14. package/dist/src/checkbox-utils.js +120 -0
  15. package/dist/src/circuit-breaker.d.ts +76 -0
  16. package/dist/src/circuit-breaker.d.ts.map +1 -0
  17. package/dist/src/circuit-breaker.js +229 -0
  18. package/dist/src/circuit-breaker.test.d.ts +2 -0
  19. package/dist/src/circuit-breaker.test.d.ts.map +1 -0
  20. package/dist/src/circuit-breaker.test.js +292 -0
  21. package/dist/src/constants.d.ts +87 -0
  22. package/dist/src/constants.d.ts.map +1 -0
  23. package/dist/src/constants.js +101 -0
  24. package/dist/src/defaults/auto-trigger.d.ts +35 -0
  25. package/dist/src/defaults/auto-trigger.d.ts.map +1 -0
  26. package/dist/src/defaults/auto-trigger.js +36 -0
  27. package/dist/src/defaults/index.d.ts +12 -0
  28. package/dist/src/defaults/index.d.ts.map +1 -0
  29. package/dist/src/defaults/index.js +11 -0
  30. package/dist/src/defaults/priority.d.ts +20 -0
  31. package/dist/src/defaults/priority.d.ts.map +1 -0
  32. package/dist/src/defaults/priority.js +37 -0
  33. package/dist/src/defaults/prompts.d.ts +42 -0
  34. package/dist/src/defaults/prompts.d.ts.map +1 -0
  35. package/dist/src/defaults/prompts.js +310 -0
  36. package/dist/src/defaults/prompts.test.d.ts +2 -0
  37. package/dist/src/defaults/prompts.test.d.ts.map +1 -0
  38. package/dist/src/defaults/prompts.test.js +263 -0
  39. package/dist/src/defaults/work-type-detection.d.ts +19 -0
  40. package/dist/src/defaults/work-type-detection.d.ts.map +1 -0
  41. package/dist/src/defaults/work-type-detection.js +93 -0
  42. package/dist/src/errors.d.ts +91 -0
  43. package/dist/src/errors.d.ts.map +1 -0
  44. package/dist/src/errors.js +173 -0
  45. package/dist/src/frontend-adapter.d.ts +168 -0
  46. package/dist/src/frontend-adapter.d.ts.map +1 -0
  47. package/dist/src/frontend-adapter.js +314 -0
  48. package/dist/src/frontend-adapter.test.d.ts +2 -0
  49. package/dist/src/frontend-adapter.test.d.ts.map +1 -0
  50. package/dist/src/frontend-adapter.test.js +545 -0
  51. package/dist/src/index.d.ts +28 -0
  52. package/dist/src/index.d.ts.map +1 -0
  53. package/dist/src/index.js +30 -0
  54. package/dist/src/issue-tracker-proxy.d.ts +140 -0
  55. package/dist/src/issue-tracker-proxy.d.ts.map +1 -0
  56. package/dist/src/issue-tracker-proxy.js +10 -0
  57. package/dist/src/platform-adapter.d.ts +132 -0
  58. package/dist/src/platform-adapter.d.ts.map +1 -0
  59. package/dist/src/platform-adapter.js +260 -0
  60. package/dist/src/platform-adapter.test.d.ts +2 -0
  61. package/dist/src/platform-adapter.test.d.ts.map +1 -0
  62. package/dist/src/platform-adapter.test.js +468 -0
  63. package/dist/src/proxy-client.d.ts +103 -0
  64. package/dist/src/proxy-client.d.ts.map +1 -0
  65. package/dist/src/proxy-client.js +191 -0
  66. package/dist/src/rate-limiter.d.ts +64 -0
  67. package/dist/src/rate-limiter.d.ts.map +1 -0
  68. package/dist/src/rate-limiter.js +163 -0
  69. package/dist/src/rate-limiter.test.d.ts +2 -0
  70. package/dist/src/rate-limiter.test.d.ts.map +1 -0
  71. package/dist/src/rate-limiter.test.js +217 -0
  72. package/dist/src/retry.d.ts +59 -0
  73. package/dist/src/retry.d.ts.map +1 -0
  74. package/dist/src/retry.js +82 -0
  75. package/dist/src/types.d.ts +492 -0
  76. package/dist/src/types.d.ts.map +1 -0
  77. package/dist/src/types.js +143 -0
  78. package/dist/src/utils.d.ts +52 -0
  79. package/dist/src/utils.d.ts.map +1 -0
  80. package/dist/src/utils.js +277 -0
  81. package/dist/src/webhook-types.d.ts +308 -0
  82. package/dist/src/webhook-types.d.ts.map +1 -0
  83. package/dist/src/webhook-types.js +46 -0
  84. package/package.json +70 -0
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Default prompt templates for each work type.
3
+ *
4
+ * These provide sensible defaults that can be overridden by consumers.
5
+ * The Rensei project overrides these with its own prompts.ts.
6
+ */
7
+ import type { AgentWorkType, SubIssueStatus } from '../types.js';
8
+ export declare const WORK_RESULT_MARKER_INSTRUCTION = "\n\nMANDATORY \u2014 Structured Result Marker:\nYou MUST include exactly one of these HTML comment markers in your final output:\n- On pass: <!-- WORK_RESULT:passed -->\n- On fail: <!-- WORK_RESULT:failed -->\nWithout this marker, the orchestrator CANNOT detect your result and the issue status will NOT be updated. Even if you encounter errors, always emit <!-- WORK_RESULT:failed -->.";
9
+ export declare const READ_ONLY_CONSTRAINT = "\n\nCRITICAL CONSTRAINT \u2014 READ-ONLY ROLE:\nYou are a VALIDATION agent, NOT a development agent. You MUST NOT modify any source code, configuration files, migration files, or project files. Your role is strictly to READ, VALIDATE, and REPORT.\nFORBIDDEN actions: creating files, editing files, writing code, committing changes, patching snapshots, fixing bugs, resolving errors in code.\nALLOWED actions: reading files, running tests, running builds, checking CI status, posting comments, merging PRs (acceptance only), updating Linear status.\nIf you discover issues (missing files, broken builds, failing tests), REPORT them in your result comment and emit WORK_RESULT:failed. Do NOT attempt to fix them.";
10
+ export declare const PR_SELECTION_GUIDANCE = "\n\nPR Selection (Multi-PR Handling):\nIssues may have multiple PRs. Select the correct one:\n1. Check linked PRs in the issue attachments/links for GitHub PR URLs\n2. Filter by state \u2014 prefer OPEN over MERGED over CLOSED: gh pr view NNN --json state\n3. If multiple OPEN PRs, pick the most recently created one\n4. Fallback search by branch: gh pr list --head \"$(git branch --show-current)\" --state open\n5. Last resort search by issue ID: gh pr list --state open --search \"[issue-id]\"\n6. If no PR found, emit WORK_RESULT:failed with explanation";
11
+ /**
12
+ * Context from the workflow state machine for retry enrichment.
13
+ * Injected when an issue has been through previous dev-QA-rejected cycles.
14
+ */
15
+ export interface WorkflowContext {
16
+ cycleCount: number;
17
+ strategy: string;
18
+ failureSummary: string | null;
19
+ qaAttemptCount?: number;
20
+ }
21
+ /**
22
+ * Build the failure context block to append to prompts for retries.
23
+ */
24
+ export declare function buildFailureContextBlock(workType: AgentWorkType, context: WorkflowContext): string;
25
+ /**
26
+ * Generate a default prompt for a given work type and issue identifier.
27
+ *
28
+ * @param identifier - The issue identifier (e.g., "PROJ-123")
29
+ * @param workType - The type of work to perform
30
+ * @param mentionContext - Optional additional context from a user mention
31
+ * @param workflowContext - Optional workflow state context for retry enrichment
32
+ */
33
+ export declare function defaultGeneratePrompt(identifier: string, workType: AgentWorkType, mentionContext?: string, workflowContext?: WorkflowContext): string;
34
+ /**
35
+ * Build default QA context for parent issues with sub-issues.
36
+ */
37
+ export declare function defaultBuildParentQAContext(issueIdentifier: string, subIssueStatuses: SubIssueStatus[]): string;
38
+ /**
39
+ * Build default acceptance context for parent issues with sub-issues.
40
+ */
41
+ export declare function defaultBuildParentAcceptanceContext(issueIdentifier: string, subIssueStatuses: SubIssueStatus[]): string;
42
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/defaults/prompts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAahE,eAAO,MAAM,8BAA8B,uYAMsI,CAAA;AAEjL,eAAO,MAAM,oBAAoB,2sBAMiI,CAAA;AAElK,eAAO,MAAM,qBAAqB,ijBAS0B,CAAA;AAE5D;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,eAAe,GACvB,MAAM,CA0DR;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,aAAa,EACvB,cAAc,CAAC,EAAE,MAAM,EACvB,eAAe,CAAC,EAAE,eAAe,GAChC,MAAM,CAgKR;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,eAAe,EAAE,MAAM,EACvB,gBAAgB,EAAE,cAAc,EAAE,GACjC,MAAM,CAoBR;AAED;;GAEG;AACH,wBAAgB,mCAAmC,CACjD,eAAe,EAAE,MAAM,EACvB,gBAAgB,EAAE,cAAc,EAAE,GACjC,MAAM,CAmBR"}
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Default prompt templates for each work type.
3
+ *
4
+ * These provide sensible defaults that can be overridden by consumers.
5
+ * The Rensei project overrides these with its own prompts.ts.
6
+ */
7
+ const HUMAN_BLOCKER_INSTRUCTION = `
8
+
9
+ HUMAN-NEEDED BLOCKERS:
10
+ If you encounter work that requires human action and cannot be resolved autonomously
11
+ (e.g., missing API keys/credentials, infrastructure not provisioned, third-party onboarding,
12
+ manual setup steps, policy decisions, access permissions), create a blocker issue:
13
+ pnpm af-linear create-blocker <SOURCE-ISSUE-ID> --title "What human needs to do" --description "Detailed steps"
14
+ This creates a tracked issue in Icebox with 'Needs Human' label, linked as blocking the source issue.
15
+ Do NOT silently skip human-needed work or bury it in comments.
16
+ Only create blockers for things that genuinely require a human — not for things you can retry or work around.`;
17
+ export const WORK_RESULT_MARKER_INSTRUCTION = `
18
+
19
+ MANDATORY — Structured Result Marker:
20
+ You MUST include exactly one of these HTML comment markers in your final output:
21
+ - On pass: <!-- WORK_RESULT:passed -->
22
+ - On fail: <!-- WORK_RESULT:failed -->
23
+ Without this marker, the orchestrator CANNOT detect your result and the issue status will NOT be updated. Even if you encounter errors, always emit <!-- WORK_RESULT:failed -->.`;
24
+ export const READ_ONLY_CONSTRAINT = `
25
+
26
+ CRITICAL CONSTRAINT — READ-ONLY ROLE:
27
+ You are a VALIDATION agent, NOT a development agent. You MUST NOT modify any source code, configuration files, migration files, or project files. Your role is strictly to READ, VALIDATE, and REPORT.
28
+ FORBIDDEN actions: creating files, editing files, writing code, committing changes, patching snapshots, fixing bugs, resolving errors in code.
29
+ ALLOWED actions: reading files, running tests, running builds, checking CI status, posting comments, merging PRs (acceptance only), updating Linear status.
30
+ If you discover issues (missing files, broken builds, failing tests), REPORT them in your result comment and emit WORK_RESULT:failed. Do NOT attempt to fix them.`;
31
+ export const PR_SELECTION_GUIDANCE = `
32
+
33
+ PR Selection (Multi-PR Handling):
34
+ Issues may have multiple PRs. Select the correct one:
35
+ 1. Check linked PRs in the issue attachments/links for GitHub PR URLs
36
+ 2. Filter by state — prefer OPEN over MERGED over CLOSED: gh pr view NNN --json state
37
+ 3. If multiple OPEN PRs, pick the most recently created one
38
+ 4. Fallback search by branch: gh pr list --head "$(git branch --show-current)" --state open
39
+ 5. Last resort search by issue ID: gh pr list --state open --search "[issue-id]"
40
+ 6. If no PR found, emit WORK_RESULT:failed with explanation`;
41
+ /**
42
+ * Build the failure context block to append to prompts for retries.
43
+ */
44
+ export function buildFailureContextBlock(workType, context) {
45
+ if (context.cycleCount <= 0)
46
+ return '';
47
+ switch (workType) {
48
+ case 'refinement': {
49
+ if (context.strategy === 'decompose') {
50
+ return `\n\n## Decomposition Required (Cycle ${context.cycleCount})
51
+
52
+ This issue has been through ${context.cycleCount} development-QA cycle(s) and keeps failing.
53
+ Instead of refining, DECOMPOSE this issue into smaller, independently testable pieces.
54
+
55
+ ### Failure History
56
+ ${context.failureSummary ?? 'No details recorded.'}
57
+
58
+ ### Decomposition Instructions
59
+ - Break this issue into smaller sub-issues (use --parentId to make them children)
60
+ - Each sub-issue must have clear, unambiguous acceptance criteria
61
+ - Each sub-issue must be testable in isolation
62
+ - Address one specific concern that previous attempts failed on
63
+ - After creating sub-issues, keep the PARENT issue in Icebox for human review`;
64
+ }
65
+ return `\n\n## Previous Failure Context
66
+
67
+ This issue has been through ${context.cycleCount} development-QA cycle(s).
68
+
69
+ ### Failure History
70
+ ${context.failureSummary ?? 'No details recorded.'}
71
+
72
+ ### Instructions
73
+ - Read the failure history carefully before making changes
74
+ - Do NOT repeat approaches that already failed
75
+ - If the acceptance criteria are ambiguous, update them to be testable before fixing code
76
+ - Focus on the ROOT CAUSE, not symptoms`;
77
+ }
78
+ case 'development':
79
+ case 'coordination': {
80
+ return `\n\n## Retry Context
81
+
82
+ This is retry #${context.cycleCount} for this issue. Previous QA failures:
83
+ ${context.failureSummary ?? 'No details recorded.'}
84
+
85
+ Pay special attention to the areas that failed QA previously.`;
86
+ }
87
+ case 'qa':
88
+ case 'qa-coordination': {
89
+ if (!context.failureSummary)
90
+ return '';
91
+ return `\n\n## Previous QA Results
92
+ This issue has been QA'd ${context.qaAttemptCount ?? context.cycleCount} times previously.
93
+ ${context.failureSummary}
94
+ Focus validation on these previously failing areas.`;
95
+ }
96
+ default:
97
+ return '';
98
+ }
99
+ }
100
+ /**
101
+ * Generate a default prompt for a given work type and issue identifier.
102
+ *
103
+ * @param identifier - The issue identifier (e.g., "PROJ-123")
104
+ * @param workType - The type of work to perform
105
+ * @param mentionContext - Optional additional context from a user mention
106
+ * @param workflowContext - Optional workflow state context for retry enrichment
107
+ */
108
+ export function defaultGeneratePrompt(identifier, workType, mentionContext, workflowContext) {
109
+ let basePrompt;
110
+ switch (workType) {
111
+ case 'research':
112
+ basePrompt = `Research and flesh out story ${identifier}. Analyze requirements, identify technical approach, estimate complexity, and update the story description with detailed acceptance criteria. Do NOT implement code.`;
113
+ break;
114
+ case 'backlog-creation':
115
+ basePrompt = `Create backlog issues from the researched story ${identifier}.
116
+ Read the issue description, identify distinct work items, classify each as bug/feature/chore,
117
+ and create appropriately scoped issues in Icebox status (so a human can review before moving to Backlog).
118
+ Choose the correct issue structure based on the work:
119
+ - Sub-issues (--parentId): When work is a single concern with sequential/parallel phases sharing context and dependencies.
120
+ - Independent issues (--type related): When items are unrelated work in different codebase areas with no shared context.
121
+ - Single issue rewrite: When scope is atomic (single concern, few files, no phases). Rewrite source in-place, keep in Icebox.
122
+ When creating multiple issues, always add "related" links between them AND blocking relations where one step depends on another.
123
+ Do NOT wait for user approval - create issues automatically.`;
124
+ break;
125
+ case 'development':
126
+ basePrompt = `Start work on ${identifier}. Implement the feature/fix as specified.`;
127
+ break;
128
+ case 'inflight':
129
+ basePrompt = `Continue work on ${identifier}. Resume where you left off.`;
130
+ break;
131
+ case 'qa':
132
+ basePrompt = `QA ${identifier}. Validate the implementation against acceptance criteria.
133
+ ${READ_ONLY_CONSTRAINT}
134
+ ${WORK_RESULT_MARKER_INSTRUCTION}
135
+ ${PR_SELECTION_GUIDANCE}
136
+
137
+ Validation Steps:
138
+ 1. Find and validate the correct PR (see PR selection above)
139
+ 2. Run tests scoped to the affected packages
140
+ 3. Verify the build passes
141
+ 4. Check deployment status (CI checks on the PR)
142
+ 5. Review changes against issue requirements
143
+ 6. Post result comment with the structured marker`;
144
+ break;
145
+ case 'acceptance':
146
+ basePrompt = `Process acceptance for ${identifier}. Validate development and QA work is complete, verify PR is ready to merge (CI passing, no conflicts), merge the PR, and clean up local resources.
147
+ ${READ_ONLY_CONSTRAINT}
148
+ ${WORK_RESULT_MARKER_INSTRUCTION}
149
+ ${PR_SELECTION_GUIDANCE}
150
+
151
+ Acceptance Steps:
152
+ 1. Find and validate the correct PR (see PR selection above)
153
+ 2. Verify CI is passing and there are no merge conflicts
154
+ 3. Confirm QA has passed (check issue status or QA comments)
155
+ 4. Merge the PR
156
+ 5. Delete the remote branch after successful merge
157
+ 6. Post result comment with the structured marker`;
158
+ break;
159
+ case 'refinement':
160
+ basePrompt = `Refine ${identifier} based on rejection feedback. Read comments, update requirements, then return to Backlog.`;
161
+ break;
162
+ case 'coordination': {
163
+ const isRetry = workflowContext && workflowContext.cycleCount > 0;
164
+ if (isRetry) {
165
+ basePrompt = `Fix issues found during QA for parent issue ${identifier}.
166
+
167
+ REWORK MODE — DO NOT re-coordinate sub-issues from scratch.
168
+ All sub-issues are already Finished and a PR already exists. QA failed and specific fixes are needed.
169
+
170
+ MANDATORY FIRST STEPS:
171
+ 1. Read the most recent QA failure comments: pnpm af-linear list-comments ${identifier}
172
+ 2. Identify the SPECIFIC fixes needed from the QA failure details below
173
+ 3. Apply fixes directly — do NOT re-spawn sub-agents for already-complete work
174
+ 4. Commit fixes, push to the existing PR branch
175
+ 5. Run full validation: pnpm typecheck && pnpm build && pnpm test
176
+ 6. Update parent issue status to Finished
177
+
178
+ COMMON REWORK FIXES:
179
+ - Missing migration .json snapshots: Find .ts migrations without .json, patch the latest snapshot
180
+ - TypeScript errors: Read the error details, fix the type issues
181
+ - Missing API fields: Update route handlers to include missing fields
182
+ - Build failures: Run pnpm build, diagnose, fix
183
+
184
+ If the existing PR branch is checked out, work directly on it. Do not create a new branch or PR.`;
185
+ }
186
+ else {
187
+ basePrompt = `Coordinate sub-issue execution for parent issue ${identifier}. Fetch sub-issues with dependency graph, create tasks mapping to each sub-issue, spawn sub-agents for unblocked sub-issues in parallel, monitor completion, and create a single PR with all changes when done.
188
+
189
+ SUB-ISSUE STATUS MANAGEMENT:
190
+ Update sub-issue statuses in Linear as work progresses:
191
+ - When starting work on a sub-issue: update status to Started
192
+ - When a sub-agent completes a sub-issue: update status to Finished
193
+ - If a sub-agent fails: add a comment explaining the failure
194
+
195
+ COMPLETION VERIFICATION:
196
+ Before marking the parent issue as complete, verify ALL sub-issues are in Finished status.
197
+ If any sub-issue is not Finished, report the failure and do not mark the parent as complete.`;
198
+ }
199
+ break;
200
+ }
201
+ case 'qa-coordination':
202
+ basePrompt = `Coordinate QA across sub-issues for parent issue ${identifier}. Fetch sub-issues, validate each against acceptance criteria, collect pass/fail results, and roll up to parent.
203
+ ${READ_ONLY_CONSTRAINT}
204
+ ${WORK_RESULT_MARKER_INSTRUCTION}
205
+ ${PR_SELECTION_GUIDANCE}
206
+
207
+ QA Coordination Steps:
208
+ 1. Find and validate the correct PR (see PR selection above)
209
+ 2. Fetch all sub-issues and verify each is in Finished or later status
210
+ 3. Run tests scoped to the affected packages
211
+ 4. Verify the build passes (pnpm typecheck && pnpm build)
212
+ 5. Review changes against each sub-issue's acceptance criteria
213
+ 6. Verify cross-cutting concerns: shared types, API contracts, data flow between sub-issues
214
+ 7. Check deployment status (CI checks on the PR)
215
+
216
+ Pass/Fail:
217
+ - PASS (emit <!-- WORK_RESULT:passed -->): ALL tests pass, build succeeds, all sub-issues implemented, deployment healthy
218
+ - FAIL (emit <!-- WORK_RESULT:failed -->): ANY test failure, build error, missing implementation, deployment failure
219
+ Post a result comment listing per-sub-issue findings, then emit the marker.`;
220
+ break;
221
+ case 'acceptance-coordination':
222
+ basePrompt = `Coordinate acceptance across sub-issues for parent issue ${identifier}. Verify all sub-issues are Delivered, validate the PR, merge it, and bulk-update sub-issues to Accepted.
223
+ ${READ_ONLY_CONSTRAINT}
224
+ ${WORK_RESULT_MARKER_INSTRUCTION}
225
+ ${PR_SELECTION_GUIDANCE}
226
+
227
+ Acceptance Coordination Steps:
228
+ 1. Find and validate the correct PR (see PR selection above)
229
+ 2. Verify ALL sub-issues are in Delivered or Accepted status
230
+ 3. Verify CI is passing and there are no merge conflicts
231
+ 4. Merge the PR
232
+ 5. Delete the remote branch after successful merge
233
+ 6. Post result comment with per-sub-issue status, then emit the marker
234
+
235
+ Pass/Fail:
236
+ - PASS (emit <!-- WORK_RESULT:passed -->): All sub-issues Delivered, CI passing, PR merged successfully
237
+ - FAIL (emit <!-- WORK_RESULT:failed -->): Incomplete sub-issues, CI failure, merge conflicts, merge failed
238
+ If ANY issue prevents merging, do NOT attempt to fix it — emit WORK_RESULT:failed with details.`;
239
+ break;
240
+ case 'refinement-coordination':
241
+ basePrompt = `Coordinate refinement across sub-issues for parent issue ${identifier}.
242
+ Read the QA/acceptance failure comments to identify which sub-issues failed and why.
243
+ For each failing sub-issue, update its description with the specific failure feedback and move it back to Backlog.
244
+ Leave passing sub-issues in their current state — do not re-run them.
245
+ Once failing sub-issues are triaged, the orchestrator will move the parent to Backlog for re-coordination.
246
+
247
+ Refinement Coordination Steps:
248
+ 1. Read comments on ${identifier} to find the QA/acceptance failure report
249
+ 2. Fetch sub-issues: pnpm af-linear list-sub-issues ${identifier}
250
+ 3. For each failing sub-issue: update description with failure details, move to Backlog
251
+ 4. Leave passing sub-issues unchanged
252
+
253
+ IMPORTANT: Do NOT implement fixes yourself — only triage and route feedback to the correct sub-issues.`;
254
+ break;
255
+ }
256
+ basePrompt += HUMAN_BLOCKER_INSTRUCTION;
257
+ // Inject workflow failure context for retries
258
+ if (workflowContext) {
259
+ basePrompt += buildFailureContextBlock(workType, workflowContext);
260
+ }
261
+ if (mentionContext) {
262
+ return `${basePrompt}\n\nAdditional context from the user's mention:\n${mentionContext}`;
263
+ }
264
+ return basePrompt;
265
+ }
266
+ /**
267
+ * Build default QA context for parent issues with sub-issues.
268
+ */
269
+ export function defaultBuildParentQAContext(issueIdentifier, subIssueStatuses) {
270
+ const subIssueList = subIssueStatuses
271
+ .map(s => `- ${s.identifier}: ${s.title} (Status: ${s.status})`)
272
+ .join('\n');
273
+ return `QA ${issueIdentifier} (parent issue with ${subIssueStatuses.length} sub-issues).
274
+
275
+ ## Sub-Issues
276
+ ${subIssueList}
277
+
278
+ ## Holistic QA Instructions
279
+ This is a parent issue whose work was coordinated across multiple sub-issues.
280
+ Perform holistic validation beyond individual sub-issue checks:
281
+
282
+ 1. **Scope Coverage**: Read each sub-issue description and verify the PR includes implementation for ALL sub-issues.
283
+ 2. **Integration Validation**: Check that shared types, API contracts, and data flow between sub-issue implementations are consistent and correct.
284
+ 3. **Cross-Cutting Concerns**: Verify consistent error handling, auth patterns, naming conventions, and no orphaned/dead code across all sub-issue changes.
285
+ 4. **Sub-Issue Status**: All sub-issues must be in Finished, Delivered, or Accepted status.
286
+
287
+ Validate the implementation against the parent issue's acceptance criteria as a whole, not just each sub-issue in isolation.`;
288
+ }
289
+ /**
290
+ * Build default acceptance context for parent issues with sub-issues.
291
+ */
292
+ export function defaultBuildParentAcceptanceContext(issueIdentifier, subIssueStatuses) {
293
+ const subIssueList = subIssueStatuses
294
+ .map(s => `- ${s.identifier}: ${s.title} (Status: ${s.status})`)
295
+ .join('\n');
296
+ return `Process acceptance for ${issueIdentifier} (parent issue with ${subIssueStatuses.length} sub-issues).
297
+
298
+ ## Sub-Issues
299
+ ${subIssueList}
300
+
301
+ ## Parent Issue Acceptance Requirements
302
+ This is a parent issue with coordinated sub-issues. Before merging:
303
+
304
+ 1. **Sub-Issue Status**: ALL sub-issues must be in **Delivered** or **Accepted** status.
305
+ 2. **PR Completeness**: The single PR should contain changes for all sub-issues.
306
+ 3. **CI/Deployment**: Verify the combined PR passes CI and deploys successfully.
307
+
308
+ Validate development and QA work is complete, verify PR is ready to merge (CI passing, no conflicts), merge the PR.
309
+ After merge succeeds, delete the remote branch.`;
310
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=prompts.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.test.d.ts","sourceRoot":"","sources":["../../../src/defaults/prompts.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,263 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildFailureContextBlock, defaultGeneratePrompt } from './prompts.js';
3
+ describe('buildFailureContextBlock', () => {
4
+ const baseContext = {
5
+ cycleCount: 2,
6
+ strategy: 'context-enriched',
7
+ failureSummary: '--- Cycle 1, qa (2024-01-01) ---\nTests failed: TypeError in UserService',
8
+ };
9
+ describe('refinement work type', () => {
10
+ it('returns empty string for cycleCount 0', () => {
11
+ expect(buildFailureContextBlock('refinement', { ...baseContext, cycleCount: 0 })).toBe('');
12
+ });
13
+ it('includes failure history for cycle 1+', () => {
14
+ const result = buildFailureContextBlock('refinement', baseContext);
15
+ expect(result).toContain('Previous Failure Context');
16
+ expect(result).toContain('2 development-QA cycle(s)');
17
+ expect(result).toContain('TypeError in UserService');
18
+ expect(result).toContain('Do NOT repeat approaches that already failed');
19
+ });
20
+ it('includes decomposition instructions for decompose strategy', () => {
21
+ const decomposeCtx = {
22
+ ...baseContext,
23
+ cycleCount: 3,
24
+ strategy: 'decompose',
25
+ };
26
+ const result = buildFailureContextBlock('refinement', decomposeCtx);
27
+ expect(result).toContain('Decomposition Required');
28
+ expect(result).toContain('DECOMPOSE this issue');
29
+ expect(result).toContain('smaller sub-issues');
30
+ expect(result).not.toContain('Previous Failure Context');
31
+ });
32
+ it('handles null failure summary gracefully', () => {
33
+ const result = buildFailureContextBlock('refinement', { ...baseContext, failureSummary: null });
34
+ expect(result).toContain('No details recorded');
35
+ });
36
+ });
37
+ describe('development work type', () => {
38
+ it('returns empty string for cycleCount 0', () => {
39
+ expect(buildFailureContextBlock('development', { ...baseContext, cycleCount: 0 })).toBe('');
40
+ });
41
+ it('includes retry context for cycle 1+', () => {
42
+ const result = buildFailureContextBlock('development', baseContext);
43
+ expect(result).toContain('Retry Context');
44
+ expect(result).toContain('retry #2');
45
+ expect(result).toContain('TypeError in UserService');
46
+ });
47
+ });
48
+ describe('coordination work type', () => {
49
+ it('includes retry context same as development', () => {
50
+ const result = buildFailureContextBlock('coordination', baseContext);
51
+ expect(result).toContain('Retry Context');
52
+ expect(result).toContain('retry #2');
53
+ });
54
+ });
55
+ describe('qa-coordination work type', () => {
56
+ it('returns empty string when no failure summary', () => {
57
+ expect(buildFailureContextBlock('qa-coordination', { ...baseContext, failureSummary: null })).toBe('');
58
+ });
59
+ it('includes previous QA results when failure summary exists', () => {
60
+ const result = buildFailureContextBlock('qa-coordination', baseContext);
61
+ expect(result).toContain('Previous QA Results');
62
+ expect(result).toContain('TypeError in UserService');
63
+ });
64
+ });
65
+ describe('qa work type', () => {
66
+ it('returns empty string when no failure summary', () => {
67
+ expect(buildFailureContextBlock('qa', { ...baseContext, failureSummary: null })).toBe('');
68
+ });
69
+ it('includes previous QA results when failure summary exists', () => {
70
+ const qaCtx = {
71
+ ...baseContext,
72
+ qaAttemptCount: 2,
73
+ };
74
+ const result = buildFailureContextBlock('qa', qaCtx);
75
+ expect(result).toContain('Previous QA Results');
76
+ expect(result).toContain('QA\'d 2 times previously');
77
+ expect(result).toContain('TypeError in UserService');
78
+ });
79
+ it('falls back to cycleCount when qaAttemptCount not provided', () => {
80
+ const result = buildFailureContextBlock('qa', baseContext);
81
+ expect(result).toContain('QA\'d 2 times previously');
82
+ });
83
+ });
84
+ describe('other work types', () => {
85
+ it('returns empty string for acceptance', () => {
86
+ expect(buildFailureContextBlock('acceptance', baseContext)).toBe('');
87
+ });
88
+ it('returns empty string for research', () => {
89
+ expect(buildFailureContextBlock('research', baseContext)).toBe('');
90
+ });
91
+ it('returns empty string for backlog-creation', () => {
92
+ expect(buildFailureContextBlock('backlog-creation', baseContext)).toBe('');
93
+ });
94
+ });
95
+ });
96
+ describe('defaultGeneratePrompt with workflowContext', () => {
97
+ it('does not modify prompt when workflowContext is undefined', () => {
98
+ const withoutCtx = defaultGeneratePrompt('PROJ-123', 'development');
99
+ const withUndefined = defaultGeneratePrompt('PROJ-123', 'development', undefined, undefined);
100
+ expect(withoutCtx).toBe(withUndefined);
101
+ });
102
+ it('does not modify prompt when cycleCount is 0', () => {
103
+ const withoutCtx = defaultGeneratePrompt('PROJ-123', 'development');
104
+ const withZero = defaultGeneratePrompt('PROJ-123', 'development', undefined, {
105
+ cycleCount: 0,
106
+ strategy: 'normal',
107
+ failureSummary: null,
108
+ });
109
+ expect(withoutCtx).toBe(withZero);
110
+ });
111
+ it('enriches refinement prompt with failure context', () => {
112
+ const result = defaultGeneratePrompt('PROJ-123', 'refinement', undefined, {
113
+ cycleCount: 2,
114
+ strategy: 'context-enriched',
115
+ failureSummary: 'Tests failed in UserService',
116
+ });
117
+ expect(result).toContain('Refine PROJ-123');
118
+ expect(result).toContain('Previous Failure Context');
119
+ expect(result).toContain('Tests failed in UserService');
120
+ });
121
+ it('enriches development prompt with retry context', () => {
122
+ const result = defaultGeneratePrompt('PROJ-123', 'development', undefined, {
123
+ cycleCount: 1,
124
+ strategy: 'normal',
125
+ failureSummary: 'Build error in core package',
126
+ });
127
+ expect(result).toContain('Start work on PROJ-123');
128
+ expect(result).toContain('Retry Context');
129
+ expect(result).toContain('Build error in core package');
130
+ });
131
+ it('preserves mentionContext alongside workflowContext', () => {
132
+ const result = defaultGeneratePrompt('PROJ-123', 'development', 'Please focus on the API layer', {
133
+ cycleCount: 1,
134
+ strategy: 'normal',
135
+ failureSummary: 'API tests failing',
136
+ });
137
+ expect(result).toContain('Retry Context');
138
+ expect(result).toContain('Please focus on the API layer');
139
+ });
140
+ });
141
+ describe('defaultGeneratePrompt read-only constraint', () => {
142
+ const readOnlyWorkTypes = ['qa', 'acceptance', 'qa-coordination', 'acceptance-coordination'];
143
+ for (const workType of readOnlyWorkTypes) {
144
+ it(`includes READ-ONLY constraint for ${workType}`, () => {
145
+ const result = defaultGeneratePrompt('PROJ-123', workType);
146
+ expect(result).toContain('READ-ONLY ROLE');
147
+ expect(result).toContain('MUST NOT modify any source code');
148
+ expect(result).toContain('WORK_RESULT:failed');
149
+ });
150
+ }
151
+ const writableWorkTypes = ['development', 'coordination', 'refinement', 'research', 'backlog-creation', 'inflight'];
152
+ for (const workType of writableWorkTypes) {
153
+ it(`does NOT include READ-ONLY constraint for ${workType}`, () => {
154
+ const result = defaultGeneratePrompt('PROJ-123', workType);
155
+ expect(result).not.toContain('READ-ONLY ROLE');
156
+ });
157
+ }
158
+ });
159
+ describe('defaultGeneratePrompt coordination prompts have steps', () => {
160
+ it('qa-coordination includes numbered steps and pass/fail criteria', () => {
161
+ const result = defaultGeneratePrompt('PROJ-100', 'qa-coordination');
162
+ expect(result).toContain('QA Coordination Steps:');
163
+ expect(result).toContain('1. Find and validate the correct PR');
164
+ expect(result).toContain('Pass/Fail:');
165
+ expect(result).toContain('WORK_RESULT:passed');
166
+ expect(result).toContain('WORK_RESULT:failed');
167
+ expect(result).toContain('PR Selection');
168
+ });
169
+ it('acceptance-coordination includes numbered steps and pass/fail criteria', () => {
170
+ const result = defaultGeneratePrompt('PROJ-100', 'acceptance-coordination');
171
+ expect(result).toContain('Acceptance Coordination Steps:');
172
+ expect(result).toContain('1. Find and validate the correct PR');
173
+ expect(result).toContain('Merge the PR');
174
+ expect(result).toContain('Pass/Fail:');
175
+ expect(result).toContain('WORK_RESULT:passed');
176
+ expect(result).toContain('WORK_RESULT:failed');
177
+ expect(result).toContain('do NOT attempt to fix it');
178
+ expect(result).toContain('PR Selection');
179
+ });
180
+ });
181
+ describe('defaultGeneratePrompt coordination retry', () => {
182
+ it('uses fresh coordination prompt when no workflowContext', () => {
183
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination');
184
+ expect(result).toContain('Coordinate sub-issue execution for parent issue PROJ-100');
185
+ expect(result).toContain('Fetch sub-issues with dependency graph');
186
+ expect(result).not.toContain('REWORK MODE');
187
+ });
188
+ it('uses fresh coordination prompt when cycleCount is 0', () => {
189
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination', undefined, {
190
+ cycleCount: 0,
191
+ strategy: 'normal',
192
+ failureSummary: null,
193
+ });
194
+ expect(result).toContain('Coordinate sub-issue execution for parent issue PROJ-100');
195
+ expect(result).not.toContain('REWORK MODE');
196
+ });
197
+ it('switches to rework mode when cycleCount > 0', () => {
198
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination', undefined, {
199
+ cycleCount: 1,
200
+ strategy: 'context-enriched',
201
+ failureSummary: '2 migrations missing .json snapshots',
202
+ });
203
+ expect(result).toContain('REWORK MODE');
204
+ expect(result).toContain('Fix issues found during QA for parent issue PROJ-100');
205
+ expect(result).toContain('DO NOT re-coordinate sub-issues from scratch');
206
+ expect(result).toContain('pnpm af-linear list-comments PROJ-100');
207
+ expect(result).not.toContain('Fetch sub-issues with dependency graph');
208
+ });
209
+ it('includes common rework fixes in rework mode', () => {
210
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination', undefined, {
211
+ cycleCount: 2,
212
+ strategy: 'context-enriched',
213
+ failureSummary: 'Build failed',
214
+ });
215
+ expect(result).toContain('Missing migration .json snapshots');
216
+ expect(result).toContain('TypeScript errors');
217
+ expect(result).toContain('Missing API fields');
218
+ expect(result).toContain('Build failures');
219
+ });
220
+ it('appends failure context block in rework mode', () => {
221
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination', undefined, {
222
+ cycleCount: 2,
223
+ strategy: 'context-enriched',
224
+ failureSummary: 'Tests failed: missing snapshot for 20260308_migration.ts',
225
+ });
226
+ expect(result).toContain('REWORK MODE');
227
+ expect(result).toContain('Retry Context');
228
+ expect(result).toContain('retry #2');
229
+ expect(result).toContain('missing snapshot for 20260308_migration.ts');
230
+ });
231
+ it('includes mention context alongside rework mode', () => {
232
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination', 'Focus on the migration snapshots', {
233
+ cycleCount: 1,
234
+ strategy: 'normal',
235
+ failureSummary: 'Missing .json snapshots',
236
+ });
237
+ expect(result).toContain('REWORK MODE');
238
+ expect(result).toContain('Focus on the migration snapshots');
239
+ });
240
+ it('instructs agent to use existing PR branch', () => {
241
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination', undefined, {
242
+ cycleCount: 1,
243
+ strategy: 'normal',
244
+ failureSummary: null,
245
+ });
246
+ expect(result).toContain('Do not create a new branch or PR');
247
+ expect(result).toContain('push to the existing PR branch');
248
+ });
249
+ it('includes sub-issue status management in fresh coordination', () => {
250
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination');
251
+ expect(result).toContain('SUB-ISSUE STATUS MANAGEMENT');
252
+ expect(result).toContain('COMPLETION VERIFICATION');
253
+ });
254
+ it('does not include sub-issue status management in rework mode', () => {
255
+ const result = defaultGeneratePrompt('PROJ-100', 'coordination', undefined, {
256
+ cycleCount: 1,
257
+ strategy: 'normal',
258
+ failureSummary: 'QA failed',
259
+ });
260
+ expect(result).not.toContain('SUB-ISSUE STATUS MANAGEMENT');
261
+ expect(result).not.toContain('COMPLETION VERIFICATION');
262
+ });
263
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Default work type detection from prompt keywords.
3
+ *
4
+ * Scans prompt text for keywords that map to specific work types,
5
+ * constrained to the set of valid work types for the current issue status.
6
+ */
7
+ import type { AgentWorkType } from '../types.js';
8
+ /**
9
+ * Detect work type from prompt text, constrained to valid options.
10
+ *
11
+ * Scans the prompt for keywords and returns the first matching work type
12
+ * that is also in the set of valid work types for the current issue status.
13
+ *
14
+ * @param prompt - The prompt text to scan
15
+ * @param validWorkTypes - Work types valid for the current issue status
16
+ * @returns The detected work type, or undefined if no match
17
+ */
18
+ export declare function defaultDetectWorkTypeFromPrompt(prompt: string, validWorkTypes: AgentWorkType[]): AgentWorkType | undefined;
19
+ //# sourceMappingURL=work-type-detection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-type-detection.d.ts","sourceRoot":"","sources":["../../../src/defaults/work-type-detection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAmEhD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,aAAa,EAAE,GAC9B,aAAa,GAAG,SAAS,CAe3B"}