phoebe-agent 0.0.0 → 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.
Files changed (75) hide show
  1. package/README.md +77 -8
  2. package/bootstrap/bin.mjs +42 -0
  3. package/bootstrap/boot.ts +383 -0
  4. package/bootstrap/cli.ts +29 -0
  5. package/bootstrap/crash-loop.ts +391 -0
  6. package/bootstrap/define-config.ts +20 -0
  7. package/bootstrap/engine-source.ts +83 -0
  8. package/bootstrap/github-engine.ts +169 -0
  9. package/bootstrap/index.mjs +9 -0
  10. package/bootstrap/index.ts +24 -0
  11. package/bootstrap/materialize.mjs +53 -0
  12. package/bootstrap/reconcile.ts +314 -0
  13. package/bootstrap/spawn-engine.mjs +78 -0
  14. package/package.json +26 -24
  15. package/prompts/checks-prompt.md +21 -6
  16. package/prompts/conflict-prompt.md +12 -1
  17. package/prompts/research-prompt.md +61 -0
  18. package/src/agent-env.ts +32 -0
  19. package/src/branded.ts +19 -0
  20. package/src/cli.ts +187 -0
  21. package/src/config-schema.ts +278 -0
  22. package/src/drain.ts +74 -0
  23. package/src/execution-gate.ts +27 -0
  24. package/src/git-model.ts +113 -0
  25. package/src/init.ts +277 -0
  26. package/src/load-config.ts +168 -0
  27. package/src/main.ts +1636 -0
  28. package/src/orchestrator.ts +953 -0
  29. package/src/prompt.ts +98 -0
  30. package/src/providers/providers.ts +222 -0
  31. package/src/providers/run-agent.ts +90 -0
  32. package/src/providers/types.ts +26 -0
  33. package/src/resolved-config.ts +55 -0
  34. package/templates/.env.example +11 -5
  35. package/templates/container/Dockerfile +41 -19
  36. package/templates/container/compose.local.yml +37 -0
  37. package/templates/container/compose.yml +34 -13
  38. package/templates/phoebe.config.ts +30 -6
  39. package/dist/phoebe.config.d.ts +0 -2
  40. package/dist/phoebe.config.js +0 -43
  41. package/dist/src/agent-env.d.ts +0 -6
  42. package/dist/src/agent-env.js +0 -24
  43. package/dist/src/cli.d.ts +0 -25
  44. package/dist/src/cli.js +0 -161
  45. package/dist/src/config-schema.d.ts +0 -163
  46. package/dist/src/config-schema.js +0 -140
  47. package/dist/src/execution-gate.d.ts +0 -9
  48. package/dist/src/execution-gate.js +0 -17
  49. package/dist/src/git-model.d.ts +0 -30
  50. package/dist/src/git-model.js +0 -71
  51. package/dist/src/index.d.ts +0 -2
  52. package/dist/src/index.js +0 -12
  53. package/dist/src/init.d.ts +0 -82
  54. package/dist/src/init.js +0 -207
  55. package/dist/src/load-config.d.ts +0 -88
  56. package/dist/src/load-config.js +0 -153
  57. package/dist/src/main.d.ts +0 -7
  58. package/dist/src/main.js +0 -1180
  59. package/dist/src/orchestrator.d.ts +0 -275
  60. package/dist/src/orchestrator.js +0 -579
  61. package/dist/src/prompt.d.ts +0 -13
  62. package/dist/src/prompt.js +0 -55
  63. package/dist/src/providers/providers.d.ts +0 -3
  64. package/dist/src/providers/providers.js +0 -210
  65. package/dist/src/providers/run-agent.d.ts +0 -34
  66. package/dist/src/providers/run-agent.js +0 -57
  67. package/dist/src/providers/types.d.ts +0 -27
  68. package/dist/src/providers/types.js +0 -6
  69. package/dist/src/resolved-config.d.ts +0 -8
  70. package/dist/src/resolved-config.js +0 -49
  71. package/dist/src/supervisor-decision.d.ts +0 -70
  72. package/dist/src/supervisor-decision.js +0 -94
  73. package/templates/container/compose.daemon.yml +0 -16
  74. package/templates/container/supervisor.sh +0 -50
  75. /package/prompts/{prompt.md → issues-prompt.md} +0 -0
