whitesmith 0.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 (70) hide show
  1. package/dist/__tests__/task-manager.test.d.ts +2 -0
  2. package/dist/__tests__/task-manager.test.d.ts.map +1 -0
  3. package/dist/__tests__/task-manager.test.js +95 -0
  4. package/dist/__tests__/task-manager.test.js.map +1 -0
  5. package/dist/cli.d.ts +5 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +147 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/git.d.ts +60 -0
  10. package/dist/git.d.ts.map +1 -0
  11. package/dist/git.js +138 -0
  12. package/dist/git.js.map +1 -0
  13. package/dist/harnesses/agent-harness.d.ts +19 -0
  14. package/dist/harnesses/agent-harness.d.ts.map +1 -0
  15. package/dist/harnesses/agent-harness.js +2 -0
  16. package/dist/harnesses/agent-harness.js.map +1 -0
  17. package/dist/harnesses/index.d.ts +3 -0
  18. package/dist/harnesses/index.d.ts.map +1 -0
  19. package/dist/harnesses/index.js +2 -0
  20. package/dist/harnesses/index.js.map +1 -0
  21. package/dist/harnesses/pi.d.ts +23 -0
  22. package/dist/harnesses/pi.d.ts.map +1 -0
  23. package/dist/harnesses/pi.js +63 -0
  24. package/dist/harnesses/pi.js.map +1 -0
  25. package/dist/index.d.ts +11 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +8 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/orchestrator.d.ts +44 -0
  30. package/dist/orchestrator.d.ts.map +1 -0
  31. package/dist/orchestrator.js +241 -0
  32. package/dist/orchestrator.js.map +1 -0
  33. package/dist/prompts.d.ts +12 -0
  34. package/dist/prompts.d.ts.map +1 -0
  35. package/dist/prompts.js +112 -0
  36. package/dist/prompts.js.map +1 -0
  37. package/dist/providers/github.d.ts +34 -0
  38. package/dist/providers/github.d.ts.map +1 -0
  39. package/dist/providers/github.js +135 -0
  40. package/dist/providers/github.js.map +1 -0
  41. package/dist/providers/index.d.ts +3 -0
  42. package/dist/providers/index.d.ts.map +1 -0
  43. package/dist/providers/index.js +2 -0
  44. package/dist/providers/index.js.map +1 -0
  45. package/dist/providers/issue-provider.d.ts +59 -0
  46. package/dist/providers/issue-provider.d.ts.map +1 -0
  47. package/dist/providers/issue-provider.js +2 -0
  48. package/dist/providers/issue-provider.js.map +1 -0
  49. package/dist/task-manager.d.ts +57 -0
  50. package/dist/task-manager.d.ts.map +1 -0
  51. package/dist/task-manager.js +158 -0
  52. package/dist/task-manager.js.map +1 -0
  53. package/dist/types.d.ts +92 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +14 -0
  56. package/dist/types.js.map +1 -0
  57. package/package.json +46 -0
  58. package/src/cli.ts +172 -0
  59. package/src/git.ts +148 -0
  60. package/src/harnesses/agent-harness.ts +15 -0
  61. package/src/harnesses/index.ts +2 -0
  62. package/src/harnesses/pi.ts +82 -0
  63. package/src/index.ts +13 -0
  64. package/src/orchestrator.ts +294 -0
  65. package/src/prompts.ts +114 -0
  66. package/src/providers/github.ts +180 -0
  67. package/src/providers/index.ts +2 -0
  68. package/src/providers/issue-provider.ts +59 -0
  69. package/src/task-manager.ts +190 -0
  70. package/src/types.ts +88 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=task-manager.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-manager.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/task-manager.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,95 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import * as os from 'node:os';
