xforce 0.1.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.
@@ -0,0 +1,434 @@
1
+ /** Parsed from a structured GitHub Issue body */
2
+ interface TaskSpec {
3
+ title: string;
4
+ context: string;
5
+ acceptanceCriteria: string[];
6
+ affectedFiles: string[];
7
+ edgeCases: string[];
8
+ priority: "critical" | "high" | "medium" | "low";
9
+ type: "feature" | "bugfix" | "refactor" | "test" | "docs";
10
+ size: "xs" | "s" | "m" | "l" | "xl";
11
+ issueNumber: number;
12
+ issueUrl: string;
13
+ repoOwner: string;
14
+ repoName: string;
15
+ }
16
+ /** Configuration for a single target repository */
17
+ interface RepoConfig {
18
+ owner: string;
19
+ name: string;
20
+ defaultBranch: string;
21
+ testCommand: string;
22
+ lintCommand?: string;
23
+ buildCommand?: string;
24
+ runCommand?: string;
25
+ claudeMdPath?: string;
26
+ maxTurns?: number;
27
+ maxReviewCycles?: number;
28
+ maxTestRetries?: number;
29
+ budgetPerTaskUsd?: number;
30
+ autoMerge: boolean;
31
+ autoMergeRules?: AutoMergeRules;
32
+ allowedTools?: string[];
33
+ localPath?: string;
34
+ }
35
+ /** Label configuration */
36
+ interface LabelsConfig {
37
+ ready: string;
38
+ inProgress: string;
39
+ done: string;
40
+ failed: string;
41
+ }
42
+ /** Default settings applied to all repos unless overridden */
43
+ interface DefaultsConfig {
44
+ model: string;
45
+ reviewerModel: string;
46
+ plannerModel: string;
47
+ maxTurns: number;
48
+ maxReviewCycles: number;
49
+ maxTestRetries: number;
50
+ timeoutMinutes: number;
51
+ budgetPerTaskUsd: number;
52
+ branchPrefix: string;
53
+ labels: LabelsConfig;
54
+ allowedTools: string[];
55
+ enablePlanning: boolean;
56
+ enableSecurityScan: boolean;
57
+ }
58
+ /** Slack notification config */
59
+ interface SlackConfig {
60
+ webhookUrl: string;
61
+ channels?: {
62
+ success?: string;
63
+ failure?: string;
64
+ };
65
+ }
66
+ /** GitHub notification config */
67
+ interface GitHubNotifyConfig {
68
+ mentionOnFailure?: string[];
69
+ mentionOnReview?: string[];
70
+ }
71
+ /** Notifications config */
72
+ interface NotificationsConfig {
73
+ slack?: SlackConfig;
74
+ github?: GitHubNotifyConfig;
75
+ }
76
+ /** Top-level xforce configuration */
77
+ interface XForceConfig {
78
+ version: string;
79
+ defaults: DefaultsConfig;
80
+ repos: RepoConfig[];
81
+ notifications?: NotificationsConfig;
82
+ }
83
+ /** Resolved config for a specific repo (defaults merged with repo overrides) */
84
+ interface ResolvedRepoConfig {
85
+ owner: string;
86
+ name: string;
87
+ defaultBranch: string;
88
+ testCommand: string;
89
+ lintCommand?: string;
90
+ buildCommand?: string;
91
+ runCommand?: string;
92
+ claudeMdPath?: string;
93
+ model: string;
94
+ reviewerModel: string;
95
+ plannerModel: string;
96
+ maxTurns: number;
97
+ maxReviewCycles: number;
98
+ maxTestRetries: number;
99
+ timeoutMinutes: number;
100
+ budgetPerTaskUsd: number;
101
+ branchPrefix: string;
102
+ labels: LabelsConfig;
103
+ autoMerge: boolean;
104
+ autoMergeRules: AutoMergeRules;
105
+ allowedTools: string[];
106
+ enablePlanning: boolean;
107
+ enableSecurityScan: boolean;
108
+ localPath?: string;
109
+ }
110
+ /** Rules for auto-merging approved PRs */
111
+ interface AutoMergeRules {
112
+ types: Array<TaskSpec["type"]>;
113
+ maxSize: TaskSpec["size"];
114
+ mergeStrategy: "squash" | "merge" | "rebase";
115
+ requireCleanSecurityScan: boolean;
116
+ }
117
+ /** Pipeline execution state */
118
+ type PipelineStatus = "parsing_issue" | "creating_branch" | "planning" | "coding" | "running_tests" | "reviewing" | "addressing_review" | "merging" | "awaiting_human" | "completed" | "failed";
119
+ /** A single log entry in the pipeline */
120
+ interface PipelineLogEntry {
121
+ timestamp: Date;
122
+ status: PipelineStatus;
123
+ message: string;
124
+ costUsd?: number;
125
+ }
126
+ /** Full pipeline state at any point */
127
+ interface PipelineState {
128
+ id: string;
129
+ taskSpec: TaskSpec;
130
+ status: PipelineStatus;
131
+ branchName: string;
132
+ prNumber?: number;
133
+ prUrl?: string;
134
+ reviewCycle: number;
135
+ testRetry: number;
136
+ totalCostUsd: number;
137
+ logs: PipelineLogEntry[];
138
+ startedAt: Date;
139
+ completedAt?: Date;
140
+ error?: string;
141
+ plan?: ImplementationPlan;
142
+ }
143
+ /** Result from the coding agent */
144
+ interface CodingResult {
145
+ sessionId: string;
146
+ costUsd: number;
147
+ result: string;
148
+ numTurns: number;
149
+ filesChanged?: string[];
150
+ }
151
+ /** A single issue found during review */
152
+ interface ReviewIssue {
153
+ severity: "critical" | "major" | "minor" | "suggestion";
154
+ file: string;
155
+ line?: number;
156
+ description: string;
157
+ suggestedFix?: string;
158
+ }
159
+ /** Result from the reviewer agent */
160
+ interface ReviewResult {
161
+ approved: boolean;
162
+ summary: string;
163
+ issues: ReviewIssue[];
164
+ securityConcerns: string[];
165
+ specAdherence: {
166
+ met: string[];
167
+ unmet: string[];
168
+ };
169
+ }
170
+ /** Result from running the target repo's test suite */
171
+ interface TestResult {
172
+ passed: boolean;
173
+ output: string;
174
+ durationMs: number;
175
+ }
176
+ /** A single step in an implementation plan */
177
+ interface ImplementationStep {
178
+ order: number;
179
+ description: string;
180
+ files: string[];
181
+ rationale: string;
182
+ }
183
+ /** Structured plan produced by the planning agent */
184
+ interface ImplementationPlan {
185
+ approach: string;
186
+ filesToModify: string[];
187
+ filesToCreate: string[];
188
+ estimatedComplexity: "low" | "medium" | "high";
189
+ risks: string[];
190
+ implementationSteps: ImplementationStep[];
191
+ estimatedTurns: number;
192
+ }
193
+ /** Result from the planning agent */
194
+ interface PlanningResult {
195
+ plan: ImplementationPlan;
196
+ costUsd: number;
197
+ numTurns: number;
198
+ }
199
+ /** A single security finding from the scanner */
200
+ interface SecurityFinding {
201
+ severity: "critical" | "high" | "medium" | "low" | "info";
202
+ category: string;
203
+ file: string;
204
+ line?: number;
205
+ description: string;
206
+ recommendation: string;
207
+ }
208
+ /** Full security scan report */
209
+ interface SecurityReport {
210
+ riskLevel: "critical" | "high" | "medium" | "low" | "none";
211
+ findings: SecurityFinding[];
212
+ recommendations: string[];
213
+ summary: string;
214
+ }
215
+ /** Result from the security scanner agent */
216
+ interface SecurityScanResult {
217
+ report: SecurityReport;
218
+ costUsd: number;
219
+ }
220
+ /** Result from attempting to merge a PR */
221
+ interface MergeResult {
222
+ merged: boolean;
223
+ sha?: string;
224
+ error?: string;
225
+ }
226
+ /** A record of a completed pipeline run, persisted to disk */
227
+ interface PipelineRunRecord {
228
+ id: string;
229
+ repo: string;
230
+ issueNumber: number;
231
+ issueUrl: string;
232
+ prNumber?: number;
233
+ prUrl?: string;
234
+ status: "completed" | "failed";
235
+ totalCostUsd: number;
236
+ durationMs: number;
237
+ reviewCycles: number;
238
+ model: string;
239
+ startedAt: string;
240
+ completedAt: string;
241
+ taskTitle: string;
242
+ taskType: string;
243
+ taskSize: string;
244
+ error?: string;
245
+ }
246
+ /** Summary of cost tracking data for display */
247
+ interface CostSummary {
248
+ totalCostUsd: number;
249
+ totalRuns: number;
250
+ successfulRuns: number;
251
+ failedRuns: number;
252
+ avgCostPerRun: number;
253
+ avgDurationMs: number;
254
+ costByRepo: Record<string, number>;
255
+ }
256
+
257
+ interface RunPipelineParams {
258
+ issueUrl?: string;
259
+ repoOwner?: string;
260
+ repoName?: string;
261
+ issueNumber?: number;
262
+ config: XForceConfig;
263
+ localDir?: string;
264
+ }
265
+ declare function runPipeline(params: RunPipelineParams): Promise<PipelineState>;
266
+
267
+ /** Load and validate the xforce config file */
268
+ declare function loadConfig(configPath?: string): XForceConfig;
269
+ /** Resolve config for a specific repo by merging defaults with repo overrides */
270
+ declare function resolveRepoConfig(config: XForceConfig, owner: string, name: string): ResolvedRepoConfig;
271
+
272
+ /** Parse a structured GitHub issue body into a TaskSpec */
273
+ declare function parseIssueBody(params: {
274
+ title: string;
275
+ body: string;
276
+ labels: string[];
277
+ issueNumber: number;
278
+ issueUrl: string;
279
+ repoOwner: string;
280
+ repoName: string;
281
+ }): TaskSpec;
282
+
283
+ /** Parse an issue URL into owner, repo, and issue number */
284
+ declare function parseIssueUrl(url: string): {
285
+ owner: string;
286
+ repo: string;
287
+ issueNumber: number;
288
+ };
289
+ /** Parse a PR URL into owner, repo, and PR number */
290
+ declare function parsePRUrl(url: string): {
291
+ owner: string;
292
+ repo: string;
293
+ prNumber: number;
294
+ };
295
+
296
+ declare function runCodingAgent(params: {
297
+ taskSpec: TaskSpec;
298
+ repoConfig: ResolvedRepoConfig;
299
+ workingDir: string;
300
+ previousReview?: ReviewResult;
301
+ testFailures?: string;
302
+ commandFailures?: {
303
+ kind: string;
304
+ output: string;
305
+ };
306
+ sessionId?: string;
307
+ plan?: ImplementationPlan;
308
+ onProgress?: (message: string) => void;
309
+ }): Promise<CodingResult>;
310
+
311
+ declare function runReviewerAgent(params: {
312
+ taskSpec: TaskSpec;
313
+ diff: string;
314
+ repoConfig: ResolvedRepoConfig;
315
+ reviewCycle: number;
316
+ }): Promise<ReviewResult>;
317
+
318
+ declare function runPlanningAgent(params: {
319
+ taskSpec: TaskSpec;
320
+ repoConfig: ResolvedRepoConfig;
321
+ workingDir: string;
322
+ onProgress?: (message: string) => void;
323
+ }): Promise<PlanningResult>;
324
+
325
+ declare function runSecurityScanner(params: {
326
+ taskSpec: TaskSpec;
327
+ diff: string;
328
+ repoConfig: ResolvedRepoConfig;
329
+ }): Promise<SecurityScanResult>;
330
+
331
+ declare function isAutoMergeEligible(params: {
332
+ taskSpec: TaskSpec;
333
+ repoConfig: ResolvedRepoConfig;
334
+ securityReport?: SecurityReport;
335
+ }): {
336
+ eligible: boolean;
337
+ reasons: string[];
338
+ };
339
+
340
+ /** Convert a completed PipelineState into a PipelineRunRecord */
341
+ declare function buildRecordFromState(state: PipelineState, repoConfig: ResolvedRepoConfig): PipelineRunRecord;
342
+ /** Append a pipeline run record to the JSONL history file */
343
+ declare function appendRecord(record: PipelineRunRecord, basePath?: string): Promise<void>;
344
+ interface CostFilter {
345
+ repo?: string;
346
+ since?: Date;
347
+ until?: Date;
348
+ }
349
+ /** Read pipeline run records from the JSONL history file */
350
+ declare function readRecords(filter?: CostFilter, basePath?: string): Promise<PipelineRunRecord[]>;
351
+ /** Compute summary statistics from a set of pipeline run records */
352
+ declare function summarize(records: PipelineRunRecord[]): CostSummary;
353
+
354
+ type JobStatus = "pending" | "running" | "completed" | "failed";
355
+ interface Job {
356
+ id: string;
357
+ owner: string;
358
+ repo: string;
359
+ issueNumber: number;
360
+ issueUrl: string;
361
+ status: JobStatus;
362
+ result?: PipelineState;
363
+ error?: string;
364
+ enqueuedAt: Date;
365
+ startedAt?: Date;
366
+ completedAt?: Date;
367
+ }
368
+ interface QueueStatus {
369
+ active: Job | null;
370
+ pending: Job[];
371
+ completed: Job[];
372
+ totalProcessed: number;
373
+ }
374
+ interface QueueOptions {
375
+ maxSize: number;
376
+ historySize: number;
377
+ }
378
+ declare class JobQueue {
379
+ private pending;
380
+ private active;
381
+ private completed;
382
+ private totalProcessed;
383
+ private processing;
384
+ private readonly options;
385
+ private readonly processor;
386
+ constructor(processor: (job: Job) => Promise<PipelineState>, options?: Partial<QueueOptions>);
387
+ enqueue(params: {
388
+ owner: string;
389
+ repo: string;
390
+ issueNumber: number;
391
+ issueUrl: string;
392
+ }): Job;
393
+ getStatus(): QueueStatus;
394
+ getJob(id: string): Job | undefined;
395
+ get size(): number;
396
+ get isFull(): boolean;
397
+ private isDuplicateIn;
398
+ private processNext;
399
+ }
400
+
401
+ interface WebhookServerOptions {
402
+ port: number;
403
+ host: string;
404
+ secret: string;
405
+ maxQueueSize?: number;
406
+ historySize?: number;
407
+ }
408
+ interface WebhookServer {
409
+ start(): Promise<void>;
410
+ stop(): Promise<void>;
411
+ getQueueStatus(): QueueStatus;
412
+ address(): {
413
+ host: string;
414
+ port: number;
415
+ } | null;
416
+ }
417
+ declare function createWebhookServer(config: XForceConfig, options: WebhookServerOptions): WebhookServer;
418
+
419
+ type CommandKind = "lint" | "build" | "test" | "run";
420
+ /** Run any shell command and capture output */
421
+ declare function runCommand(params: {
422
+ workingDir: string;
423
+ command: string;
424
+ kind: CommandKind;
425
+ timeoutMs?: number;
426
+ }): Promise<TestResult>;
427
+ /** Run the target repo's test suite and capture output */
428
+ declare function runTests(params: {
429
+ workingDir: string;
430
+ testCommand: string;
431
+ timeoutMs?: number;
432
+ }): Promise<TestResult>;
433
+
434
+ export { type AutoMergeRules, type CodingResult, type CommandKind, type CostSummary, type DefaultsConfig, type ImplementationPlan, type ImplementationStep, type Job, JobQueue, type JobStatus, type LabelsConfig, type MergeResult, type PipelineRunRecord, type PipelineState, type PipelineStatus, type PlanningResult, type QueueStatus, type RepoConfig, type ResolvedRepoConfig, type ReviewIssue, type ReviewResult, type RunPipelineParams, type SecurityFinding, type SecurityReport, type SecurityScanResult, type TaskSpec, type TestResult, type WebhookServer, type WebhookServerOptions, type XForceConfig, appendRecord, buildRecordFromState, createWebhookServer, isAutoMergeEligible, loadConfig, parseIssueBody, parseIssueUrl, parsePRUrl, readRecords, resolveRepoConfig, runCodingAgent, runCommand, runPipeline, runPlanningAgent, runReviewerAgent, runSecurityScanner, runTests, summarize };