@supaku/agentfactory-linear 0.7.8 → 0.7.10

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.
@@ -34,6 +34,11 @@ export declare const CONTINUATION_MARKER = "\n\n*...continued in next comment*";
34
34
  * hoisting issues where the value is captured before dotenv runs.
35
35
  */
36
36
  export declare function getDefaultTeamId(): string;
37
+ /**
38
+ * Default team name
39
+ * Can be set via LINEAR_TEAM_NAME env var (auto-set by orchestrator from issue context)
40
+ */
41
+ export declare function getDefaultTeamName(): string;
37
42
  /**
38
43
  * Project IDs — must be set via env vars:
39
44
  * - LINEAR_PROJECT_AGENT
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,QAAQ,CAAA;AAE9C;;GAEG;AACH,eAAO,MAAM,iBAAiB,gCAAgC,CAAA;AAE9D;;GAEG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC;;GAEG;AACH,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAEnC;;GAEG;AACH,eAAO,MAAM,mBAAmB,uCAAuC,CAAA;AAQvE;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe;;;IAG1B,mDAAmD;;CAE3C,CAAA;AAEV;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;CAKhB,CAAA;AAGV,eAAO,MAAM,gBAAgB;IAC3B,+DAA+D;;IAE/D,2CAA2C;;CAEnC,CAAA;AAMV;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;CAS1B,CAAA;AAEV,MAAM,MAAM,oBAAoB,GAC9B,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,OAAO,uBAAuB,CAAC,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,QAAQ,CAAA;AAE9C;;GAEG;AACH,eAAO,MAAM,iBAAiB,gCAAgC,CAAA;AAE9D;;GAEG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC;;GAEG;AACH,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAEnC;;GAEG;AACH,eAAO,MAAM,mBAAmB,uCAAuC,CAAA;AAQvE;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe;;;IAG1B,mDAAmD;;CAE3C,CAAA;AAEV;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;CAKhB,CAAA;AAGV,eAAO,MAAM,gBAAgB;IAC3B,+DAA+D;;IAE/D,2CAA2C;;CAEnC,CAAA;AAMV;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;CAS1B,CAAA;AAEV,MAAM,MAAM,oBAAoB,GAC9B,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,OAAO,uBAAuB,CAAC,CAAA"}
@@ -44,6 +44,13 @@ export const CONTINUATION_MARKER = '\n\n*...continued in next comment*';
44
44
  export function getDefaultTeamId() {
45
45
  return process.env.LINEAR_TEAM_ID ?? '';
46
46
  }
47
+ /**
48
+ * Default team name
49
+ * Can be set via LINEAR_TEAM_NAME env var (auto-set by orchestrator from issue context)
50
+ */
51
+ export function getDefaultTeamName() {
52
+ return process.env.LINEAR_TEAM_NAME ?? '';
53
+ }
47
54
  /**
48
55
  * Project IDs — must be set via env vars:
49
56
  * - LINEAR_PROJECT_AGENT
@@ -5,7 +5,7 @@
5
5
  * New users start with these defaults and customize as needed.
6
6
  * Supaku overrides these with its own prompts.ts.
7
7
  */
8
- export { defaultGeneratePrompt, defaultBuildParentQAContext, defaultBuildParentAcceptanceContext, } from './prompts.js';
8
+ export { defaultGeneratePrompt, defaultBuildParentQAContext, defaultBuildParentAcceptanceContext, buildFailureContextBlock, WORK_RESULT_MARKER_INSTRUCTION, PR_SELECTION_GUIDANCE, type WorkflowContext, } from './prompts.js';
9
9
  export { defaultDetectWorkTypeFromPrompt } from './work-type-detection.js';
10
10
  export { defaultGetPriority } from './priority.js';
11
11
  export { defaultParseAutoTriggerConfig, type DefaultAutoTriggerConfig, } from './auto-trigger.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/defaults/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,mCAAmC,GACpC,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,+BAA+B,EAAE,MAAM,0BAA0B,CAAA;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAElD,OAAO,EACL,6BAA6B,EAC7B,KAAK,wBAAwB,GAC9B,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/defaults/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,mCAAmC,EACnC,wBAAwB,EACxB,8BAA8B,EAC9B,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,+BAA+B,EAAE,MAAM,0BAA0B,CAAA;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAElD,OAAO,EACL,6BAA6B,EAC7B,KAAK,wBAAwB,GAC9B,MAAM,mBAAmB,CAAA"}