5
+ import { TaskManager } from '../task-manager.js';
6
+ describe('TaskManager', () => {
7
+ let tmpDir;
8
+ let mgr;
9
+ beforeEach(() => {
10
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dev-pulse-test-'));
11
+ mgr = new TaskManager(tmpDir);
12
+ });
13
+ afterEach(() => {
14
+ fs.rmSync(tmpDir, { recursive: true, force: true });
15
+ });
16
+ function writeTaskFile(issueNumber, seq, slug, extra = '') {
17
+ const dir = path.join(tmpDir, 'tasks', String(issueNumber));
18
+ fs.mkdirSync(dir, { recursive: true });
19
+ const seqStr = String(seq).padStart(3, '0');
20
+ const id = `${issueNumber}-${seqStr}`;
21
+ const content = `---
22
+ id: "${id}"
23
+ issue: ${issueNumber}
24
+ title: "Task ${seq} for issue ${issueNumber}"
25
+ depends_on: [${extra}]
26
+ ---
27
+
28
+ ## Description
29
+ Test task.
30
+ `;
31
+ fs.writeFileSync(path.join(dir, `${seqStr}-task-${seq}.md`), content);
32
+ return id;
33
+ }
34
+ it('lists tasks for an issue', () => {
35
+ writeTaskFile(42, 1, 'first');
36
+ writeTaskFile(42, 2, 'second');
37
+ const tasks = mgr.listTasks(42);
38
+ expect(tasks).toHaveLength(2);
39
+ expect(tasks[0].id).toBe('42-001');
40
+ expect(tasks[1].id).toBe('42-002');
41
+ });
42
+ it('returns empty for non-existent issue', () => {
43
+ expect(mgr.listTasks(999)).toHaveLength(0);
44
+ });
45
+ it('lists all tasks across issues', () => {
46
+ writeTaskFile(1, 1, 'a');
47
+ writeTaskFile(2, 1, 'b');
48
+ writeTaskFile(2, 2, 'c');
49
+ const all = mgr.listAllTasks();
50
+ expect(all).toHaveLength(3);
51
+ });
52
+ it('checks remaining tasks', () => {
53
+ writeTaskFile(42, 1, 'a');
54
+ expect(mgr.hasRemainingTasks(42)).toBe(true);
55
+ expect(mgr.hasRemainingTasks(99)).toBe(false);
56
+ });
57
+ it('writes a task file', () => {
58
+ const relPath = mgr.writeTask(10, 1, 'setup-database', { id: '10-001', issue: 10, title: 'Setup database' }, '## Description\nCreate the database schema.');
59
+ expect(relPath).toBe('tasks/10/001-setup-database.md');
60
+ const tasks = mgr.listTasks(10);
61
+ expect(tasks).toHaveLength(1);
62
+ expect(tasks[0].title).toBe('Setup database');
63
+ });
64
+ it('deletes a task file', () => {
65
+ writeTaskFile(42, 1, 'a');
66
+ const tasks = mgr.listTasks(42);
67
+ expect(tasks).toHaveLength(1);
68
+ mgr.deleteTask(tasks[0].filePath);
69
+ expect(mgr.listTasks(42)).toHaveLength(0);
70
+ // Directory should be cleaned up
71
+ expect(fs.existsSync(path.join(tmpDir, 'tasks', '42'))).toBe(false);
72
+ });
73
+ it('checks dependency satisfaction', () => {
74
+ writeTaskFile(42, 1, 'first');
75
+ writeTaskFile(42, 2, 'second', '"42-001"');
76
+ const tasks = mgr.listTasks(42);
77
+ const task1 = tasks.find((t) => t.id === '42-001');
78
+ const task2 = tasks.find((t) => t.id === '42-002');
79
+ // Task 1 has no deps — satisfied
80
+ expect(mgr.areDependenciesSatisfied(task1)).toBe(true);
81
+ // Task 2 depends on task 1 which still exists — not satisfied
82
+ expect(mgr.areDependenciesSatisfied(task2)).toBe(false);
83
+ // Delete task 1 — now task 2's deps are satisfied
84
+ mgr.deleteTask(task1.filePath);
85
+ expect(mgr.areDependenciesSatisfied(task2)).toBe(true);
86
+ });
87
+ it('gets issue numbers with tasks', () => {
88
+ writeTaskFile(5, 1, 'a');
89
+ writeTaskFile(12, 1, 'b');
90
+ writeTaskFile(3, 1, 'c');
91
+ const issues = mgr.getIssuesWithTasks();
92
+ expect(issues).toEqual([3, 5, 12]);
93
+ });
94
+ });
95
+ //# sourceMappingURL=task-manager.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-manager.test.js","sourceRoot":"","sources":["../../src/__tests__/task-manager.test.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ export declare function buildCli(): Command;
4
+ export declare function main(args?: string[]): Promise<void>;
5
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAuBlC,wBAAgB,QAAQ,IAAI,OAAO,CAwIlC;AAED,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvE"}
package/dist/cli.js ADDED
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import * as path from 'node:path';
4
+ import * as fs from 'node:fs';
5
+ import { LABELS } from './types.js';
6
+ import { Orchestrator } from './orchestrator.js';
7
+ import { GitHubProvider } from './providers/github.js';
8
+ import { PiHarness } from './harnesses/pi.js';
9
+ import { TaskManager } from './task-manager.js';
10
+ import pkg from '../package.json' with { type: 'json' };
11
+ const DEFAULT_AGENT_CMD = 'pi';
12
+ const DEFAULT_MAX_ITERATIONS = 10;
13
+ function createOrchestrator(config) {
14
+ const issues = new GitHubProvider(config.workDir, config.repo);
15
+ const agent = new PiHarness(config.agentCmd);
16
+ return new Orchestrator(config, issues, agent);
17
+ }
18
+ const packageName = pkg.name;
19
+ const binName = typeof pkg.bin === 'string' ? pkg.bin : Object.keys(pkg.bin)[0];
20
+ export function buildCli() {
21
+ const program = new Command();
22
+ program.name(binName).description('AI-powered issue-to-PR pipeline').version('0.0.0');
23
+ // --- run ---
24
+ program
25
+ .command('run')
26
+ .description('Run the main whitesmith loop: investigate issues, implement tasks')
27
+ .argument('[work_dir]', 'Working directory', '.')
28
+ .option('--agent-cmd <cmd>', 'Agent harness command', DEFAULT_AGENT_CMD)
29
+ .option('--max-iterations <n>', 'Max iterations', String(DEFAULT_MAX_ITERATIONS))
30
+ .option('--repo <owner/repo>', 'GitHub repo (auto-detected if omitted)')
31
+ .option('--log-file <path>', 'Log agent output to file')
32
+ .option('--no-push', 'Skip pushing and PR creation')
33
+ .option('--no-sleep', 'Skip sleep between iterations')
34
+ .action(async (workDir, opts) => {
35
+ const config = {
36
+ agentCmd: opts.agentCmd,
37
+ maxIterations: parseInt(opts.maxIterations, 10),
38
+ workDir: path.resolve(workDir),
39
+ noPush: opts.push === false,
40
+ noSleep: opts.sleep === false,
41
+ logFile: opts.logFile,
42
+ repo: opts.repo,
43
+ };
44
+ if (!fs.existsSync(config.workDir)) {
45
+ console.error(`ERROR: Directory '${config.workDir}' does not exist`);
46
+ process.exit(1);
47
+ }
48
+ process.chdir(config.workDir);
49
+ const orchestrator = createOrchestrator(config);
50
+ try {
51
+ await orchestrator.run();
52
+ }
53
+ catch (error) {
54
+ console.error('ERROR:', error instanceof Error ? error.message : error);
55
+ process.exit(1);
56
+ }
57
+ });
58
+ // --- status ---
59
+ program
60
+ .command('status')
61
+ .description('Show current status of issues and tasks')
62
+ .argument('[work_dir]', 'Working directory', '.')
63
+ .option('--repo <owner/repo>', 'GitHub repo')
64
+ .action(async (workDir, opts) => {
65
+ const resolvedDir = path.resolve(workDir);
66
+ const issues = new GitHubProvider(resolvedDir, opts.repo);
67
+ const taskMgr = new TaskManager(resolvedDir);
68
+ console.log('=== whitesmith status ===\n');
69
+ // Show issues by state
70
+ for (const [name, label] of Object.entries(LABELS)) {
71
+ const list = await issues.listIssues({ labels: [label] });
72
+ if (list.length > 0) {
73
+ console.log(`${name} (${label}):`);
74
+ for (const issue of list) {
75
+ console.log(` #${issue.number} - ${issue.title}`);
76
+ }
77
+ console.log('');
78
+ }
79
+ }
80
+ // Show new issues (no whitesmith labels)
81
+ const allLabels = Object.values(LABELS);
82
+ const newIssues = await issues.listIssues({ noLabels: allLabels });
83
+ if (newIssues.length > 0) {
84
+ console.log('NEW (no label):');
85
+ for (const issue of newIssues) {
86
+ console.log(` #${issue.number} - ${issue.title}`);
87
+ }
88
+ console.log('');
89
+ }
90
+ // Show pending tasks
91
+ const allTasks = taskMgr.listAllTasks();
92
+ if (allTasks.length > 0) {
93
+ console.log('PENDING TASKS:');
94
+ for (const task of allTasks) {
95
+ const deps = task.dependsOn.length > 0 ? ` (depends: ${task.dependsOn.join(', ')})` : '';
96
+ console.log(` ${task.id} - ${task.title}${deps}`);
97
+ }
98
+ console.log('');
99
+ }
100
+ });
101
+ // --- reconcile ---
102
+ program
103
+ .command('reconcile')
104
+ .description('Check for completed issues and close them (no AI needed)')
105
+ .argument('[work_dir]', 'Working directory', '.')
106
+ .option('--repo <owner/repo>', 'GitHub repo')
107
+ .action(async (workDir, opts) => {
108
+ const resolvedDir = path.resolve(workDir);
109
+ const issues = new GitHubProvider(resolvedDir, opts.repo);
110
+ const taskMgr = new TaskManager(resolvedDir);
111
+ console.log('=== whitesmith reconcile ===\n');
112
+ // Also handle tasks-proposed → tasks-accepted transition
113
+ // When a PR is merged, the tasks land on main, so if we see tasks on disk
114
+ // for an issue labeled tasks-proposed, it means the PR was merged
115
+ const proposedIssues = await issues.listIssues({ labels: [LABELS.TASKS_PROPOSED] });
116
+ for (const issue of proposedIssues) {
117
+ if (taskMgr.hasRemainingTasks(issue.number)) {
118
+ // Tasks exist on main = PR was merged
119
+ console.log(`Issue #${issue.number}: tasks PR merged, marking as accepted`);
120
+ await issues.removeLabel(issue.number, LABELS.TASKS_PROPOSED);
121
+ await issues.addLabel(issue.number, LABELS.TASKS_ACCEPTED);
122
+ }
123
+ }
124
+ // Check accepted issues for completion
125
+ const acceptedIssues = await issues.listIssues({ labels: [LABELS.TASKS_ACCEPTED] });
126
+ for (const issue of acceptedIssues) {
127
+ if (!taskMgr.hasRemainingTasks(issue.number)) {
128
+ console.log(`Issue #${issue.number}: all tasks done, closing`);
129
+ await issues.addLabel(issue.number, LABELS.COMPLETED);
130
+ await issues.removeLabel(issue.number, LABELS.TASKS_ACCEPTED);
131
+ await issues.comment(issue.number, '✅ All tasks for this issue have been implemented and merged. Closing.');
132
+ await issues.closeIssue(issue.number);
133
+ }
134
+ }
135
+ console.log('Reconcile complete.');
136
+ });
137
+ return program;
138
+ }
139
+ export async function main(args = process.argv) {
140
+ const program = buildCli();
141
+ await program.parseAsync(args);
142
+ }
143
+ main().catch((err) => {
144
+ console.error(err);
145
+ process.exit(1);
146
+ });
147
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Git operations for whitesmith.
3
+ */
4
+ export declare class GitManager {
5
+ private workDir;
6
+ constructor(workDir: string);
7
+ private git;
8
+ /**
9
+ * Get the current branch name
10
+ */
11
+ getCurrentBranch(): Promise<string>;
12
+ /**
13
+ * Fetch latest from origin
14
+ */
15
+ fetch(): Promise<void>;
16
+ /**
17
+ * Checkout a branch (create if it doesn't exist)
18
+ */
19
+ checkout(branch: string, options?: {
20
+ create?: boolean;
21
+ startPoint?: string;
22
+ }): Promise<void>;
23
+ /**
24
+ * Checkout main and pull latest
25
+ */
26
+ checkoutMain(): Promise<void>;
27
+ /**
28
+ * Stage all changes and commit
29
+ */
30
+ commitAll(message: string, exclude?: string[]): Promise<boolean>;
31
+ /**
32
+ * Push branch to origin
33
+ */
34
+ push(branch: string): Promise<void>;
35
+ /**
36
+ * Force push branch to origin
37
+ */
38
+ forcePush(branch: string): Promise<void>;
39
+ /**
40
+ * Check if there are uncommitted changes
41
+ */
42
+ hasChanges(): Promise<boolean>;
43
+ /**
44
+ * Check if a local branch exists
45
+ */
46
+ localBranchExists(branch: string): Promise<boolean>;
47
+ /**
48
+ * Delete a local branch
49
+ */
50
+ deleteLocalBranch(branch: string): Promise<void>;
51
+ /**
52
+ * Get the default branch (usually main)
53
+ */
54
+ getDefaultBranch(): Promise<string>;
55
+ /**
56
+ * Verify we're on the expected branch
57
+ */
58
+ verifyBranch(expected: string): Promise<void>;
59
+ }
60
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,qBAAa,UAAU;IACtB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM;YAIb,GAAG;IAKjB;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIzC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAShG;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAKnC;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAwBtE;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAKpC;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASzD;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtD;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IASzC;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMnD"}
package/dist/git.js ADDED
@@ -0,0 +1,138 @@
1
+ import { exec } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execAsync = promisify(exec);
4
+ /**
5
+ * Git operations for whitesmith.
6
+ */
7
+ export class GitManager {
8
+ workDir;
9
+ constructor(workDir) {
10
+ this.workDir = workDir;
11
+ }
12
+ async git(args) {
13
+ const { stdout } = await execAsync(`git ${args}`, { cwd: this.workDir });
14
+ return stdout.trim();
15
+ }
16
+ /**
17
+ * Get the current branch name
18
+ */
19
+ async getCurrentBranch() {
20
+ return this.git('rev-parse --abbrev-ref HEAD');
21
+ }
22
+ /**
23
+ * Fetch latest from origin
24
+ */
25
+ async fetch() {
26
+ await this.git('fetch origin');
27
+ }
28
+ /**
29
+ * Checkout a branch (create if it doesn't exist)
30
+ */
31
+ async checkout(branch, options) {
32
+ if (options?.create) {
33
+ const startPoint = options.startPoint || 'origin/main';
34
+ await this.git(`checkout -b ${branch} ${startPoint}`);
35
+ }
36
+ else {
37
+ await this.git(`checkout ${branch}`);
38
+ }
39
+ }
40
+ /**
41
+ * Checkout main and pull latest
42
+ */
43
+ async checkoutMain() {
44
+ await this.git('checkout main');
45
+ await this.git('pull origin main');
46
+ }
47
+ /**
48
+ * Stage all changes and commit
49
+ */
50
+ async commitAll(message, exclude) {
51
+ // Check if there are changes
52
+ const status = await this.git('status --porcelain');
53
+ if (!status)
54
+ return false;
55
+ let addCmd = 'git add -A';
56
+ if (exclude && exclude.length > 0) {
57
+ // Add all then unstage excluded
58
+ await this.git('add -A');
59
+ for (const pattern of exclude) {
60
+ try {
61
+ await this.git(`reset HEAD -- ${pattern}`);
62
+ }
63
+ catch {
64
+ // File might not be staged
65
+ }
66
+ }
67
+ }
68
+ else {
69
+ await this.git('add -A');
70
+ }
71
+ await this.git(`commit -m "${message.replace(/"/g, '\\"')}"`);
72
+ return true;
73
+ }
74
+ /**
75
+ * Push branch to origin
76
+ */
77
+ async push(branch) {
78
+ await this.git(`push origin ${branch}`);
79
+ }
80
+ /**
81
+ * Force push branch to origin
82
+ */
83
+ async forcePush(branch) {
84
+ await this.git(`push --force-with-lease origin ${branch}`);
85
+ }
86
+ /**
87
+ * Check if there are uncommitted changes
88
+ */
89
+ async hasChanges() {
90
+ const status = await this.git('status --porcelain');
91
+ return status.length > 0;
92
+ }
93
+ /**
94
+ * Check if a local branch exists
95
+ */
96
+ async localBranchExists(branch) {
97
+ try {
98
+ await this.git(`rev-parse --verify ${branch}`);
99
+ return true;
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ }
105
+ /**
106
+ * Delete a local branch
107
+ */
108
+ async deleteLocalBranch(branch) {
109
+ try {
110
+ await this.git(`branch -D ${branch}`);
111
+ }
112
+ catch {
113
+ // Branch might not exist
114
+ }
115
+ }
116
+ /**
117
+ * Get the default branch (usually main)
118
+ */
119
+ async getDefaultBranch() {
120
+ try {
121
+ const ref = await this.git('symbolic-ref refs/remotes/origin/HEAD');
122
+ return ref.replace('refs/remotes/origin/', '');
123
+ }
124
+ catch {
125
+ return 'main';
126
+ }
127
+ }
128
+ /**
129
+ * Verify we're on the expected branch
130
+ */
131
+ async verifyBranch(expected) {
132
+ const current = await this.getCurrentBranch();
133
+ if (current !== expected) {
134
+ throw new Error(`Expected to be on branch '${expected}' but on '${current}'`);
135
+ }
136
+ }
137
+ }
138
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Interface for AI agent harnesses.
3
+ * Implementations wrap specific tools (pi, claude CLI, aider, etc.)
4
+ */
5
+ export interface AgentHarness {
6
+ /**
7
+ * Run the agent with a prompt and return its output.
8
+ * The agent is expected to execute in the given working directory.
9
+ */
10
+ run(options: {
11
+ prompt: string;
12
+ workDir: string;
13
+ logFile?: string;
14
+ }): Promise<{
15
+ output: string;
16
+ exitCode: number;
17
+ }>;
18
+ }
19
+ //# sourceMappingURL=agent-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-harness.d.ts","sourceRoot":"","sources":["../../src/harnesses/agent-harness.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B;;;OAGG;IACH,GAAG,CAAC,OAAO,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CAChD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agent-harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-harness.js","sourceRoot":"","sources":["../../src/harnesses/agent-harness.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export type { AgentHarness } from './agent-harness.js';
2
+ export { PiHarness } from './pi.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harnesses/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PiHarness } from './pi.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harnesses/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { AgentHarness } from './agent-harness.js';
2
+ /**
3
+ * Agent harness for @mariozechner/pi-coding-agent.
4
+ *
5
+ * Runs `pi` with a prompt passed via a temp file, captures output.
6
+ */
7
+ export declare class PiHarness implements AgentHarness {
8
+ private cmd;
9
+ /**
10
+ * @param cmd - Command to invoke pi (default: "pi")
11
+ */
12
+ constructor(cmd?: string);
13
+ run(options: {
14
+ prompt: string;
15
+ workDir: string;
16
+ logFile?: string;
17
+ }): Promise<{
18
+ output: string;
19
+ exitCode: number;
20
+ }>;
21
+ private exec;
22
+ }
23
+ //# sourceMappingURL=pi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../../src/harnesses/pi.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAErD;;;;GAIG;AACH,qBAAa,SAAU,YAAW,YAAY;IAC7C,OAAO,CAAC,GAAG,CAAS;IAEpB;;OAEG;gBACS,GAAG,GAAE,MAAa;IAIxB,GAAG,CAAC,OAAO,EAAE;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAC;IAsB/C,OAAO,CAAC,IAAI;CAmCZ"}
@@ -0,0 +1,63 @@
1
+ import { exec } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ /**
5
+ * Agent harness for @mariozechner/pi-coding-agent.
6
+ *
7
+ * Runs `pi` with a prompt passed via a temp file, captures output.
8
+ */
9
+ export class PiHarness {
10
+ cmd;
11
+ /**
12
+ * @param cmd - Command to invoke pi (default: "pi")
13
+ */
14
+ constructor(cmd = 'pi') {
15
+ this.cmd = cmd;
16
+ }
17
+ async run(options) {
18
+ // Write prompt to a temp file to avoid shell escaping issues
19
+ const promptFile = path.join(options.workDir, '.whitesmith-prompt.md');
20
+ fs.writeFileSync(promptFile, options.prompt, 'utf-8');
21
+ try {
22
+ const result = await this.exec(`${this.cmd} --prompt-file "${promptFile}" --yes`, options.workDir, options.logFile);
23
+ return result;
24
+ }
25
+ finally {
26
+ // Clean up prompt file
27
+ try {
28
+ fs.unlinkSync(promptFile);
29
+ }
30
+ catch {
31
+ // Ignore
32
+ }
33
+ }
34
+ }
35
+ exec(cmd, workDir, logFile) {
36
+ return new Promise((resolve) => {
37
+ const child = exec(cmd, {
38
+ cwd: workDir,
39
+ maxBuffer: 50 * 1024 * 1024,
40
+ timeout: 30 * 60 * 1000, // 30 minute timeout
41
+ });
42
+ let output = '';
43
+ const logStream = logFile
44
+ ? fs.createWriteStream(path.resolve(workDir, logFile), { flags: 'a' })
45
+ : null;
46
+ child.stdout?.on('data', (data) => {
47
+ output += data;
48
+ process.stdout.write(data);
49
+ logStream?.write(data);
50
+ });
51
+ child.stderr?.on('data', (data) => {
52
+ output += data;
53
+ process.stderr.write(data);
54
+ logStream?.write(data);
55
+ });
56
+ child.on('close', (code) => {
57
+ logStream?.end();
58
+ resolve({ output, exitCode: code ?? 1 });
59
+ });
60
+ });
61
+ }
62
+ }
63
+ //# sourceMappingURL=pi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.js","sourceRoot":"","sources":["../../src/harnesses/pi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,oBAAoB,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC;;;;GAIG;AACH,MAAM,OAAO,SAAS;IACb,GAAG,CAAS;IAEpB;;OAEG;IACH,YAAY,MAAc,IAAI;QAC7B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,OAIT;QACA,6DAA6D;QAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;QACvE,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEtD,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAC7B,GAAG,IAAI,CAAC,GAAG,mBAAmB,UAAU,SAAS,EACjD,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,OAAO,CACf,CAAC;YACF,OAAO,MAAM,CAAC;QACf,CAAC;gBAAS,CAAC;YACV,uBAAuB;YACvB,IAAI,CAAC;gBACJ,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACR,SAAS;YACV,CAAC;QACF,CAAC;IACF,CAAC;IAEO,IAAI,CACX,GAAW,EACX,OAAe,EACf,OAAgB;QAEhB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;gBACvB,GAAG,EAAE,OAAO;gBACZ,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;gBAC3B,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,oBAAoB;aAC7C,CAAC,CAAC;YAEH,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,OAAO;gBACxB,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAC,KAAK,EAAE,GAAG,EAAC,CAAC;gBACpE,CAAC,CAAC,IAAI,CAAC;YAER,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBACzC,MAAM,IAAI,IAAI,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC3B,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBACzC,MAAM,IAAI,IAAI,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC3B,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC1B,SAAS,EAAE,GAAG,EAAE,CAAC;gBACjB,OAAO,CAAC,EAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC,EAAC,CAAC,CAAC;YACxC,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC;CACD"}
@@ -0,0 +1,11 @@
1
+ export { Orchestrator } from './orchestrator.js';
2
+ export { TaskManager } from './task-manager.js';
3
+ export { GitManager } from './git.js';
4
+ export { buildInvestigatePrompt, buildImplementPrompt } from './prompts.js';
5
+ export type { IssueProvider } from './providers/issue-provider.js';
6
+ export { GitHubProvider } from './providers/github.js';
7
+ export type { AgentHarness } from './harnesses/agent-harness.js';
8
+ export { PiHarness } from './harnesses/pi.js';
9
+ export type { Issue, Task, TaskFrontmatter, DevPulseConfig, Action } from './types.js';
10
+ export { LABELS } from './types.js';
11
+ //# sourceMappingURL=index.d.ts.map