@bradtaylorsf/alpha-loop 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +294 -0
  3. package/agents/implementer.md +30 -0
  4. package/agents/reviewer.md +29 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +57 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/auth.d.ts +1 -0
  9. package/dist/commands/auth.js +89 -0
  10. package/dist/commands/auth.js.map +1 -0
  11. package/dist/commands/history.d.ts +8 -0
  12. package/dist/commands/history.js +185 -0
  13. package/dist/commands/history.js.map +1 -0
  14. package/dist/commands/init.d.ts +1 -0
  15. package/dist/commands/init.js +241 -0
  16. package/dist/commands/init.js.map +1 -0
  17. package/dist/commands/run.d.ts +15 -0
  18. package/dist/commands/run.js +321 -0
  19. package/dist/commands/run.js.map +1 -0
  20. package/dist/commands/scan.d.ts +1 -0
  21. package/dist/commands/scan.js +50 -0
  22. package/dist/commands/scan.js.map +1 -0
  23. package/dist/commands/sync.d.ts +20 -0
  24. package/dist/commands/sync.js +149 -0
  25. package/dist/commands/sync.js.map +1 -0
  26. package/dist/commands/vision.d.ts +1 -0
  27. package/dist/commands/vision.js +194 -0
  28. package/dist/commands/vision.js.map +1 -0
  29. package/dist/engine/agents.d.ts +41 -0
  30. package/dist/engine/agents.js +90 -0
  31. package/dist/engine/agents.js.map +1 -0
  32. package/dist/engine/config.d.ts +71 -0
  33. package/dist/engine/config.js +73 -0
  34. package/dist/engine/config.js.map +1 -0
  35. package/dist/engine/prerequisites.d.ts +34 -0
  36. package/dist/engine/prerequisites.js +90 -0
  37. package/dist/engine/prerequisites.js.map +1 -0
  38. package/dist/lib/agent.d.ts +25 -0
  39. package/dist/lib/agent.js +97 -0
  40. package/dist/lib/agent.js.map +1 -0
  41. package/dist/lib/config.d.ts +35 -0
  42. package/dist/lib/config.js +179 -0
  43. package/dist/lib/config.js.map +1 -0
  44. package/dist/lib/context.d.ts +17 -0
  45. package/dist/lib/context.js +96 -0
  46. package/dist/lib/context.js.map +1 -0
  47. package/dist/lib/github.d.ts +61 -0
  48. package/dist/lib/github.js +313 -0
  49. package/dist/lib/github.js.map +1 -0
  50. package/dist/lib/learning.d.ts +43 -0
  51. package/dist/lib/learning.js +207 -0
  52. package/dist/lib/learning.js.map +1 -0
  53. package/dist/lib/logger.d.ts +9 -0
  54. package/dist/lib/logger.js +28 -0
  55. package/dist/lib/logger.js.map +1 -0
  56. package/dist/lib/pipeline.d.ts +18 -0
  57. package/dist/lib/pipeline.js +456 -0
  58. package/dist/lib/pipeline.js.map +1 -0
  59. package/dist/lib/preflight.d.ts +33 -0
  60. package/dist/lib/preflight.js +123 -0
  61. package/dist/lib/preflight.js.map +1 -0
  62. package/dist/lib/prerequisites.d.ts +12 -0
  63. package/dist/lib/prerequisites.js +54 -0
  64. package/dist/lib/prerequisites.js.map +1 -0
  65. package/dist/lib/prompts.d.ts +44 -0
  66. package/dist/lib/prompts.js +102 -0
  67. package/dist/lib/prompts.js.map +1 -0
  68. package/dist/lib/session.d.ts +28 -0
  69. package/dist/lib/session.js +173 -0
  70. package/dist/lib/session.js.map +1 -0
  71. package/dist/lib/shell.d.ts +32 -0
  72. package/dist/lib/shell.js +95 -0
  73. package/dist/lib/shell.js.map +1 -0
  74. package/dist/lib/testing.d.ts +10 -0
  75. package/dist/lib/testing.js +51 -0
  76. package/dist/lib/testing.js.map +1 -0
  77. package/dist/lib/verify.d.ts +18 -0
  78. package/dist/lib/verify.js +235 -0
  79. package/dist/lib/verify.js.map +1 -0
  80. package/dist/lib/vision.d.ts +9 -0
  81. package/dist/lib/vision.js +21 -0
  82. package/dist/lib/vision.js.map +1 -0
  83. package/dist/lib/worktree.d.ts +29 -0
  84. package/dist/lib/worktree.js +153 -0
  85. package/dist/lib/worktree.js.map +1 -0
  86. package/package.json +63 -0
  87. package/templates/agents/implementer.md +34 -0
  88. package/templates/agents/reviewer.md +48 -0
  89. package/templates/skills/code-review/SKILL.md +58 -0
  90. package/templates/skills/git-workflow/SKILL.md +53 -0
  91. package/templates/skills/implementation-planning/SKILL.md +64 -0
  92. package/templates/skills/security-analysis/SKILL.md +560 -0
  93. package/templates/skills/security-analysis/scripts/security-scanner.sh +227 -0
  94. package/templates/skills/test-robustness/SKILL.md +897 -0
  95. package/templates/skills/testing-patterns/SKILL.md +75 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Agent Runner — spawn AI agents with real-time output streaming.