@@ -5,7 +5,7 @@
5
5
  * New users start with these defaults and customize as needed.
6
6
  * Supaku overrides these with its own prompts.ts.
7
7
  */
8
- export { defaultGeneratePrompt, defaultBuildParentQAContext, defaultBuildParentAcceptanceContext, } from './prompts.js';
8
+ export { defaultGeneratePrompt, defaultBuildParentQAContext, defaultBuildParentAcceptanceContext, buildFailureContextBlock, WORK_RESULT_MARKER_INSTRUCTION, PR_SELECTION_GUIDANCE, } from './prompts.js';
9
9
  export { defaultDetectWorkTypeFromPrompt } from './work-type-detection.js';
10
10
  export { defaultGetPriority } from './priority.js';
11
11
  export { defaultParseAutoTriggerConfig, } from './auto-trigger.js';
@@ -5,14 +5,31 @@
5
5
  * The Supaku project overrides these with its own prompts.ts.
6
6
  */
7
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 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";
10
+ /**
11
+ * Context from the workflow state machine for retry enrichment.
12
+ * Injected when an issue has been through previous dev-QA-rejected cycles.
13
+ */
14
+ export interface WorkflowContext {
15
+ cycleCount: number;
16
+ strategy: string;
17
+ failureSummary: string | null;
18
+ qaAttemptCount?: number;
19
+ }
20
+ /**
21
+ * Build the failure context block to append to prompts for retries.
22
+ */
23
+ export declare function buildFailureContextBlock(workType: AgentWorkType, context: WorkflowContext): string;
8
24
  /**
9
25
  * Generate a default prompt for a given work type and issue identifier.
10
26
  *
11
27
  * @param identifier - The issue identifier (e.g., "PROJ-123")
12
28
  * @param workType - The type of work to perform
13
29
  * @param mentionContext - Optional additional context from a user mention
30
+ * @param workflowContext - Optional workflow state context for retry enrichment
14
31
  */
15
- export declare function defaultGeneratePrompt(identifier: string, workType: AgentWorkType, mentionContext?: string): string;
32
+ export declare function defaultGeneratePrompt(identifier: string, workType: AgentWorkType, mentionContext?: string, workflowContext?: WorkflowContext): string;
16
33
  /**
17
34
  * Build default QA context for parent issues with sub-issues.
18
35
  */
@@ -1 +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;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,aAAa,EACvB,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CA4DR;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"}
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,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,CAuFR;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"}
@@ -14,14 +14,91 @@ manual setup steps, policy decisions, access permissions), create a blocker issu
14
14
  This creates a tracked issue in Icebox with 'Needs Human' label, linked as blocking the source issue.
15
15
  Do NOT silently skip human-needed work or bury it in comments.
