sequant 1.20.3 → 2.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.
Files changed (137) hide show
  1. package/.claude-plugin/marketplace.json +2 -4
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +29 -9
  4. package/dist/bin/cli.js +25 -2
  5. package/dist/src/commands/doctor.js +42 -9
  6. package/dist/src/commands/init.d.ts +1 -0
  7. package/dist/src/commands/init.js +52 -0
  8. package/dist/src/commands/logs.d.ts +1 -0
  9. package/dist/src/commands/logs.js +18 -2
  10. package/dist/src/commands/run.d.ts +7 -0
  11. package/dist/src/commands/run.js +235 -68
  12. package/dist/src/commands/serve.d.ts +13 -0
  13. package/dist/src/commands/serve.js +131 -0
  14. package/dist/src/commands/stats.d.ts +1 -0
  15. package/dist/src/commands/stats.js +185 -26
  16. package/dist/src/commands/status.d.ts +2 -0
  17. package/dist/src/commands/status.js +99 -50
  18. package/dist/src/index.d.ts +2 -2
  19. package/dist/src/index.js +4 -1
  20. package/dist/src/lib/ac-parser.d.ts +2 -0
  21. package/dist/src/lib/ac-parser.js +12 -2
  22. package/dist/src/lib/assess-comment-parser.d.ts +137 -0
  23. package/dist/src/lib/assess-comment-parser.js +344 -0
  24. package/dist/src/lib/ci/config.d.ts +22 -0
  25. package/dist/src/lib/ci/config.js +134 -0
  26. package/dist/src/lib/ci/index.d.ts +12 -0
  27. package/dist/src/lib/ci/index.js +10 -0
  28. package/dist/src/lib/ci/inputs.d.ts +29 -0
  29. package/dist/src/lib/ci/inputs.js +103 -0
  30. package/dist/src/lib/ci/labels.d.ts +34 -0
  31. package/dist/src/lib/ci/labels.js +101 -0
  32. package/dist/src/lib/ci/outputs.d.ts +25 -0
  33. package/dist/src/lib/ci/outputs.js +84 -0
  34. package/dist/src/lib/ci/triggers.d.ts +9 -0
  35. package/dist/src/lib/ci/triggers.js +86 -0
  36. package/dist/src/lib/ci/types.d.ts +131 -0
  37. package/dist/src/lib/ci/types.js +47 -0
  38. package/dist/src/lib/mcp-config.d.ts +54 -0
  39. package/dist/src/lib/mcp-config.js +172 -0
  40. package/dist/src/lib/merge-check/index.js +6 -12
  41. package/dist/src/lib/merge-check/types.d.ts +20 -7
  42. package/dist/src/lib/merge-check/types.js +11 -0
  43. package/dist/src/lib/phase-signal.d.ts +3 -3
  44. package/dist/src/lib/phase-signal.js +5 -3
  45. package/dist/src/lib/settings.d.ts +52 -0
  46. package/dist/src/lib/settings.js +41 -0
  47. package/dist/src/lib/shutdown.d.ts +16 -5
  48. package/dist/src/lib/shutdown.js +32 -12
  49. package/dist/src/lib/solve-comment-parser.d.ts +9 -102
  50. package/dist/src/lib/solve-comment-parser.js +13 -248
  51. package/dist/src/lib/stacks.d.ts +8 -0
  52. package/dist/src/lib/stacks.js +34 -0
  53. package/dist/src/lib/system.js +3 -7
  54. package/dist/src/lib/test-tautology-detector.d.ts +10 -0
  55. package/dist/src/lib/test-tautology-detector.js +43 -4
  56. package/dist/src/lib/upstream/assessment.js +9 -59
  57. package/dist/src/lib/upstream/issues.js +12 -75
  58. package/dist/src/lib/version-check.d.ts +2 -2
  59. package/dist/src/lib/version-check.js +6 -3
  60. package/dist/src/lib/version.d.ts +4 -0
  61. package/dist/src/lib/version.js +25 -0
  62. package/dist/src/lib/workflow/batch-executor.d.ts +18 -86
  63. package/dist/src/lib/workflow/batch-executor.js +232 -55
  64. package/dist/src/lib/workflow/drivers/agent-driver.d.ts +56 -0
  65. package/dist/src/lib/workflow/drivers/agent-driver.js +8 -0
  66. package/dist/src/lib/workflow/drivers/aider.d.ts +18 -0
  67. package/dist/src/lib/workflow/drivers/aider.js +160 -0
  68. package/dist/src/lib/workflow/drivers/claude-code.d.ts +17 -0
  69. package/dist/src/lib/workflow/drivers/claude-code.js +165 -0
  70. package/dist/src/lib/workflow/drivers/index.d.ts +20 -0
  71. package/dist/src/lib/workflow/drivers/index.js +27 -0
  72. package/dist/src/lib/workflow/error-classifier.d.ts +16 -0
  73. package/dist/src/lib/workflow/error-classifier.js +90 -0
  74. package/dist/src/lib/workflow/log-writer.d.ts +6 -3
  75. package/dist/src/lib/workflow/log-writer.js +57 -27
  76. package/dist/src/lib/workflow/metrics-schema.d.ts +9 -9
  77. package/dist/src/lib/workflow/phase-detection.d.ts +23 -0
  78. package/dist/src/lib/workflow/phase-detection.js +45 -29
  79. package/dist/src/lib/workflow/phase-executor.d.ts +42 -3
  80. package/dist/src/lib/workflow/phase-executor.js +340 -220
  81. package/dist/src/lib/workflow/phase-mapper.d.ts +1 -1
  82. package/dist/src/lib/workflow/phase-mapper.js +7 -7
  83. package/dist/src/lib/workflow/platforms/github.d.ts +157 -0
  84. package/dist/src/lib/workflow/platforms/github.js +466 -0
  85. package/dist/src/lib/workflow/platforms/index.d.ts +17 -0
  86. package/dist/src/lib/workflow/platforms/index.js +25 -0
  87. package/dist/src/lib/workflow/platforms/platform-provider.d.ts +67 -0
  88. package/dist/src/lib/workflow/platforms/platform-provider.js +8 -0
  89. package/dist/src/lib/workflow/pr-status.d.ts +2 -4
  90. package/dist/src/lib/workflow/pr-status.js +3 -16
  91. package/dist/src/lib/workflow/qa-cache.d.ts +58 -0
  92. package/dist/src/lib/workflow/qa-cache.js +88 -0
  93. package/dist/src/lib/workflow/reconcile.d.ts +69 -0
  94. package/dist/src/lib/workflow/reconcile.js +290 -0
  95. package/dist/src/lib/workflow/ring-buffer.d.ts +17 -0
  96. package/dist/src/lib/workflow/ring-buffer.js +37 -0
  97. package/dist/src/lib/workflow/run-log-schema.d.ts +115 -24
  98. package/dist/src/lib/workflow/run-log-schema.js +47 -12
  99. package/dist/src/lib/workflow/run-reflect.js +1 -1
  100. package/dist/src/lib/workflow/state-cleanup.js +21 -0
  101. package/dist/src/lib/workflow/state-manager.d.ts +34 -3
  102. package/dist/src/lib/workflow/state-manager.js +278 -126
  103. package/dist/src/lib/workflow/state-schema.d.ts +34 -30
  104. package/dist/src/lib/workflow/state-schema.js +35 -25
  105. package/dist/src/lib/workflow/state-utils.d.ts +3 -1
  106. package/dist/src/lib/workflow/state-utils.js +1 -0
  107. package/dist/src/lib/workflow/types.d.ts +208 -6
  108. package/dist/src/lib/workflow/types.js +20 -1
  109. package/dist/src/lib/workflow/worktree-discovery.d.ts +1 -1
  110. package/dist/src/lib/workflow/worktree-discovery.js +6 -14
  111. package/dist/src/lib/workflow/worktree-manager.js +33 -51
  112. package/dist/src/mcp/index.d.ts +4 -0
  113. package/dist/src/mcp/index.js +4 -0
  114. package/dist/src/mcp/resources.d.ts +7 -0
  115. package/dist/src/mcp/resources.js +111 -0
  116. package/dist/src/mcp/run-registry.d.ts +34 -0
  117. package/dist/src/mcp/run-registry.js +42 -0
  118. package/dist/src/mcp/server.d.ts +12 -0
  119. package/dist/src/mcp/server.js +50 -0
  120. package/dist/src/mcp/tools/logs.d.ts +7 -0
  121. package/dist/src/mcp/tools/logs.js +149 -0
  122. package/dist/src/mcp/tools/run.d.ts +121 -0
  123. package/dist/src/mcp/tools/run.js +591 -0
  124. package/dist/src/mcp/tools/status.d.ts +7 -0
  125. package/dist/src/mcp/tools/status.js +127 -0
  126. package/package.json +10 -1
  127. package/templates/hooks/post-tool.sh +19 -8
  128. package/templates/hooks/pre-tool.sh +36 -49
  129. package/templates/mcp.json +6 -0
  130. package/templates/skills/assess/SKILL.md +354 -352
  131. package/templates/skills/exec/SKILL.md +64 -1
  132. package/templates/skills/fullsolve/SKILL.md +35 -4
  133. package/templates/skills/qa/SKILL.md +486 -9
  134. package/templates/skills/qa/scripts/quality-checks.sh +1 -1
  135. package/templates/skills/setup/SKILL.md +386 -0
  136. package/templates/skills/solve/SKILL.md +38 -664
  137. package/templates/skills/spec/SKILL.md +90 -31
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Input parsing and validation for the GitHub Action.
3
+ *
4
+ * Parses raw string inputs from action.yml into validated ActionInputs,
5
+ * applying defaults and merging with repo-level configuration.
6
+ */
7
+ import { CI_DEFAULTS } from "./types.js";
8
+ const VALID_PHASES = new Set([
9
+ "spec",
10
+ "security-review",
11
+ "testgen",
12
+ "exec",
13
+ "test",
14
+ "qa",
15
+ "loop",
16
+ ]);
17
+ const VALID_AGENTS = new Set(["claude-code", "aider", "codex"]);
18
+ /**
19
+ * Parse and validate action inputs, merging with repo config.
20
+ *
21
+ * Merge precedence: workflow inputs > config file > action defaults
22
+ */
23
+ export function parseInputs(raw, config = {}) {
24
+ const issues = parseIssueNumbers(raw.issues ?? "");
25
+ const phases = parsePhases(raw.phases, config.phases ?? CI_DEFAULTS.phases);
26
+ const agent = parseAgent(raw.agent, config.agent ?? CI_DEFAULTS.agent);
27
+ const timeout = parseTimeout(raw.timeout, config.timeout ?? CI_DEFAULTS.timeout);
28
+ const qualityLoop = parseBool(raw["quality-loop"], config.qualityLoop ?? CI_DEFAULTS.qualityLoop);
29
+ const apiKey = raw["api-key"] ?? "";
30
+ return { issues, phases, agent, timeout, qualityLoop, apiKey };
31
+ }
32
+ /**
33
+ * Validate that required inputs are present and well-formed.
34
+ * Returns an array of error messages (empty = valid).
35
+ */
36
+ export function validateInputs(inputs) {
37
+ const errors = [];
38
+ if (inputs.issues.length === 0) {
39
+ errors.push("No valid issue numbers provided");
40
+ }
41
+ if (inputs.phases.length === 0) {
42
+ errors.push("No valid phases provided");
43
+ }
44
+ if (!inputs.apiKey) {
45
+ errors.push("API key is required — pass via api-key input mapped from a secret");
46
+ }
47
+ if (inputs.timeout < 60) {
48
+ errors.push("Timeout must be at least 60 seconds");
49
+ }
50
+ if (inputs.timeout > 7200) {
51
+ errors.push("Timeout must not exceed 7200 seconds (2 hours)");
52
+ }
53
+ return errors;
54
+ }
55
+ /**
56
+ * Parse space-separated issue numbers.
57
+ */
58
+ function parseIssueNumbers(input) {
59
+ if (!input.trim())
60
+ return [];
61
+ return input
62
+ .split(/[\s,]+/)
63
+ .map((s) => parseInt(s.trim(), 10))
64
+ .filter((n) => !isNaN(n) && n > 0);
65
+ }
66
+ /**
67
+ * Parse comma-separated phase names, falling back to default.
68
+ */
69
+ function parsePhases(input, fallback) {
70
+ if (!input?.trim())
71
+ return fallback;
72
+ const parsed = input
73
+ .split(",")
74
+ .map((p) => p.trim())
75
+ .filter((p) => VALID_PHASES.has(p));
76
+ return parsed.length > 0 ? parsed : fallback;
77
+ }
78
+ /**
79
+ * Parse agent name with validation.
80
+ */
81
+ function parseAgent(input, fallback) {
82
+ if (!input?.trim())
83
+ return fallback;
84
+ const agent = input.trim();
85
+ return VALID_AGENTS.has(agent) ? agent : fallback;
86
+ }
87
+ /**
88
+ * Parse timeout string to number with bounds check.
89
+ */
90
+ function parseTimeout(input, fallback) {
91
+ if (!input?.trim())
92
+ return fallback;
93
+ const n = parseInt(input.trim(), 10);
94
+ return isNaN(n) ? fallback : n;
95
+ }
96
+ /**
97
+ * Parse boolean string.
98
+ */
99
+ function parseBool(input, fallback) {
100
+ if (!input?.trim())
101
+ return fallback;
102
+ return input.trim().toLowerCase() === "true";
103
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Label lifecycle management for CI-triggered workflows.
3
+ *
4
+ * Manages the sequant:solving → sequant:done / sequant:failed label
5
+ * transitions on GitHub issues during and after workflow execution.
6
+ */
7
+ /**
8
+ * Get labels to add when a workflow run starts.
9
+ */
10
+ export declare function getStartLabels(): string[];
11
+ /**
12
+ * Get labels to remove when a workflow run starts.
13
+ * Removes the trigger label that initiated the run.
14
+ */
15
+ export declare function getStartRemoveLabels(triggerLabel?: string): string[];
16
+ /**
17
+ * Get labels to apply when a workflow completes successfully.
18
+ */
19
+ export declare function getSuccessLabels(): {
20
+ add: string[];
21
+ remove: string[];
22
+ };
23
+ /**
24
+ * Get labels to apply when a workflow fails.
25
+ */
26
+ export declare function getFailureLabels(): {
27
+ add: string[];
28
+ remove: string[];
29
+ };
30
+ /**
31
+ * Generate gh CLI commands for label transitions.
32
+ * Useful for composite action shell steps.
33
+ */
34
+ export declare function labelCommands(issueNumber: number, transition: "start" | "success" | "failure", triggerLabel?: string): string[];
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Label lifecycle management for CI-triggered workflows.
3
+ *
4
+ * Manages the sequant:solving → sequant:done / sequant:failed label
5
+ * transitions on GitHub issues during and after workflow execution.
6
+ */
7
+ import { LIFECYCLE_LABELS, TRIGGER_LABELS } from "./types.js";
8
+ /**
9
+ * All trigger labels that should be removed when a run starts.
10
+ */
11
+ const TRIGGER_LABEL_SET = new Set(Object.values(TRIGGER_LABELS));
12
+ /**
13
+ * Trigger label aliases — labels that trigger the same workflow.
14
+ * When one is used, all aliases should also be removed to prevent
15
+ * stale labels during migration (e.g. sequant:solve → sequant:assess).
16
+ */
17
+ const TRIGGER_ALIASES = new Map([
18
+ [TRIGGER_LABELS.ASSESS, [TRIGGER_LABELS.SOLVE]],
19
+ [TRIGGER_LABELS.SOLVE, [TRIGGER_LABELS.ASSESS]],
20
+ ]);
21
+ /**
22
+ * Get labels to add when a workflow run starts.
23
+ */
24
+ export function getStartLabels() {
25
+ return [LIFECYCLE_LABELS.SOLVING];
26
+ }
27
+ /**
28
+ * Get labels to remove when a workflow run starts.
29
+ * Removes the trigger label that initiated the run.
30
+ */
31
+ export function getStartRemoveLabels(triggerLabel) {
32
+ const labels = [];
33
+ // Remove the trigger label and any aliases (e.g. assess ↔ solve)
34
+ if (triggerLabel && TRIGGER_LABEL_SET.has(triggerLabel)) {
35
+ labels.push(triggerLabel);
36
+ const aliases = TRIGGER_ALIASES.get(triggerLabel);
37
+ if (aliases) {
38
+ labels.push(...aliases);
39
+ }
40
+ }
41
+ // Remove any stale outcome labels from prior runs
42
+ labels.push(LIFECYCLE_LABELS.DONE, LIFECYCLE_LABELS.FAILED);
43
+ return labels;
44
+ }
45
+ /**
46
+ * Get labels to apply when a workflow completes successfully.
47
+ */
48
+ export function getSuccessLabels() {
49
+ return {
50
+ add: [LIFECYCLE_LABELS.DONE],
51
+ remove: [LIFECYCLE_LABELS.SOLVING],
52
+ };
53
+ }
54
+ /**
55
+ * Get labels to apply when a workflow fails.
56
+ */
57
+ export function getFailureLabels() {
58
+ return {
59
+ add: [LIFECYCLE_LABELS.FAILED],
60
+ remove: [LIFECYCLE_LABELS.SOLVING],
61
+ };
62
+ }
63
+ /**
64
+ * Generate gh CLI commands for label transitions.
65
+ * Useful for composite action shell steps.
66
+ */
67
+ export function labelCommands(issueNumber, transition, triggerLabel) {
68
+ const commands = [];
69
+ switch (transition) {
70
+ case "start": {
71
+ for (const label of getStartLabels()) {
72
+ commands.push(`gh issue edit ${issueNumber} --add-label "${label}"`);
73
+ }
74
+ for (const label of getStartRemoveLabels(triggerLabel)) {
75
+ commands.push(`gh issue edit ${issueNumber} --remove-label "${label}" 2>/dev/null || true`);
76
+ }
77
+ break;
78
+ }
79
+ case "success": {
80
+ const { add, remove } = getSuccessLabels();
81
+ for (const label of add) {
82
+ commands.push(`gh issue edit ${issueNumber} --add-label "${label}"`);
83
+ }
84
+ for (const label of remove) {
85
+ commands.push(`gh issue edit ${issueNumber} --remove-label "${label}" 2>/dev/null || true`);
86
+ }
87
+ break;
88
+ }
89
+ case "failure": {
90
+ const { add, remove } = getFailureLabels();
91
+ for (const label of add) {
92
+ commands.push(`gh issue edit ${issueNumber} --add-label "${label}"`);
93
+ }
94
+ for (const label of remove) {
95
+ commands.push(`gh issue edit ${issueNumber} --remove-label "${label}" 2>/dev/null || true`);
96
+ }
97
+ break;
98
+ }
99
+ }
100
+ return commands;
101
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Output formatting for GitHub Actions.
3
+ *
4
+ * Formats IssueResult into structured outputs that can be consumed
5
+ * by downstream workflow steps via $GITHUB_OUTPUT.
6
+ */
7
+ import type { IssueResult } from "../workflow/types.js";
8
+ import type { ActionOutputs } from "./types.js";
9
+ /**
10
+ * Format an IssueResult into GitHub Actions outputs.
11
+ */
12
+ export declare function formatOutputs(result: IssueResult): ActionOutputs;
13
+ /**
14
+ * Format multiple issue results into combined outputs.
15
+ */
16
+ export declare function formatMultiOutputs(results: IssueResult[]): ActionOutputs;
17
+ /**
18
+ * Generate shell commands to set GitHub Actions outputs.
19
+ * Each output is written to $GITHUB_OUTPUT file.
20
+ */
21
+ export declare function outputCommands(outputs: ActionOutputs): string[];
22
+ /**
23
+ * Generate a GitHub Actions step summary (Markdown).
24
+ */
25
+ export declare function formatSummary(results: IssueResult[]): string;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Output formatting for GitHub Actions.
3
+ *
4
+ * Formats IssueResult into structured outputs that can be consumed
5
+ * by downstream workflow steps via $GITHUB_OUTPUT.
6
+ */
7
+ /**
8
+ * Format an IssueResult into GitHub Actions outputs.
9
+ */
10
+ export function formatOutputs(result) {
11
+ return {
12
+ issue: String(result.issueNumber),
13
+ success: String(result.success),
14
+ phases: JSON.stringify(formatPhaseResults(result.phaseResults)),
15
+ "pr-url": result.prUrl ?? "",
16
+ duration: String(result.durationSeconds ?? 0),
17
+ };
18
+ }
19
+ /**
20
+ * Format multiple issue results into combined outputs.
21
+ */
22
+ export function formatMultiOutputs(results) {
23
+ const allSuccess = results.every((r) => r.success);
24
+ const totalDuration = results.reduce((sum, r) => sum + (r.durationSeconds ?? 0), 0);
25
+ const prUrls = results
26
+ .map((r) => r.prUrl)
27
+ .filter(Boolean)
28
+ .join(",");
29
+ const allPhases = results.flatMap((r) => formatPhaseResults(r.phaseResults));
30
+ return {
31
+ issue: results.map((r) => r.issueNumber).join(" "),
32
+ success: String(allSuccess),
33
+ phases: JSON.stringify(allPhases),
34
+ "pr-url": prUrls,
35
+ duration: String(totalDuration),
36
+ };
37
+ }
38
+ /**
39
+ * Format phase results for JSON output.
40
+ */
41
+ function formatPhaseResults(phases) {
42
+ return phases.map((p) => ({
43
+ phase: p.phase,
44
+ success: p.success,
45
+ duration: p.durationSeconds ?? 0,
46
+ }));
47
+ }
48
+ /**
49
+ * Generate shell commands to set GitHub Actions outputs.
50
+ * Each output is written to $GITHUB_OUTPUT file.
51
+ */
52
+ export function outputCommands(outputs) {
53
+ return Object.entries(outputs).map(([key, value]) => `echo "${key}=${value}" >> "$GITHUB_OUTPUT"`);
54
+ }
55
+ /**
56
+ * Generate a GitHub Actions step summary (Markdown).
57
+ */
58
+ export function formatSummary(results) {
59
+ const lines = [];
60
+ lines.push("## Sequant Workflow Results\n");
61
+ for (const result of results) {
62
+ const icon = result.success ? "✅" : "❌";
63
+ lines.push(`### ${icon} Issue #${result.issueNumber}\n`);
64
+ lines.push("| Phase | Status | Duration |");
65
+ lines.push("|-------|--------|----------|");
66
+ for (const phase of result.phaseResults) {
67
+ const status = phase.success ? "✅ Passed" : "❌ Failed";
68
+ const duration = phase.durationSeconds
69
+ ? `${phase.durationSeconds}s`
70
+ : "-";
71
+ lines.push(`| ${phase.phase} | ${status} | ${duration} |`);
72
+ }
73
+ if (result.prUrl) {
74
+ lines.push(`\n**PR:** ${result.prUrl}`);
75
+ }
76
+ if (result.abortReason) {
77
+ lines.push(`\n**Abort reason:** ${result.abortReason}`);
78
+ }
79
+ lines.push("");
80
+ }
81
+ const total = results.reduce((sum, r) => sum + (r.durationSeconds ?? 0), 0);
82
+ lines.push(`**Total duration:** ${total}s`);
83
+ return lines.join("\n");
84
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Trigger detection — parses GitHub event payloads into structured
3
+ * trigger results that determine which issues and phases to run.
4
+ */
5
+ import { type GitHubContext, type TriggerResult } from "./types.js";
6
+ /**
7
+ * Detect the trigger type and extract issue/phases from a GitHub event.
8
+ */
9
+ export declare function detectTrigger(context: GitHubContext): TriggerResult;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Trigger detection — parses GitHub event payloads into structured
3
+ * trigger results that determine which issues and phases to run.
4
+ */
5
+ import { COMMENT_TRIGGER_PATTERN, TRIGGER_LABELS, } from "./types.js";
6
+ const VALID_PHASES = new Set([
7
+ "spec",
8
+ "security-review",
9
+ "testgen",
10
+ "exec",
11
+ "test",
12
+ "qa",
13
+ "loop",
14
+ ]);
15
+ /**
16
+ * Map trigger labels to their corresponding phase lists.
17
+ */
18
+ const LABEL_PHASE_MAP = {
19
+ [TRIGGER_LABELS.ASSESS]: ["spec", "exec", "qa"],
20
+ [TRIGGER_LABELS.SOLVE]: ["spec", "exec", "qa"],
21
+ [TRIGGER_LABELS.SPEC_ONLY]: ["spec"],
22
+ [TRIGGER_LABELS.EXEC]: ["exec"],
23
+ [TRIGGER_LABELS.QA]: ["qa"],
24
+ };
25
+ /**
26
+ * Detect the trigger type and extract issue/phases from a GitHub event.
27
+ */
28
+ export function detectTrigger(context) {
29
+ switch (context.eventName) {
30
+ case "workflow_dispatch":
31
+ return {
32
+ trigger: "workflow_dispatch",
33
+ phases: ["spec", "exec", "qa"],
34
+ issue: null,
35
+ };
36
+ case "issues":
37
+ return detectLabelTrigger(context);
38
+ case "issue_comment":
39
+ return detectCommentTrigger(context);
40
+ default:
41
+ return { trigger: "unknown", phases: [], issue: null };
42
+ }
43
+ }
44
+ /**
45
+ * Detect label-based trigger from an issues event.
46
+ */
47
+ function detectLabelTrigger(context) {
48
+ const { payload } = context;
49
+ if (payload.action !== "labeled" || !payload.label) {
50
+ return { trigger: "unknown", phases: [], issue: null };
51
+ }
52
+ const labelName = payload.label.name;
53
+ const phases = LABEL_PHASE_MAP[labelName];
54
+ if (!phases) {
55
+ return { trigger: "unknown", phases: [], issue: null };
56
+ }
57
+ return {
58
+ trigger: "label",
59
+ phases,
60
+ issue: payload.issue?.number ?? null,
61
+ label: labelName,
62
+ };
63
+ }
64
+ /**
65
+ * Detect @sequant command trigger from an issue comment.
66
+ */
67
+ function detectCommentTrigger(context) {
68
+ const { payload } = context;
69
+ if (payload.action !== "created" || !payload.comment?.body) {
70
+ return { trigger: "unknown", phases: [], issue: null };
71
+ }
72
+ const match = payload.comment.body.match(COMMENT_TRIGGER_PATTERN);
73
+ if (!match) {
74
+ return { trigger: "unknown", phases: [], issue: null };
75
+ }
76
+ const rawPhases = match[1].split(",").map((p) => p.trim());
77
+ const phases = rawPhases.filter((p) => VALID_PHASES.has(p));
78
+ if (phases.length === 0) {
79
+ return { trigger: "unknown", phases: [], issue: null };
80
+ }
81
+ return {
82
+ trigger: "comment",
83
+ phases,
84
+ issue: payload.issue?.number ?? null,
85
+ };
86
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Types for GitHub Actions CI integration.
3
+ *
4
+ * These types model the inputs, outputs, triggers, and configuration
5
+ * that the sequant GitHub Action uses to bridge GitHub events to
6
+ * sequant workflow execution.
7
+ */
8
+ import type { Phase } from "../workflow/types.js";
9
+ /**
10
+ * Validated action inputs after parsing from GitHub Actions context.
11
+ */
12
+ export interface ActionInputs {
13
+ /** Issue numbers to process */
14
+ issues: number[];
15
+ /** Workflow phases to execute */
16
+ phases: Phase[];
17
+ /** Agent backend name */
18
+ agent: string;
19
+ /** Phase timeout in seconds */
20
+ timeout: number;
21
+ /** Enable quality loop */
22
+ qualityLoop: boolean;
23
+ /** API key for the selected agent */
24
+ apiKey: string;
25
+ }
26
+ /**
27
+ * Supported GitHub event triggers for the action.
28
+ */
29
+ export type TriggerType = "workflow_dispatch" | "label" | "comment" | "unknown";
30
+ /**
31
+ * Labels that map to specific phase configurations.
32
+ */
33
+ export declare const TRIGGER_LABELS: {
34
+ /** Full workflow: spec → exec → qa */
35
+ readonly ASSESS: "sequant:assess";
36
+ /** @deprecated Use ASSESS instead */
37
+ readonly SOLVE: "sequant:solve";
38
+ /** Spec phase only */
39
+ readonly SPEC_ONLY: "sequant:spec-only";
40
+ /** Exec phase only */
41
+ readonly EXEC: "sequant:exec";
42
+ /** QA phase only */
43
+ readonly QA: "sequant:qa";
44
+ };
45
+ /**
46
+ * Labels used for lifecycle tracking.
47
+ */
48
+ export declare const LIFECYCLE_LABELS: {
49
+ /** Applied when a run starts */
50
+ readonly SOLVING: "sequant:solving";
51
+ /** Applied on successful completion */
52
+ readonly DONE: "sequant:done";
53
+ /** Applied on failure */
54
+ readonly FAILED: "sequant:failed";
55
+ };
56
+ /**
57
+ * Result of parsing a GitHub event into a trigger.
58
+ */
59
+ export interface TriggerResult {
60
+ /** Type of trigger detected */
61
+ trigger: TriggerType;
62
+ /** Phases to execute */
63
+ phases: Phase[];
64
+ /** Issue number extracted from the event */
65
+ issue: number | null;
66
+ /** The label that triggered the action (if label trigger) */
67
+ label?: string;
68
+ }
69
+ /**
70
+ * GitHub Actions event payload (subset of fields we use).
71
+ */
72
+ export interface GitHubEventPayload {
73
+ action?: string;
74
+ issue?: {
75
+ number: number;
76
+ labels?: Array<{
77
+ name: string;
78
+ }>;
79
+ };
80
+ label?: {
81
+ name: string;
82
+ };
83
+ comment?: {
84
+ body: string;
85
+ };
86
+ }
87
+ /**
88
+ * GitHub Actions context (subset of fields we use).
89
+ */
90
+ export interface GitHubContext {
91
+ eventName: string;
92
+ payload: GitHubEventPayload;
93
+ }
94
+ /**
95
+ * Structured action outputs set via $GITHUB_OUTPUT.
96
+ */
97
+ export interface ActionOutputs {
98
+ /** The issue number(s) processed */
99
+ issue: string;
100
+ /** Whether all phases passed */
101
+ success: string;
102
+ /** JSON array of phase results */
103
+ phases: string;
104
+ /** URL of created PR (empty if no PR) */
105
+ "pr-url": string;
106
+ /** Total duration in seconds */
107
+ duration: string;
108
+ }
109
+ /**
110
+ * Repository-level CI configuration from .github/sequant.yml.
111
+ */
112
+ export interface CIConfig {
113
+ /** Default agent backend */
114
+ agent?: string;
115
+ /** Default phases to execute */
116
+ phases?: Phase[];
117
+ /** Default phase timeout in seconds */
118
+ timeout?: number;
119
+ /** Enable quality loop by default */
120
+ qualityLoop?: boolean;
121
+ /** Maximum concurrent workflow runs */
122
+ maxConcurrentRuns?: number;
123
+ }
124
+ /**
125
+ * Merge precedence: workflow inputs > config file > action defaults.
126
+ */
127
+ export declare const CI_DEFAULTS: Required<CIConfig>;
128
+ /**
129
+ * Pattern for matching @sequant commands in issue comments.
130
+ */
131
+ export declare const COMMENT_TRIGGER_PATTERN: RegExp;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Types for GitHub Actions CI integration.
3
+ *
4
+ * These types model the inputs, outputs, triggers, and configuration
5
+ * that the sequant GitHub Action uses to bridge GitHub events to
6
+ * sequant workflow execution.
7
+ */
8
+ /**
9
+ * Labels that map to specific phase configurations.
10
+ */
11
+ export const TRIGGER_LABELS = {
12
+ /** Full workflow: spec → exec → qa */
13
+ ASSESS: "sequant:assess",
14
+ /** @deprecated Use ASSESS instead */
15
+ SOLVE: "sequant:solve",
16
+ /** Spec phase only */
17
+ SPEC_ONLY: "sequant:spec-only",
18
+ /** Exec phase only */
19
+ EXEC: "sequant:exec",
20
+ /** QA phase only */
21
+ QA: "sequant:qa",
22
+ };
23
+ /**
24
+ * Labels used for lifecycle tracking.
25
+ */
26
+ export const LIFECYCLE_LABELS = {
27
+ /** Applied when a run starts */
28
+ SOLVING: "sequant:solving",
29
+ /** Applied on successful completion */
30
+ DONE: "sequant:done",
31
+ /** Applied on failure */
32
+ FAILED: "sequant:failed",
33
+ };
34
+ /**
35
+ * Merge precedence: workflow inputs > config file > action defaults.
36
+ */
37
+ export const CI_DEFAULTS = {
38
+ agent: "claude-code",
39
+ phases: ["spec", "exec", "qa"],
40
+ timeout: 1800,
41
+ qualityLoop: false,
42
+ maxConcurrentRuns: 1,
43
+ };
44
+ /**
45
+ * Pattern for matching @sequant commands in issue comments.
46
+ */
47
+ export const COMMENT_TRIGGER_PATTERN = /^@sequant\s+run\s+([\w,-]+)\s*$/m;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * MCP client detection and configuration
3
+ *
4
+ * Detects installed MCP clients (Claude Desktop, Cursor, VS Code)
5
+ * and generates appropriate configuration entries for Sequant MCP server.
6
+ */
7
+ /** Path to the project-level MCP config file used by Claude Code */
8
+ export declare const PROJECT_MCP_JSON = ".mcp.json";
9
+ export type McpClientType = "claude-desktop" | "cursor" | "vscode-continue";
10
+ export interface McpClientInfo {
11
+ name: string;
12
+ clientType: McpClientType;
13
+ configPath: string;
14
+ exists: boolean;
15
+ }
16
+ /**
17
+ * Sequant MCP server configuration entry.
18
+ *
19
+ * @param options.projectDir - Absolute project path (used as cwd for clients that need it)
20
+ * @param options.clientType - Target client; determines whether cwd/env are included
21
+ */
22
+ export declare function getSequantMcpConfig(options?: {
23
+ projectDir?: string;
24
+ clientType?: McpClientType;
25
+ }): Record<string, unknown>;
26
+ /**
27
+ * Detect which MCP-compatible clients are installed
28
+ */
29
+ export declare function detectMcpClients(): McpClientInfo[];
30
+ /**
31
+ * Add Sequant MCP server to a client's config file.
32
+ * Returns true if written, false if already configured.
33
+ */
34
+ export declare function addSequantToMcpConfig(configPath: string, clientType?: McpClientType): boolean;
35
+ /**
36
+ * Check whether .mcp.json already has a sequant server entry.
37
+ */
38
+ export declare function isSequantInProjectMcpJson(projectDir?: string): boolean;
39
+ export interface ProjectMcpJsonResult {
40
+ created: boolean;
41
+ merged: boolean;
42
+ skipped: boolean;
43
+ }
44
+ /**
45
+ * Create or update .mcp.json in the project root for Claude Code.
46
+ *
47
+ * - If .mcp.json doesn't exist → create it with the sequant server entry
48
+ * - If .mcp.json exists with a sequant entry → skip (already configured)
49
+ * - If .mcp.json exists without a sequant entry → merge it in
50
+ *
51
+ * Unlike global client configs, .mcp.json does NOT include cwd or env
52
+ * because Claude Code runs from the project root.
53
+ */
54
+ export declare function createProjectMcpJson(projectDir?: string): ProjectMcpJsonResult;