3
+ */
4
+ import { spawn } from 'node:child_process';
5
+ import { createWriteStream } from 'node:fs';
6
+ import { log } from './logger.js';
7
+ /**
8
+ * Build CLI command and args for a given agent type.
9
+ */
10
+ export function buildAgentArgs(options) {
11
+ switch (options.agent) {
12
+ case 'claude': {
13
+ const args = [
14
+ '-p',
15
+ '--model', options.model,
16
+ '--dangerously-skip-permissions',
17
+ '--verbose',
18
+ '--output-format', 'text',
19
+ ];
20
+ // Note: --max-turns intentionally omitted. Let the agent finish naturally.
21
+ // The harness controls retry limits via maxTestRetries, not agent turn limits.
22
+ return { command: 'claude', args };
23
+ }
24
+ case 'codex': {
25
+ const args = [
26
+ '-q',
27
+ '--model', options.model,
28
+ '--auto-edit',
29
+ ];
30
+ return { command: 'codex', args };
31
+ }
32
+ case 'opencode': {
33
+ const args = [
34
+ 'run',
35
+ '--model', options.model,
36
+ ];
37
+ return { command: 'opencode', args };
38
+ }
39
+ default:
40
+ throw new Error(`Unknown agent type: ${options.agent}`);
41
+ }
42
+ }
43
+ /**
44
+ * Spawn an AI agent with a prompt.
45
+ * Streams output to terminal in real-time while capturing it.
46
+ */
47
+ export async function spawnAgent(options) {
48
+ const { command, args } = buildAgentArgs(options);
49
+ log.info(`Agent: ${options.agent} | Model: ${options.model} | CWD: ${options.cwd}`);
50
+ const startTime = Date.now();
51
+ const chunks = [];
52
+ let logStream;
53
+ if (options.logFile) {
54
+ logStream = createWriteStream(options.logFile, { flags: 'w' });
55
+ }
56
+ return new Promise((resolve) => {
57
+ const child = spawn(command, args, {
58
+ cwd: options.cwd,
59
+ stdio: ['pipe', 'pipe', 'pipe'],
60
+ });
61
+ // Pipe prompt via stdin (like: echo "$prompt" | claude -p)
62
+ child.stdin.write(options.prompt);
63
+ child.stdin.end();
64
+ const handleData = (data) => {
65
+ const text = data.toString();
66
+ chunks.push(text);
67
+ // Stream to terminal only when verbose is enabled
68
+ if (options.verbose) {
69
+ process.stderr.write(data);
70
+ }
71
+ // Always write to log file if provided
72
+ if (logStream) {
73
+ logStream.write(data);
74
+ }
75
+ };
76
+ child.stdout.on('data', handleData);
77
+ child.stderr.on('data', handleData);
78
+ const finish = (exitCode, output) => {
79
+ const duration = Date.now() - startTime;
80
+ if (logStream) {
81
+ logStream.end(() => {
82
+ resolve({ exitCode, output, duration });
83
+ });
84
+ }
85
+ else {
86
+ resolve({ exitCode, output, duration });
87
+ }
88
+ };
89
+ child.on('close', (code) => {
90
+ finish(code ?? 1, chunks.join(''));
91
+ });
92
+ child.on('error', (err) => {
93
+ finish(1, `Failed to spawn ${command}: ${err.message}`);
94
+ });
95
+ });
96
+ }
97
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/lib/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export type Config = {
2
+ repo: string;
3
+ repoOwner: string;
4
+ project: number;
5
+ model: string;
6
+ reviewModel: string;
7
+ pollInterval: number;
8
+ dryRun: boolean;
9
+ baseBranch: string;
10
+ logDir: string;
11
+ labelReady: string;
12
+ maxTestRetries: number;
13
+ testCommand: string;
14
+ devCommand: string;
15
+ port: number;
16
+ skipTests: boolean;
17
+ skipReview: boolean;
18
+ skipInstall: boolean;
19
+ skipPreflight: boolean;
20
+ skipVerify: boolean;
21
+ skipLearn: boolean;
22
+ skipE2e: boolean;
23
+ maxIssues: number;
24
+ maxSessionDuration: number;
25
+ milestone: string;
26
+ autoMerge: boolean;
27
+ mergeTo: string;
28
+ autoCleanup: boolean;
29
+ runFull: boolean;
30
+ verbose: boolean;
31
+ };
32
+ /** Validate a string contains only safe shell characters. */
33
+ export declare function assertSafeShellArg(value: string, name: string): string;
34
+ export declare function detectRepo(): string | null;
35
+ export declare function loadConfig(overrides?: Partial<Config>): Config;
@@ -0,0 +1,179 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { execSync } from 'node:child_process';
3
+ import { parse as parseYaml } from 'yaml';
4
+ const DEFAULTS = {
5
+ repo: '',
6
+ repoOwner: '',
7
+ project: 2,
8
+ model: 'opus',
9
+ reviewModel: 'opus',
10
+ pollInterval: 60,
11
+ dryRun: false,
12
+ baseBranch: 'master',
13
+ logDir: 'logs',
14
+ labelReady: 'ready',
15
+ maxTestRetries: 3,
16
+ testCommand: 'pnpm test',
17
+ devCommand: 'pnpm dev',
18
+ port: 3000,
19
+ skipTests: false,
20
+ skipReview: false,
21
+ skipInstall: false,
22
+ skipPreflight: false,
23
+ skipVerify: false,
24
+ skipLearn: false,
25
+ skipE2e: false,
26
+ maxIssues: 0,
27
+ maxSessionDuration: 0,
28
+ milestone: '',
29
+ autoMerge: true,
30
+ mergeTo: '',
31
+ autoCleanup: true,
32
+ runFull: false,
33
+ verbose: false,
34
+ };
35
+ /** Map from YAML key (snake_case) to Config key (camelCase). */
36
+ const YAML_KEY_MAP = {
37
+ repo: 'repo',
38
+ project: 'project',
39
+ model: 'model',
40
+ review_model: 'reviewModel',
41
+ poll_interval: 'pollInterval',
42
+ dry_run: 'dryRun',
43
+ base_branch: 'baseBranch',
44
+ log_dir: 'logDir',
45
+ label: 'labelReady',
46
+ max_test_retries: 'maxTestRetries',
47
+ test_command: 'testCommand',
48
+ dev_command: 'devCommand',
49
+ port: 'port',
50
+ skip_tests: 'skipTests',
51
+ skip_review: 'skipReview',
52
+ skip_install: 'skipInstall',
53
+ skip_preflight: 'skipPreflight',
54
+ skip_verify: 'skipVerify',
55
+ skip_learn: 'skipLearn',
56
+ skip_e2e: 'skipE2e',
57
+ max_issues: 'maxIssues',
58
+ max_session_duration: 'maxSessionDuration',
59
+ milestone: 'milestone',
60
+ auto_merge: 'autoMerge',
61
+ merge_to: 'mergeTo',
62
+ auto_cleanup: 'autoCleanup',
63
+ run_full: 'runFull',
64
+ verbose: 'verbose',
65
+ };
66
+ /** Map from env var name to Config key. */
67
+ const ENV_KEY_MAP = {
68
+ REPO: 'repo',
69
+ PROJECT_NUM: 'project',
70
+ MODEL: 'model',
71
+ REVIEW_MODEL: 'reviewModel',
72
+ POLL_INTERVAL: 'pollInterval',
73
+ DRY_RUN: 'dryRun',
74
+ BASE_BRANCH: 'baseBranch',
75
+ LOG_DIR: 'logDir',
76
+ LABEL_READY: 'labelReady',
77
+ MAX_TEST_RETRIES: 'maxTestRetries',
78
+ TEST_COMMAND: 'testCommand',
79
+ DEV_COMMAND: 'devCommand',
80
+ PORT: 'port',
81
+ SKIP_TESTS: 'skipTests',
82
+ SKIP_REVIEW: 'skipReview',
83
+ SKIP_INSTALL: 'skipInstall',
84
+ SKIP_PREFLIGHT: 'skipPreflight',
85
+ SKIP_VERIFY: 'skipVerify',
86
+ SKIP_LEARN: 'skipLearn',
87
+ SKIP_E2E: 'skipE2e',
88
+ MAX_ISSUES: 'maxIssues',
89
+ MAX_SESSION_DURATION: 'maxSessionDuration',
90
+ MILESTONE: 'milestone',
91
+ AUTO_MERGE: 'autoMerge',
92
+ MERGE_TO: 'mergeTo',
93
+ AUTO_CLEANUP: 'autoCleanup',
94
+ RUN_FULL: 'runFull',
95
+ VERBOSE: 'verbose',
96
+ };
97
+ function coerce(value, current) {
98
+ if (typeof current === 'number')
99
+ return Number(value);
100
+ if (typeof current === 'boolean')
101
+ return value === 'true' || value === '1';
102
+ return value;
103
+ }
104
+ /** Validate a string contains only safe shell characters. */
105
+ export function assertSafeShellArg(value, name) {
106
+ if (!/^[a-zA-Z0-9._\-/]+$/.test(value)) {
107
+ throw new Error(`Invalid ${name}: contains unsafe characters: ${value}`);
108
+ }
109
+ return value;
110
+ }
111
+ export function detectRepo() {
112
+ try {
113
+ const url = execSync('git remote get-url origin', {
114
+ encoding: 'utf-8',
115
+ stdio: ['pipe', 'pipe', 'pipe'],
116
+ }).trim();
117
+ // HTTPS: https://github.com/owner/repo.git
118
+ const https = url.match(/github\.com\/([^/]+)\/([^/.]+)/);
119
+ if (https)
120
+ return `${https[1]}/${https[2]}`;
121
+ // SSH: git@github.com:owner/repo.git
122
+ const ssh = url.match(/github\.com:([^/]+)\/([^/.]+)/);
123
+ if (ssh)
124
+ return `${ssh[1]}/${ssh[2]}`;
125
+ }
126
+ catch {
127
+ // Not a git repo or no remote
128
+ }
129
+ return null;
130
+ }
131
+ function loadYamlConfig(configPath) {
132
+ if (!existsSync(configPath))
133
+ return {};
134
+ const raw = readFileSync(configPath, 'utf-8');
135
+ const parsed = parseYaml(raw);
136
+ if (!parsed || typeof parsed !== 'object')
137
+ return {};
138
+ const result = {};
139
+ for (const [yamlKey, configKey] of Object.entries(YAML_KEY_MAP)) {
140
+ if (yamlKey in parsed) {
141
+ result[configKey] = parsed[yamlKey];
142
+ }
143
+ }
144
+ return result;
145
+ }
146
+ function loadEnvConfig() {
147
+ const result = {};
148
+ for (const [envKey, configKey] of Object.entries(ENV_KEY_MAP)) {
149
+ const val = process.env[envKey];
150
+ if (val !== undefined) {
151
+ result[configKey] = coerce(val, DEFAULTS[configKey]);
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+ export function loadConfig(overrides) {
157
+ const yamlConfig = loadYamlConfig('.alpha-loop.yaml');
158
+ const envConfig = loadEnvConfig();
159
+ // Auto-detect repo if not set by any source
160
+ const detectedRepo = detectRepo();
161
+ const autoDetect = {};
162
+ if (detectedRepo) {
163
+ autoDetect.repo = detectedRepo;
164
+ }
165
+ // Precedence: overrides (CLI flags) > env vars > config file > auto-detect > defaults
166
+ const merged = {
167
+ ...DEFAULTS,
168
+ ...autoDetect,
169
+ ...yamlConfig,
170
+ ...envConfig,
171
+ ...overrides,
172
+ };
173
+ // Derive repoOwner from repo
174
+ if (merged.repo) {
175
+ merged.repoOwner = merged.repo.split('/')[0] ?? '';
176
+ }
177
+ return merged;
178
+ }
179
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { type ExecResult } from './shell.js';
2
+ /**
3
+ * Generate a fresh project context file by invoking the configured agent.
4
+ */
5
+ export declare function generateProjectContext(projectDir: string, agentCommand: string, executor?: (cmd: string, cwd?: string) => Promise<ExecResult>): Promise<void>;
6
+ /**
7
+ * Read the current project context, or null if it doesn't exist.
8
+ */
9
+ export declare function getProjectContext(projectDir?: string): string | null;
10
+ /**
11
+ * Check if context needs refreshing (older than 4 hours or doesn't exist).
12
+ */
13
+ export declare function contextNeedsRefresh(projectDir?: string, now?: number): boolean;
14
+ /**
15
+ * Update context after a successful run by appending a summary under ## Active State.
16
+ */
17
+ export declare function updateContextAfterRun(issueNum: number, title: string, status: string, filesChanged: number, projectDir?: string): void;
@@ -0,0 +1,96 @@
1
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { execAsync } from './shell.js';
4
+ import { log } from './logger.js';
5
+ const CONTEXT_DIR = '.alpha-loop';
6
+ const CONTEXT_FILE = join(CONTEXT_DIR, 'context.md');
7
+ // Context expires after 4 hours
8
+ const CONTEXT_MAX_AGE_MS = 4 * 60 * 60 * 1000;
9
+ const SCAN_PROMPT = `Analyze this codebase and produce a concise project context file. Read the key files (package.json, entry points, config files, README, CLAUDE.md) and output ONLY this markdown structure:
10
+
11
+ ## Architecture
12
+ - Entry points and how they connect (e.g., "Express server in src/server/index.ts mounts routes from routes/*.ts")
13
+ - Database (type, schema location, how to query)
14
+ - Key directories and what they contain
15
+
16
+ ## Conventions
17
+ - Language, framework, coding patterns used
18
+ - How tests are structured and run
19
+ - How new features should be wired in (e.g., "new routes must be imported in index.ts")
20
+
21
+ ## Critical Rules
22
+ - Files/directories that must not be deleted or modified without care
23
+ - Integration points that break if not updated together
24
+ - Common mistakes to avoid in this codebase
25
+
26
+ ## Active State
27
+ - Test status: (will be filled in by the loop)
28
+ - Recent changes: (will be filled in by the loop)
29
+
30
+ Keep each section to 3-5 bullet points. Be specific to THIS codebase, not generic advice. Under 400 words total.`;
31
+ /**
32
+ * Generate a fresh project context file by invoking the configured agent.
33
+ */
34
+ export async function generateProjectContext(projectDir, agentCommand, executor = execAsync) {
35
+ const contextDir = join(projectDir, CONTEXT_DIR);
36
+ const contextFile = join(projectDir, CONTEXT_FILE);
37
+ if (!existsSync(contextDir)) {
38
+ mkdirSync(contextDir, { recursive: true });
39
+ }
40
+ const escapedPrompt = SCAN_PROMPT.replace(/'/g, "'\\''");
41
+ const cmd = `echo '${escapedPrompt}' | ${agentCommand} -p --output-format text 2>/dev/null`;
42
+ const result = await executor(cmd, projectDir);
43
+ if (result.exitCode !== 0 || !result.stdout.trim()) {
44
+ log.warn(`Project context generation failed (exit ${result.exitCode})`);
45
+ return;
46
+ }
47
+ writeFileSync(contextFile, result.stdout, 'utf-8');
48
+ }
49
+ /**
50
+ * Read the current project context, or null if it doesn't exist.
51
+ */
52
+ export function getProjectContext(projectDir = '.') {
53
+ const contextFile = join(projectDir, CONTEXT_FILE);
54
+ if (!existsSync(contextFile)) {
55
+ return null;
56
+ }
57
+ return readFileSync(contextFile, 'utf-8');
58
+ }
59
+ /**
60
+ * Check if context needs refreshing (older than 4 hours or doesn't exist).
61
+ */
62
+ export function contextNeedsRefresh(projectDir = '.', now = Date.now()) {
63
+ const contextFile = join(projectDir, CONTEXT_FILE);
64
+ if (!existsSync(contextFile)) {
65
+ return true;
66
+ }
67
+ const mtime = statSync(contextFile).mtimeMs;
68
+ return (now - mtime) >= CONTEXT_MAX_AGE_MS;
69
+ }
70
+ /**
71
+ * Update context after a successful run by appending a summary under ## Active State.
72
+ */
73
+ export function updateContextAfterRun(issueNum, title, status, filesChanged, projectDir = '.') {
74
+ const contextFile = join(projectDir, CONTEXT_FILE);
75
+ if (!existsSync(contextFile)) {
76
+ return;
77
+ }
78
+ const timestamp = new Date().toISOString().replace(/\.\d+Z$/, '');
79
+ const entry = `- [${timestamp}] #${issueNum} ${title} (${status}) — ${filesChanged} files changed`;
80
+ const content = readFileSync(contextFile, 'utf-8');
81
+ const marker = '## Active State';
82
+ const markerIndex = content.indexOf(marker);
83
+ if (markerIndex === -1) {
84
+ return;
85
+ }
86
+ // Insert the entry on the line after the marker
87
+ const insertPos = content.indexOf('\n', markerIndex);
88
+ if (insertPos === -1) {
89
+ // Marker is at end of file
90
+ writeFileSync(contextFile, content + '\n' + entry + '\n', 'utf-8');
91
+ return;
92
+ }
93
+ const updated = content.slice(0, insertPos + 1) + entry + '\n' + content.slice(insertPos + 1);
94
+ writeFileSync(contextFile, updated, 'utf-8');
95
+ }
96
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/lib/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ export type Issue = {
2
+ number: number;
3
+ title: string;
4
+ body: string;
5
+ labels: string[];
6
+ };
7
+ export type Milestone = {
8
+ number: number;
9
+ title: string;
10
+ description: string;
11
+ openIssues: number;
12
+ closedIssues: number;
13
+ dueOn: string | null;
14
+ state: string;
15
+ };
16
+ /**
17
+ * List open milestones for a repository.
18
+ */
19
+ export declare function listMilestones(repo: string): Milestone[];
20
+ /**
21
+ * Fetch issues to process. When a project board is configured, reads from
22
+ * the board in display order (the order you set by dragging), filtered to
23
+ * "Todo" status. Falls back to label-based polling when no project is set.
24
+ *
25
+ * When a milestone is specified, only issues in that milestone are returned.
26
+ */
27
+ export declare function pollIssues(repo: string, label: string, limit?: number, options?: {
28
+ project?: number;
29
+ repoOwner?: string;
30
+ milestone?: string;
31
+ }): Issue[];
32
+ /**
33
+ * Add/remove labels on an issue.
34
+ */
35
+ export declare function labelIssue(repo: string, issueNum: number, addLabel: string, removeLabel?: string): void;
36
+ /**
37
+ * Comment on an issue.
38
+ */
39
+ export declare function commentIssue(repo: string, issueNum: number, body: string): void;
40
+ export type CreatePROptions = {
41
+ repo: string;
42
+ base: string;
43
+ head: string;
44
+ title: string;
45
+ body: string;
46
+ cwd?: string;
47
+ };
48
+ /**
49
+ * Create a PR, or update an existing one if a PR already exists for the branch.
50
+ * Returns the PR URL.
51
+ */
52
+ export declare function createPR(options: CreatePROptions): string;
53
+ /**
54
+ * Merge a PR by branch name.
55
+ */
56
+ export declare function mergePR(repo: string, head: string, method?: 'squash' | 'merge'): void;
57
+ /**
58
+ * Update project board status for an issue.
59
+ * This is a multi-step operation using gh project commands.
60
+ */
61
+ export declare function updateProjectStatus(repo: string, projectNum: number, owner: string, issueNum: number, status: string): void;