16
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 PR_SELECTION_GUIDANCE = `
25
+
26
+ PR Selection (Multi-PR Handling):
27
+ Issues may have multiple PRs. Select the correct one:
28
+ 1. Check linked PRs in the issue attachments/links for GitHub PR URLs
29
+ 2. Filter by state — prefer OPEN over MERGED over CLOSED: gh pr view NNN --json state
30
+ 3. If multiple OPEN PRs, pick the most recently created one
31
+ 4. Fallback search by branch: gh pr list --head "$(git branch --show-current)" --state open
32
+ 5. Last resort search by issue ID: gh pr list --state open --search "[issue-id]"
33
+ 6. If no PR found, emit WORK_RESULT:failed with explanation`;
34
+ /**
35
+ * Build the failure context block to append to prompts for retries.
36
+ */
37
+ export function buildFailureContextBlock(workType, context) {
38
+ if (context.cycleCount <= 0)
39
+ return '';
40
+ switch (workType) {
41
+ case 'refinement': {
42
+ if (context.strategy === 'decompose') {
43
+ return `\n\n## Decomposition Required (Cycle ${context.cycleCount})
44
+
45
+ This issue has been through ${context.cycleCount} development-QA cycle(s) and keeps failing.
46
+ Instead of refining, DECOMPOSE this issue into smaller, independently testable pieces.
47
+
48
+ ### Failure History
49
+ ${context.failureSummary ?? 'No details recorded.'}
50
+
51
+ ### Decomposition Instructions
52
+ - Break this issue into smaller sub-issues (use --parentId to make them children)
53
+ - Each sub-issue must have clear, unambiguous acceptance criteria
54
+ - Each sub-issue must be testable in isolation
55
+ - Address one specific concern that previous attempts failed on
56
+ - After creating sub-issues, move the PARENT issue to Backlog status`;
57
+ }
58
+ return `\n\n## Previous Failure Context
59
+
60
+ This issue has been through ${context.cycleCount} development-QA cycle(s).
61
+
62
+ ### Failure History
63
+ ${context.failureSummary ?? 'No details recorded.'}
64
+
65
+ ### Instructions
66
+ - Read the failure history carefully before making changes
67
+ - Do NOT repeat approaches that already failed
68
+ - If the acceptance criteria are ambiguous, update them to be testable before fixing code
69
+ - Focus on the ROOT CAUSE, not symptoms`;
70
+ }
71
+ case 'development':
72
+ case 'coordination': {
73
+ return `\n\n## Retry Context
74
+
75
+ This is retry #${context.cycleCount} for this issue. Previous QA failures:
76
+ ${context.failureSummary ?? 'No details recorded.'}
77
+
78
+ Pay special attention to the areas that failed QA previously.`;
79
+ }
80
+ case 'qa':
81
+ case 'qa-coordination': {
82
+ if (!context.failureSummary)
83
+ return '';
84
+ return `\n\n## Previous QA Results
85
+ This issue has been QA'd ${context.qaAttemptCount ?? context.cycleCount} times previously.
86
+ ${context.failureSummary}
87
+ Focus validation on these previously failing areas.`;
88
+ }
89
+ default:
90
+ return '';
91
+ }
92
+ }
17
93
  /**
18
94
  * Generate a default prompt for a given work type and issue identifier.
19
95
  *
20
96
  * @param identifier - The issue identifier (e.g., "PROJ-123")
21
97
  * @param workType - The type of work to perform
22
98
  * @param mentionContext - Optional additional context from a user mention
99
+ * @param workflowContext - Optional workflow state context for retry enrichment
23
100
  */