@@ -1,275 +0,0 @@
1
- export type Issue = {
2
- number: number;
3
- title: string;
4
- body: string;
5
- labels: string[];
6
- createdAt: string;
7
- };
8
- export type BlockerPrState = {
9
- hasOpenPr: boolean;
10
- openPrNumber?: number;
11
- hasMergedPr: boolean;
12
- mergedPrNumber?: number;
13
- };
14
- export type BaseResolution = {
15
- worktreeBase: string;
16
- stacked: boolean;
17
- blockerIssueNumber?: number;
18
- blockerPrNumber?: number;
19
- };
20
- declare const PRIORITY_ORDER: readonly ["bug", "tracer", "polish", "refactor"];
21
- export type Priority = (typeof PRIORITY_ORDER)[number];
22
- /**
23
- * Parse blocker references from issue body text (and optional comments).
24
- * The pattern is configurable via `config.blockedByPattern`; capture group 1
25
- * must yield the blocker issue number.
26
- */
27
- export declare function parseBlockedBy(...texts: string[]): number[];
28
- export declare function classifyPriority(issue: Issue): Priority;
29
- export declare function compareIssues(a: Issue, b: Issue): number;
30
- export declare function issueBranch(issueNumber: number): string;
31
- /**
32
- * Resolve the worktree base for an issue.
33
- * Returns `null` when the issue should be skipped this cycle (blocked with no
34
- * open/merged blocker PR).
35
- */
36
- export declare function resolveWorktreeBase(issue: Issue, blockerStates: ReadonlyMap<number, BlockerPrState>, phoebeBase?: string): BaseResolution | null;
37
- /** Pick the highest-priority workable issue, or `null` when none qualify. */
38
- export declare function selectIssue(issues: readonly Issue[], blockerStates: ReadonlyMap<number, BlockerPrState>, phoebeBase?: string): {
39
- issue: Issue;
40
- resolution: BaseResolution;
41
- } | null;
42
- export declare function stackedPrComment(blockerIssueNumber: number, blockerPrNumber: number): string;
43
- export type ConflictingPrCandidate = {
44
- prNumber: number;
45
- headRefName: string;
46
- issueNumber?: number;
47
- headSha?: string;
48
- failureWatermark?: ConflictFailWatermark | null;
49
- };
50
- export type ConflictFailWatermark = {
51
- prHead: string;
52
- mainHead: string;
53
- };
54
- export declare function buildConflictFailWatermarkMarker(watermark: ConflictFailWatermark): string;
55
- export declare function parseConflictFailWatermark(text: string): ConflictFailWatermark | null;
56
- /** Latest marker wins when several failure comments exist on one PR. */
57
- export declare function parseConflictFailWatermarkFromComments(comments: readonly string[]): ConflictFailWatermark | null;
58
- export declare function shouldSkipWatermarkConflictFix(opts: {
59
- watermark: ConflictFailWatermark | null;
60
- currentPrHead: string;
61
- currentMainHead: string;
62
- }): boolean;
63
- export declare function isPhoebeHeadBranch(branch: string): boolean;
64
- export type PrScopeConfig = {
65
- branchPrefix: string;
66
- prScope: "phoebe" | "all";
67
- draftPrs: "skip-non-phoebe" | "skip-all" | "include";
68
- prOptOutLabel: string;
69
- };
70
- export type PrScanFields = {
71
- headRefName: string;
72
- isDraft: boolean;
73
- isCrossRepository: boolean;
74
- labels: readonly string[];
75
- };
76
- /** Whether an open PR is eligible for conflicts/checks/reviews scanning. */
77
- export declare function isPrInScope(pr: PrScanFields, scopeConfig?: PrScopeConfig): boolean;
78
- export declare function parseIssueNumberFromBranch(branch: string): number | null;
79
- /** GitHub may return UNKNOWN while mergeability is still computing. */
80
- export declare function isPrMergeConflicting(mergeable: string, mergeStateStatus?: string): boolean;
81
- /**
82
- * Skip idle conflict-fix when the PR's issue is still stacked on a blocker with
83
- * an open PR — its divergence from `main` is expected, not a real conflict.
84
- */
85
- export declare function shouldSkipStackedConflictFix(issueBody: string, blockerStates: ReadonlyMap<number, BlockerPrState>): boolean;
86
- /** Merged blocker PR numbers for lazy catch-up (bottom-up stack order). */
87
- export declare function getMergedBlockerPrNumbers(issueBody: string, blockerStates: ReadonlyMap<number, BlockerPrState>): number[];
88
- export declare function stackedCatchUpRetractionComment(blockerPrNumbers: readonly number[]): string;
89
- export declare function selectConflictFixCandidates(prs: readonly ConflictingPrCandidate[], issueBodies: ReadonlyMap<number, string>, blockerStates: ReadonlyMap<number, BlockerPrState>, opts?: {
90
- currentMainHead: string;
91
- }): ConflictingPrCandidate[];
92
- export type StatusCheckItem = {
93
- __typename?: string;
94
- name?: string;
95
- context?: string;
96
- status?: string;
97
- conclusion?: string | null;
98
- state?: string;
99
- };
100
- export type FailingCheck = {
101
- name: string;
102
- conclusion: string;
103
- };
104
- export declare function checkItemName(item: StatusCheckItem): string;
105
- export declare function isCheckItemFailing(item: StatusCheckItem): boolean;
106
- export declare function isCheckItemPending(item: StatusCheckItem): boolean;
107
- /** Combined rollup: FAILURE when at least one check failed and none are pending. */
108
- export declare function statusCheckRollupState(checks: readonly StatusCheckItem[]): "FAILURE" | "PENDING" | "SUCCESS" | "NONE";
109
- export type WorkflowRunItem = {
110
- workflowName?: string;
111
- name?: string;
112
- status?: string;
113
- conclusion?: string | null;
114
- };
115
- /**
116
- * Map `gh run list` rows onto StatusCheckItem. The REST Actions API is the
117
- * check-state source usable by fine-grained PATs — GraphQL statusCheckRollup
118
- * is GitHub-App/OAuth only. REST enums are lowercase; rows arrive newest
119
- * first, and only the newest run per workflow counts.
120
- */
121
- export declare function workflowRunsToCheckItems(runs: readonly WorkflowRunItem[]): StatusCheckItem[];
122
- export declare function listFailingChecks(checks: readonly StatusCheckItem[]): FailingCheck[];
123
- export type ChecksCandidate = {
124
- prNumber: number;
125
- headRefName: string;
126
- issueNumber?: number;
127
- headSha?: string;
128
- mergeable: string;
129
- mergeStateStatus?: string;
130
- failingChecks: FailingCheck[];
131
- failureWatermark?: ChecksFailWatermark | null;
132
- };
133
- export type ChecksFailWatermark = {
134
- prHead: string;
135
- };
136
- export declare function buildChecksFailWatermarkMarker(watermark: ChecksFailWatermark): string;
137
- export declare function parseChecksFailWatermark(text: string): ChecksFailWatermark | null;
138
- export declare function parseChecksFailWatermarkFromComments(comments: readonly string[]): ChecksFailWatermark | null;
139
- export declare function shouldSkipWatermarkChecksFix(opts: {
140
- watermark: ChecksFailWatermark | null;
141
- currentPrHead: string;
142
- }): boolean;
143
- /** Reuse stacked-blocker skip logic — stacked PR red CI is handled at blocker merge. */
144
- export declare const shouldSkipStackedChecksFix: typeof shouldSkipStackedConflictFix;
145
- export declare function selectChecksCandidates(prs: readonly ChecksCandidate[], issueBodies: ReadonlyMap<number, string>, blockerStates: ReadonlyMap<number, BlockerPrState>): ChecksCandidate[];
146
- /** Pick the single checks unit — oldest PR number among eligible failing-CI candidates. */
147
- export declare function selectChecksUnit(prs: readonly ChecksCandidate[], issueBodies: ReadonlyMap<number, string>, blockerStates: ReadonlyMap<number, BlockerPrState>): ChecksCandidate | null;
148
- export type ReviewThreadComment = {
149
- createdAt: string;
150
- authorLogin: string;
151
- };
152
- export type ReviewThread = {
153
- isResolved: boolean;
154
- isOutdated: boolean;
155
- comments: readonly ReviewThreadComment[];
156
- };
157
- export type ReviewsCandidate = {
158
- prNumber: number;
159
- headRefName: string;
160
- issueNumber?: number;
161
- authorLogin?: string;
162
- mergeable: string;
163
- mergeStateStatus?: string;
164
- threads: readonly ReviewThread[];
165
- handledWatermark?: ReviewsHandledWatermark | null;
166
- };
167
- export type ReviewsHandledWatermark = {
168
- latest: string;
169
- };
170
- export declare function buildReviewsHandledMarker(watermark: ReviewsHandledWatermark): string;
171
- export declare function parseReviewsHandledWatermark(text: string): ReviewsHandledWatermark | null;
172
- export declare function parseReviewsHandledWatermarkFromComments(comments: readonly string[]): ReviewsHandledWatermark | null;
173
- export declare function isReviewSummaryComment(body: string): boolean;
174
- export declare function isActivityNewerThanWatermark(createdAt: string, watermark: ReviewsHandledWatermark | null): boolean;
175
- export declare function newestReviewThreadCommentCreatedAt(threads: readonly ReviewThread[]): string | null;
176
- export declare function hasNewNonPhoebeReviewActivity(opts: {
177
- threads: readonly ReviewThread[];
178
- phoebeLogin: string;
179
- authorLogin?: string;
180
- watermark: ReviewsHandledWatermark | null;
181
- }): boolean;
182
- /** Reuse stacked-blocker skip logic — stacked PR review comments are often about blocker code. */
183
- export declare const shouldSkipStackedReviewsFix: typeof shouldSkipStackedConflictFix;
184
- export declare function selectReviewsCandidates(prs: readonly ReviewsCandidate[], issueBodies: ReadonlyMap<number, string>, blockerStates: ReadonlyMap<number, BlockerPrState>, phoebeLogin: string): ReviewsCandidate[];
185
- /** Pick the single reviews unit — oldest PR number among eligible review-feedback candidates. */
186
- export declare function selectReviewsUnit(prs: readonly ReviewsCandidate[], issueBodies: ReadonlyMap<number, string>, blockerStates: ReadonlyMap<number, BlockerPrState>, phoebeLogin: string): ReviewsCandidate | null;
187
- export declare function buildReviewsHandledComment(opts: {
188
- latestActivityAt: string | null;
189
- failed: boolean;
190
- }): string;
191
- export declare const WORK_KIND_NAMES: readonly ["conflicts", "checks", "reviews", "issues"];
192
- export type WorkKindName = (typeof WORK_KIND_NAMES)[number];
193
- /** Whether a work-kind may run under `--run-once`. Janitor kinds are persistent-mode only. */
194
- export declare const WORK_KIND_ONE_SHOT_ELIGIBLE: Record<WorkKindName, boolean>;
195
- export declare const RUN_ONCE_NOTHING_MESSAGE = "[phoebe] Nothing to do under --run-once (janitor kinds are persistent-mode only).";
196
- export declare function oneShotWorkKinds(workOrder: readonly WorkKindName[]): readonly WorkKindName[];
197
- /** Fail fast when `WORK_ORDER` is empty or names an unknown kind. */
198
- export declare function validateWorkOrder(order: readonly string[]): readonly WorkKindName[];
199
- /** Pick the single conflict unit — oldest PR number among unblocked candidates. */
200
- export declare function selectConflictUnit(prs: readonly ConflictingPrCandidate[], issueBodies: ReadonlyMap<number, string>, blockerStates: ReadonlyMap<number, BlockerPrState>, opts?: {
201
- currentMainHead: string;
202
- }): ConflictingPrCandidate | null;
203
- /** Oldest conflicting PR by number that is eligible for an idle conflict fix. */
204
- export declare function selectConflictFixUnit(prs: readonly ConflictingPrCandidate[], issueBodies: ReadonlyMap<number, string>, blockerStates: ReadonlyMap<number, BlockerPrState>, opts?: {
205
- currentMainHead: string;
206
- }): ConflictingPrCandidate | null;
207
- export type IssueWorkUnit = {
208
- issue: Issue;
209
- resolution: BaseResolution;
210
- };
211
- export type WorkUnit = {
212
- kind: "conflicts";
213
- unit: ConflictingPrCandidate;
214
- } | {
215
- kind: "checks";
216
- unit: ChecksCandidate;
217
- } | {
218
- kind: "reviews";
219
- unit: ReviewsCandidate;
220
- } | {
221
- kind: "issues";
222
- unit: IssueWorkUnit;
223
- };
224
- export type WorkSelectionData = {
225
- issues: readonly Issue[];
226
- blockerStates: ReadonlyMap<number, BlockerPrState>;
227
- conflictingPrs: readonly ConflictingPrCandidate[];
228
- failingCheckPrs: readonly ChecksCandidate[];
229
- reviewActivityPrs: readonly ReviewsCandidate[];
230
- issueBodies: ReadonlyMap<number, string>;
231
- phoebeBase?: string;
232
- phoebeLogin?: string;
233
- currentMainHead?: string;
234
- };
235
- export type WorkSelectionOptions = {
236
- /** When true, skip kinds with `WORK_KIND_ONE_SHOT_ELIGIBLE[kind] === false`. */
237
- oneShotOnly?: boolean;
238
- };
239
- /** Walk `workOrder` and return the first kind that has a unit of work. */
240
- export declare function selectFirstWorkUnit(workOrder: readonly WorkKindName[], data: WorkSelectionData, opts?: WorkSelectionOptions): WorkUnit | null;
241
- export declare function conflictFixFailureComment(prNumber: number, watermark?: ConflictFailWatermark): string;
242
- /**
243
- * After a sandbox conflict fix, the host may see 0 unpushed commits even when the sandbox
244
- * already pushed. Only post a failure comment when origin is unchanged and the PR still
245
- * conflicts.
246
- */
247
- export declare function shouldPostConflictFixFailure(opts: {
248
- hostCommitCount: number;
249
- originShaBefore: string;
250
- originShaAfter: string;
251
- mergeable: string;
252
- mergeStateStatus?: string;
253
- }): boolean;
254
- export declare function checksFixFailureComment(prNumber: number, watermark?: ChecksFailWatermark): string;
255
- /**
256
- * After a checks fix agent run, post a failure comment only when the agent made
257
- * no commits and did not push.
258
- */
259
- export declare function shouldPostChecksFixFailure(opts: {
260
- hostCommitCount: number;
261
- originShaBefore: string;
262
- originShaAfter: string;
263
- }): boolean;
264
- export declare function formatFailingChecksForPrompt(checks: readonly FailingCheck[]): string;
265
- export declare function buildInitialPrBody(opts: {
266
- issueNumber: number;
267
- commitCount: number;
268
- stacked?: {
269
- blockerIssueNumber: number;
270
- blockerPrNumber: number;
271
- };
272
- }): string;
273
- /** Incremental note for follow-up pushes — no stacked-PR banner. */
274
- export declare function followUpPrComment(issueNumber: number, commitCount: number): string;
275
- export {};