24
- export function defaultGeneratePrompt(identifier, workType, mentionContext) {
101
+ export function defaultGeneratePrompt(identifier, workType, mentionContext, workflowContext) {
25
102
  let basePrompt;
26
103
  switch (workType) {
27
104
  case 'research':
@@ -45,10 +122,30 @@ Do NOT wait for user approval - create issues automatically.`;
45
122
  basePrompt = `Continue work on ${identifier}. Resume where you left off.`;
46
123
  break;
47
124
  case 'qa':
48
- basePrompt = `QA ${identifier}. Validate the implementation against acceptance criteria.`;
125
+ basePrompt = `QA ${identifier}. Validate the implementation against acceptance criteria.
126
+ ${WORK_RESULT_MARKER_INSTRUCTION}
127
+ ${PR_SELECTION_GUIDANCE}
128
+
129
+ Validation Steps:
130
+ 1. Find and validate the correct PR (see PR selection above)
131
+ 2. Run tests scoped to the affected packages
132
+ 3. Verify the build passes
133
+ 4. Check deployment status (CI checks on the PR)
134
+ 5. Review changes against issue requirements
135
+ 6. Post result comment with the structured marker`;
49
136
  break;
50
137
  case 'acceptance':
51
- 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.`;
138
+ 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.
139
+ ${WORK_RESULT_MARKER_INSTRUCTION}
140
+ ${PR_SELECTION_GUIDANCE}
141
+
142
+ Acceptance Steps:
143
+ 1. Find and validate the correct PR (see PR selection above)
144
+ 2. Verify CI is passing and there are no merge conflicts
145
+ 3. Confirm QA has passed (check issue status or QA comments)
146
+ 4. Merge the PR
147
+ 5. Delete the remote branch after successful merge
148
+ 6. Post result comment with the structured marker`;
52
149
  break;
53
150
  case 'refinement':
54
151
  basePrompt = `Refine ${identifier} based on rejection feedback. Read comments, update requirements, then return to Backlog.`;
@@ -67,13 +164,19 @@ Before marking the parent issue as complete, verify ALL sub-issues are in Finish
67
164
  If any sub-issue is not Finished, report the failure and do not mark the parent as complete.`;
68
165
  break;
69
166
  case 'qa-coordination':
70
- basePrompt = `Coordinate QA across sub-issues for parent issue ${identifier}. Fetch sub-issues, spawn QA sub-agents in parallel for each sub-issue, collect pass/fail results, and roll up to parent. ALL sub-issues must pass QA for the parent to pass.`;
167
+ basePrompt = `Coordinate QA across sub-issues for parent issue ${identifier}. Fetch sub-issues, spawn QA sub-agents in parallel for each sub-issue, collect pass/fail results, and roll up to parent. ALL sub-issues must pass QA for the parent to pass.
168
+ ${WORK_RESULT_MARKER_INSTRUCTION}`;
71
169
  break;
72
170
  case 'acceptance-coordination':
73
- basePrompt = `Coordinate acceptance across sub-issues for parent issue ${identifier}. Verify all sub-issues are Delivered, validate the PR (CI passing, no conflicts), merge the PR, and bulk-update sub-issues to Accepted.`;
171
+ basePrompt = `Coordinate acceptance across sub-issues for parent issue ${identifier}. Verify all sub-issues are Delivered, validate the PR (CI passing, no conflicts), merge the PR, and bulk-update sub-issues to Accepted.
172
+ ${WORK_RESULT_MARKER_INSTRUCTION}`;
74
173
  break;
75
174
  }
76
175
  basePrompt += HUMAN_BLOCKER_INSTRUCTION;
176
+ // Inject workflow failure context for retries
177
+ if (workflowContext) {
178
+ basePrompt += buildFailureContextBlock(workType, workflowContext);
179
+ }
77
180
  if (mentionContext) {
78
181
  return `${basePrompt}\n\nAdditional context from the user's mention:\n${mentionContext}`;
79
182
  }
@@ -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,130 @@
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 work type', () => {
56
+ it('returns empty string when no failure summary', () => {
57
+ expect(buildFailureContextBlock('qa', { ...baseContext, failureSummary: null })).toBe('');
58
+ });
59
+ it('includes previous QA results when failure summary exists', () => {
60
+ const qaCtx = {
61
+ ...baseContext,
62
+ qaAttemptCount: 2,
63
+ };
64
+ const result = buildFailureContextBlock('qa', qaCtx);
65
+ expect(result).toContain('Previous QA Results');
66
+ expect(result).toContain('QA\'d 2 times previously');
67
+ expect(result).toContain('TypeError in UserService');
68
+ });
69
+ it('falls back to cycleCount when qaAttemptCount not provided', () => {
70
+ const result = buildFailureContextBlock('qa', baseContext);
71
+ expect(result).toContain('QA\'d 2 times previously');
72
+ });
73
+ });
74
+ describe('other work types', () => {
75
+ it('returns empty string for acceptance', () => {
76
+ expect(buildFailureContextBlock('acceptance', baseContext)).toBe('');
77
+ });
78
+ it('returns empty string for research', () => {
79
+ expect(buildFailureContextBlock('research', baseContext)).toBe('');
80
+ });
81
+ it('returns empty string for backlog-creation', () => {
82
+ expect(buildFailureContextBlock('backlog-creation', baseContext)).toBe('');
83
+ });
84
+ });
85
+ });
86
+ describe('defaultGeneratePrompt with workflowContext', () => {
87
+ it('does not modify prompt when workflowContext is undefined', () => {
88
+ const withoutCtx = defaultGeneratePrompt('PROJ-123', 'development');
89
+ const withUndefined = defaultGeneratePrompt('PROJ-123', 'development', undefined, undefined);
90
+ expect(withoutCtx).toBe(withUndefined);
91
+ });
92
+ it('does not modify prompt when cycleCount is 0', () => {
93
+ const withoutCtx = defaultGeneratePrompt('PROJ-123', 'development');
94
+ const withZero = defaultGeneratePrompt('PROJ-123', 'development', undefined, {
95
+ cycleCount: 0,
96
+ strategy: 'normal',
97
+ failureSummary: null,
98
+ });
99
+ expect(withoutCtx).toBe(withZero);
100
+ });
101
+ it('enriches refinement prompt with failure context', () => {
102
+ const result = defaultGeneratePrompt('PROJ-123', 'refinement', undefined, {
103
+ cycleCount: 2,
104
+ strategy: 'context-enriched',
105
+ failureSummary: 'Tests failed in UserService',
106
+ });
107
+ expect(result).toContain('Refine PROJ-123');
108
+ expect(result).toContain('Previous Failure Context');
109
+ expect(result).toContain('Tests failed in UserService');
110
+ });
111
+ it('enriches development prompt with retry context', () => {
112
+ const result = defaultGeneratePrompt('PROJ-123', 'development', undefined, {
113
+ cycleCount: 1,
114
+ strategy: 'normal',
115
+ failureSummary: 'Build error in core package',
116
+ });
117
+ expect(result).toContain('Start work on PROJ-123');
118
+ expect(result).toContain('Retry Context');
119
+ expect(result).toContain('Build error in core package');
120
+ });
121
+ it('preserves mentionContext alongside workflowContext', () => {
122
+ const result = defaultGeneratePrompt('PROJ-123', 'development', 'Please focus on the API layer', {
123
+ cycleCount: 1,
124
+ strategy: 'normal',
125
+ failureSummary: 'API tests failing',
126
+ });
127
+ expect(result).toContain('Retry Context');
128
+ expect(result).toContain('Please focus on the API layer');
129
+ });
130
+ });
@@ -1 +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;AA6DhD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,aAAa,EAAE,GAC9B,aAAa,GAAG,SAAS,CAe3B"}
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;AA+DhD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,aAAa,EAAE,GAC9B,aAAa,GAAG,SAAS,CAe3B"}
@@ -55,9 +55,11 @@ const WORK_TYPE_PRIORITY_ORDER = [
55
55
  'coordination',
56
56
  'backlog-creation',
57
57
  'research',
58
+ 'qa-coordination',
58
59
  'qa',
59
- 'inflight',
60
+ 'acceptance-coordination',
60
61
  'acceptance',
62
+ 'inflight',
61
63
  'refinement',
62
64
  'development',
63
65
  ];
@@ -0,0 +1,168 @@
1
+ /**
2
+ * LinearFrontendAdapter
3
+ *
4
+ * Implements the WorkSchedulingFrontend interface (defined in @supaku/agentfactory)
5
+ * by wrapping the LinearAgentClient. This adapter translates between abstract,
6
+ * frontend-agnostic types and Linear-specific concepts.
7
+ *
8
+ * Structural typing note: This class structurally satisfies the WorkSchedulingFrontend
9
+ * interface from @supaku/agentfactory without an explicit `implements` clause, avoiding
10
+ * a circular package dependency (core depends on linear at runtime, linear depends on
11
+ * core only for types). Consumers who import both packages can assign this to
12
+ * WorkSchedulingFrontend.
13
+ */
14
+ import type { LinearAgentClient } from './agent-client.js';
15
+ /**
16
+ * Abstract workflow statuses that map to Linear-specific status names.
17
+ */
18
+ export type AbstractStatus = 'icebox' | 'backlog' | 'started' | 'finished' | 'delivered' | 'accepted' | 'rejected' | 'canceled';
19
+ /**
20
+ * Minimal issue representation shared across frontends.
21
+ */
22
+ export interface AbstractIssue {
23
+ id: string;
24
+ identifier: string;
25
+ title: string;
26
+ description?: string;
27
+ url: string;
28
+ status: AbstractStatus;
29
+ priority: number;
30
+ labels: string[];
31
+ parentId?: string;
32
+ project?: string;
33
+ createdAt: Date;
34
+ }
35
+ /**
36
+ * Minimal comment representation.
37
+ */
38
+ export interface AbstractComment {
39
+ id: string;
40
+ body: string;
41
+ userId?: string;
42
+ userName?: string;
43
+ createdAt: Date;
44
+ }
45
+ /**
46
+ * External URL for agent sessions.
47
+ */
48
+ export interface ExternalUrl {
49
+ label: string;
50
+ url: string;
51
+ }
52
+ /**
53
+ * Input for creating an issue.
54
+ */
55
+ export interface CreateIssueInput {
56
+ title: string;
57
+ teamId?: string;
58
+ description?: string;
59
+ projectId?: string;
60
+ status?: AbstractStatus;
61
+ labels?: string[];
62
+ parentId?: string;
63
+ priority?: number;
64
+ }
65
+ /**
66
+ * Input for creating a blocker issue.
67
+ */
68
+ export interface CreateBlockerInput {
69
+ title: string;
70
+ description?: string;
71
+ teamId?: string;
72
+ projectId?: string;
73
+ assignee?: string;
74
+ }
75
+ /**
76
+ * Input for updating an agent session.
77
+ */
78
+ export interface UpdateSessionInput {
79
+ externalUrls?: ExternalUrl[];
80
+ plan?: Array<{
81
+ content: string;
82
+ status: 'pending' | 'inProgress' | 'completed' | 'canceled';
83
+ }>;
84
+ }
85
+ /**
86
+ * Linear frontend adapter that wraps LinearAgentClient.
87
+ *
88
+ * Structurally satisfies WorkSchedulingFrontend from @supaku/agentfactory.
89
+ */
90
+ export declare class LinearFrontendAdapter {
91
+ private readonly client;
92
+ readonly name: "linear";
93
+ constructor(client: LinearAgentClient);
94
+ /**
95
+ * Resolve an abstract status to its Linear-native name.
96
+ */
97
+ resolveStatus(abstract: AbstractStatus): string;
98
+ /**
99
+ * Map a Linear-native status name to its abstract equivalent.
100
+ * Defaults to 'backlog' for unknown statuses.
101
+ */
102
+ abstractStatus(nativeStatus: string): AbstractStatus;
103
+ /**
104
+ * Fetch an issue by ID or identifier and map to AbstractIssue.
105
+ */
106
+ getIssue(id: string): Promise<AbstractIssue>;
107
+ /**
108
+ * List issues in a project filtered by abstract status.
109
+ *
110
+ * Uses the underlying LinearClient directly since LinearAgentClient
111
+ * does not expose a project-scoped issue listing method.
112
+ */
113
+ listIssuesByStatus(project: string, status: AbstractStatus): Promise<AbstractIssue[]>;
114
+ /**
115
+ * Get comments for an issue and map to AbstractComment[].
116
+ */
117
+ getIssueComments(id: string): Promise<AbstractComment[]>;
118
+ /**
119
+ * List issues in a project filtered by abstract status, excluding
120
+ * those that are blocked by other issues (have incoming "blocks" relations).
121
+ */
122
+ getUnblockedIssues(project: string, status: AbstractStatus): Promise<AbstractIssue[]>;
123
+ /**
124
+ * Check if an issue has child issues (is a parent issue).
125
+ */
126
+ isParentIssue(id: string): Promise<boolean>;
127
+ /**
128
+ * Check if an issue has a parent (is a child/sub-issue).
129
+ */
130
+ isChildIssue(id: string): Promise<boolean>;
131
+ /**
132
+ * Get sub-issues of a parent issue, mapped to AbstractIssue[].
133
+ */
134
+ getSubIssues(id: string): Promise<AbstractIssue[]>;
135
+ /**
136
+ * Transition an issue to a new status.
137
+ */
138
+ transitionIssue(id: string, status: AbstractStatus): Promise<void>;
139
+ /**
140
+ * Create a comment on an issue.
141
+ */
142
+ createComment(id: string, body: string): Promise<void>;
143
+ /**
144
+ * Create a blocker issue that blocks the source issue.
145
+ * Creates the issue in Icebox with a "Needs Human" label (if found),
146
+ * then creates a "blocks" relation from the blocker to the source.
147
+ */
148
+ createBlockerIssue(sourceId: string, data: CreateBlockerInput): Promise<AbstractIssue>;
149
+ /**
150
+ * Create a new issue and return it as AbstractIssue.
151
+ */
152
+ createIssue(data: CreateIssueInput): Promise<AbstractIssue>;
153
+ /**
154
+ * Create an agent session on an issue.
155
+ * Returns the session ID.
156
+ */
157
+ createAgentSession(issueId: string, externalUrls?: ExternalUrl[]): Promise<string>;
158
+ /**
159
+ * Update an existing agent session.
160
+ */
161
+ updateAgentSession(sessionId: string, data: UpdateSessionInput): Promise<void>;
162
+ /**
163
+ * Create an activity on an agent session.
164
+ * Wraps the content as a ThoughtActivityContent.
165
+ */
166
+ createActivity(sessionId: string, type: string, content: string): Promise<void>;
167
+ }
168
+ //# sourceMappingURL=frontend-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontend-adapter.d.ts","sourceRoot":"","sources":["../../src/frontend-adapter.ts"],"names":[],"mappings":"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"}