@dev-loops/core 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.
- package/bin/capture-deep-persona-signals.mjs +143 -0
- package/bin/ensure-phase-files.mjs +7 -0
- package/bin/log-bash-exit-1.mjs +7 -0
- package/bin/parse-review-threads.mjs +7 -0
- package/package.json +78 -0
- package/src/analysis/change-classifier.mjs +146 -0
- package/src/analysis/diff-analyzer.mjs +285 -0
- package/src/bash-exit-one.mjs +130 -0
- package/src/cli/helpers.mjs +22 -0
- package/src/cli/primitives.mjs +70 -0
- package/src/cli/retry-wrapper.mjs +169 -0
- package/src/cli/subcommand-runner.mjs +246 -0
- package/src/config/config.mjs +965 -0
- package/src/debt/cluster.mjs +240 -0
- package/src/debt/debt-finding.mjs +68 -0
- package/src/debt/debt-signal.mjs +46 -0
- package/src/debt/deep-persona-signals.mjs +266 -0
- package/src/debt/remediation-to-issue.mjs +121 -0
- package/src/debt/score.mjs +127 -0
- package/src/debt/shape.mjs +214 -0
- package/src/github/copilot-helpers.mjs +343 -0
- package/src/github/repo-slug.mjs +105 -0
- package/src/github/review-threads.mjs +343 -0
- package/src/harness/adapter.mjs +57 -0
- package/src/harness/index.mjs +3 -0
- package/src/harness/noop-adapter.mjs +22 -0
- package/src/harness/pi-adapter.mjs +47 -0
- package/src/loop/async-start-contract.mjs +170 -0
- package/src/loop/conductor-routing.mjs +817 -0
- package/src/loop/copilot-ci-status.mjs +255 -0
- package/src/loop/copilot-loop-iterations.mjs +161 -0
- package/src/loop/copilot-loop-state.mjs +510 -0
- package/src/loop/handoff-envelope.mjs +800 -0
- package/src/loop/issue-refinement-artifact.mjs +268 -0
- package/src/loop/lifecycle-state.mjs +342 -0
- package/src/loop/phase-files.mjs +187 -0
- package/src/loop/policy-constants.mjs +17 -0
- package/src/loop/pr-gate-coordination.mjs +1278 -0
- package/src/loop/public-dev-loop-routing-contract.mjs +277 -0
- package/src/loop/public-dev-loop-routing.mjs +1746 -0
- package/src/loop/queue-board-ordering.mjs +38 -0
- package/src/loop/queue-board-sync.mjs +223 -0
- package/src/loop/queue-driver.mjs +164 -0
- package/src/loop/queue-parallel.mjs +190 -0
- package/src/loop/queue-state.mjs +230 -0
- package/src/loop/retrospective-checkpoint.mjs +178 -0
- package/src/loop/reviewer-loop-state.mjs +456 -0
- package/src/loop/run-inspection.mjs +604 -0
- package/src/loop/steering.mjs +793 -0
- package/src/loop/timeout-policy.mjs +73 -0
- package/src/loop/tracker-first-loop-state.mjs +87 -0
- package/src/loop/tracker-pr-state.mjs +301 -0
- package/src/loop/worktree-guard.mjs +141 -0
- package/src/refinement/ac-dod-matrix.mjs +95 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public dev-loop façade routing contract.
|
|
3
|
+
*
|
|
4
|
+
* This evaluator models the first-slice public entrypoint contract from issue #86:
|
|
5
|
+
* - one public entrypoint: `dev-loop`
|
|
6
|
+
* - one canonical current-state shape
|
|
7
|
+
* - deterministic routing to internal strategy families
|
|
8
|
+
* - no legacy compatibility entrypoint projection in routed results
|
|
9
|
+
*
|
|
10
|
+
* The evaluator is intentionally pure and side-effect free. It does not inspect
|
|
11
|
+
* GitHub or local state itself; callers may provide the authoritative current
|
|
12
|
+
* state they have already detected, or omit it for explicit start intents where
|
|
13
|
+
* the router can synthesize a minimal canonical state from the requested target.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const PUBLIC_DEV_LOOP_ENTRYPOINT = "dev-loop";
|
|
17
|
+
|
|
18
|
+
export const DEV_LOOP_PUBLIC_INTENT = Object.freeze({
|
|
19
|
+
START_ON_ISSUE: "start_on_issue",
|
|
20
|
+
CONTINUE_ON_PR: "continue_on_pr",
|
|
21
|
+
START_ISSUE_LOCALLY: "start_issue_locally",
|
|
22
|
+
START_ISSUE_LOCALLY_THEN_CONTINUE: "start_issue_locally_then_continue",
|
|
23
|
+
CONTINUE_CURRENT: "continue_current",
|
|
24
|
+
AUTO_CONTINUE_CURRENT: "auto_continue_current",
|
|
25
|
+
INSPECT_STATE: "inspect_state",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const DEV_LOOP_TARGET_KIND = Object.freeze({
|
|
29
|
+
ISSUE: "issue",
|
|
30
|
+
PR: "pr",
|
|
31
|
+
LOCAL_BRANCH: "local_branch",
|
|
32
|
+
LOCAL_PHASE: "local_phase",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const DEV_LOOP_ACTOR = Object.freeze({
|
|
36
|
+
LOCAL: "local",
|
|
37
|
+
COPILOT: "copilot",
|
|
38
|
+
EXTERNAL_HUMAN: "external_human",
|
|
39
|
+
REVIEWER: "reviewer",
|
|
40
|
+
MAINTAINER: "maintainer",
|
|
41
|
+
USER: "user",
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const DEV_LOOP_STATUS = Object.freeze({
|
|
45
|
+
ACTIVE: "active",
|
|
46
|
+
WAITING: "waiting",
|
|
47
|
+
BLOCKED: "blocked",
|
|
48
|
+
APPROVAL_READY: "approval_ready",
|
|
49
|
+
MERGE_READY: "merge_ready",
|
|
50
|
+
DONE: "done",
|
|
51
|
+
RETROSPECTIVE_GATE_PENDING: "retrospective_gate_pending",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const DEV_LOOP_AUTHORIZATION = Object.freeze({
|
|
55
|
+
AUTHORIZED: "authorized",
|
|
56
|
+
NEEDS_CONFIRMATION: "needs_confirmation",
|
|
57
|
+
NOT_AUTHORIZED: "not_authorized",
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export const DEV_LOOP_ROUTE_KIND = Object.freeze({
|
|
61
|
+
ROUTE: "route",
|
|
62
|
+
WAIT: "wait",
|
|
63
|
+
STOP: "stop",
|
|
64
|
+
INSPECT: "inspect",
|
|
65
|
+
NEEDS_RECONCILE: "needs_reconcile",
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const DEV_LOOP_GATE = Object.freeze({
|
|
69
|
+
STOP_BLOCKED_OR_NOT_AUTHORIZED: "stop_blocked_or_not_authorized",
|
|
70
|
+
STOP_DONE_TERMINAL: "stop_done_terminal",
|
|
71
|
+
FINAL_APPROVAL: "final_approval",
|
|
72
|
+
WAITING_FOR_MERGE_AUTHORIZATION: "waiting_for_merge_authorization",
|
|
73
|
+
WAIT_WATCH: "wait_watch",
|
|
74
|
+
LOCAL_IMPLEMENTATION: "local_implementation",
|
|
75
|
+
ISSUE_INTAKE: "issue_intake",
|
|
76
|
+
EXTERNAL_PR_FOLLOWUP: "external_pr_followup",
|
|
77
|
+
REVIEWER_FIXER: "reviewer_fixer",
|
|
78
|
+
COPILOT_PR_FOLLOWUP: "copilot_pr_followup",
|
|
79
|
+
FAIL_CLOSED_RECONCILE: "fail_closed_reconcile",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export const INTERNAL_DEV_LOOP_STRATEGY = Object.freeze({
|
|
83
|
+
LOCAL_IMPLEMENTATION: "local_implementation",
|
|
84
|
+
ISSUE_INTAKE: "issue_intake",
|
|
85
|
+
COPILOT_PR_FOLLOWUP: "copilot_pr_followup",
|
|
86
|
+
EXTERNAL_PR_FOLLOWUP: "external_pr_followup",
|
|
87
|
+
REVIEWER_FIXER: "reviewer_fixer",
|
|
88
|
+
WAIT_WATCH: "wait_watch",
|
|
89
|
+
FINAL_APPROVAL: "final_approval",
|
|
90
|
+
NONE: null,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export const DEV_LOOP_ARTIFACT_STATE = Object.freeze({
|
|
94
|
+
OPEN: "open",
|
|
95
|
+
CLOSED: "closed",
|
|
96
|
+
MERGED: "merged",
|
|
97
|
+
NOT_APPLICABLE: "not_applicable",
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
export const DEV_LOOP_STATUS_REPORT_KIND = Object.freeze({
|
|
101
|
+
RESOLVED: "resolved",
|
|
102
|
+
NEEDS_RECONCILE: "needs_reconcile",
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
export const DEV_LOOP_CONTRACT_TRACE_CLASSIFICATION = Object.freeze({
|
|
106
|
+
ROUTED_FOLLOWUP: "routed_followup",
|
|
107
|
+
HEALTHY_WAIT: "healthy_wait",
|
|
108
|
+
TERMINAL: "terminal",
|
|
109
|
+
BLOCKED: "blocked",
|
|
110
|
+
AUTHORIZATION_GATED: "authorization_gated",
|
|
111
|
+
RECONCILE: "reconcile",
|
|
112
|
+
INSPECT: "inspect",
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
export const DEV_LOOP_STARTUP_RESUME_BUNDLE_KIND = Object.freeze({
|
|
116
|
+
RESOLVED: "resolved",
|
|
117
|
+
NEEDS_RECONCILE: "needs_reconcile",
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
export const DEV_LOOP_EXECUTION_MODE = Object.freeze({
|
|
121
|
+
BOUNDED_HANDOFF: "bounded_handoff",
|
|
122
|
+
DURABLE_AUTO: "durable_auto",
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
export const DEV_LOOP_WAIT_SEMANTICS = Object.freeze({
|
|
126
|
+
DEFAULT: "default",
|
|
127
|
+
AUTO_HEALTHY_WAIT: "auto_healthy_wait",
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export const DEV_LOOP_ISSUE_LINKAGE_RESOLUTION = Object.freeze({
|
|
131
|
+
RESOLVED_LINKED_PR: "resolved_linked_pr",
|
|
132
|
+
RESOLVED_NO_OPEN_PR: "resolved_no_open_pr",
|
|
133
|
+
NOT_APPLICABLE: "not_applicable",
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
export const DEV_LOOP_ISSUE_READINESS = Object.freeze({
|
|
137
|
+
READY: "ready",
|
|
138
|
+
NEEDS_CLARIFICATION: "needs_clarification",
|
|
139
|
+
NOT_APPLICABLE: "not_applicable",
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
export const DEV_LOOP_ISSUE_ASSIGNMENT_STATE = Object.freeze({
|
|
143
|
+
UNASSIGNED: "unassigned",
|
|
144
|
+
ASSIGNED_TO_COPILOT: "assigned_to_copilot",
|
|
145
|
+
NOT_APPLICABLE: "not_applicable",
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
export const DEV_LOOP_ISSUE_ASSIGNMENT_SEAM = Object.freeze({
|
|
149
|
+
NEEDS_REFINEMENT: "needs_refinement",
|
|
150
|
+
READY_NEEDS_ASSIGNMENT_CONFIRMATION: "ready_needs_assignment_confirmation",
|
|
151
|
+
READY_ASSIGN_NOW: "ready_assign_now",
|
|
152
|
+
ASSIGNED_TO_COPILOT: "assigned_to_copilot",
|
|
153
|
+
NOT_APPLICABLE: "not_applicable",
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Bounded first-slice target preference values for the `targetPreference` variation parameter.
|
|
158
|
+
*
|
|
159
|
+
* `prefer_local` steers routing toward local implementation when no authoritative
|
|
160
|
+
* PR/linked-PR active-artifact truth has already decided the route.
|
|
161
|
+
* It must not override authoritative state — if the canonical state already resolves
|
|
162
|
+
* to an active PR or linked-PR path, `prefer_local` fails closed instead of silently coercing.
|
|
163
|
+
*/
|
|
164
|
+
export const DEV_LOOP_TARGET_PREFERENCE = Object.freeze({
|
|
165
|
+
PREFER_GITHUB_FIRST: "prefer_github_first",
|
|
166
|
+
PREFER_LOCAL: "prefer_local",
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* First-slice bounded variation parameter contract for the public `dev-loop` entrypoint.
|
|
171
|
+
*
|
|
172
|
+
* Variation parameters may **steer** `dev-loop` behavior, but must not replace
|
|
173
|
+
* authoritative routing. Precedence order (highest to lowest):
|
|
174
|
+
* 1. authoritative current state — primary routing source of truth
|
|
175
|
+
* 2. explicit user intent and API parameters — choose variation mode within the entrypoint
|
|
176
|
+
* 3. settings/preferences — provide defaults only when (1) and (2) have not decided
|
|
177
|
+
*
|
|
178
|
+
* Ambiguous or conflicting parameter combinations fail closed instead of silently
|
|
179
|
+
* overriding authoritative state.
|
|
180
|
+
*/
|
|
181
|
+
export const DEV_LOOP_VARIATION_PARAMETER_CONTRACT = Object.freeze({
|
|
182
|
+
/** Allowed first-slice variation parameter names. */
|
|
183
|
+
allowedParameters: Object.freeze(["mode", "watch", "intent", "targetPreference"]),
|
|
184
|
+
/** Allowed values for the `mode` parameter. */
|
|
185
|
+
allowedModeValues: Object.freeze([DEV_LOOP_EXECUTION_MODE.BOUNDED_HANDOFF, DEV_LOOP_EXECUTION_MODE.DURABLE_AUTO]),
|
|
186
|
+
/** Allowed values for the `targetPreference` parameter. */
|
|
187
|
+
allowedTargetPreferenceValues: Object.freeze(Object.values(DEV_LOOP_TARGET_PREFERENCE)),
|
|
188
|
+
/**
|
|
189
|
+
* Disallowed variation categories for this slice.
|
|
190
|
+
* These must not become public variation knobs.
|
|
191
|
+
*/
|
|
192
|
+
disallowedCategories: Object.freeze([
|
|
193
|
+
"arbitrary_ownership_override",
|
|
194
|
+
"arbitrary_strategy_override",
|
|
195
|
+
"arbitrary_gate_override",
|
|
196
|
+
"issue_pr_linkage_bypass",
|
|
197
|
+
"expert_mode_flags",
|
|
198
|
+
]),
|
|
199
|
+
/**
|
|
200
|
+
* Precedence order for variation inputs (index 0 = highest authority).
|
|
201
|
+
*/
|
|
202
|
+
precedenceOrder: Object.freeze([
|
|
203
|
+
"authoritative_current_state",
|
|
204
|
+
"explicit_intent_and_parameters",
|
|
205
|
+
"settings_and_preferences",
|
|
206
|
+
]),
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
export const PUBLIC_DEV_LOOP_GATE_CONTRACT = Object.freeze([
|
|
210
|
+
Object.freeze({
|
|
211
|
+
gate: DEV_LOOP_GATE.STOP_BLOCKED_OR_NOT_AUTHORIZED,
|
|
212
|
+
routeKind: DEV_LOOP_ROUTE_KIND.STOP,
|
|
213
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.NONE,
|
|
214
|
+
summary: "blocked or not-authorized canonical state stops for a human decision",
|
|
215
|
+
}),
|
|
216
|
+
Object.freeze({
|
|
217
|
+
gate: DEV_LOOP_GATE.STOP_DONE_TERMINAL,
|
|
218
|
+
routeKind: DEV_LOOP_ROUTE_KIND.STOP,
|
|
219
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.NONE,
|
|
220
|
+
summary: "done canonical state stops as terminal work",
|
|
221
|
+
}),
|
|
222
|
+
Object.freeze({
|
|
223
|
+
gate: DEV_LOOP_GATE.FINAL_APPROVAL,
|
|
224
|
+
routeKind: DEV_LOOP_ROUTE_KIND.ROUTE,
|
|
225
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.FINAL_APPROVAL,
|
|
226
|
+
summary: "approval-ready canonical state routes to final approval; merge-ready routes here only when merge authorization is explicit; requires explicit current-head pre_approval_gate evidence — clean-looking signals are not substitutes",
|
|
227
|
+
}),
|
|
228
|
+
Object.freeze({
|
|
229
|
+
gate: DEV_LOOP_GATE.WAITING_FOR_MERGE_AUTHORIZATION,
|
|
230
|
+
routeKind: DEV_LOOP_ROUTE_KIND.STOP,
|
|
231
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.NONE,
|
|
232
|
+
summary: "merge-ready canonical state without explicit merge authorization stops and waits for merge authorization",
|
|
233
|
+
}),
|
|
234
|
+
Object.freeze({
|
|
235
|
+
gate: DEV_LOOP_GATE.WAIT_WATCH,
|
|
236
|
+
routeKind: DEV_LOOP_ROUTE_KIND.WAIT,
|
|
237
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.WAIT_WATCH,
|
|
238
|
+
summary: "waiting canonical state routes to the shared wait/watch strategy",
|
|
239
|
+
}),
|
|
240
|
+
Object.freeze({
|
|
241
|
+
gate: DEV_LOOP_GATE.LOCAL_IMPLEMENTATION,
|
|
242
|
+
routeKind: DEV_LOOP_ROUTE_KIND.ROUTE,
|
|
243
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.LOCAL_IMPLEMENTATION,
|
|
244
|
+
summary: "local branch or phase canonical state stays on local implementation",
|
|
245
|
+
}),
|
|
246
|
+
Object.freeze({
|
|
247
|
+
gate: DEV_LOOP_GATE.ISSUE_INTAKE,
|
|
248
|
+
routeKind: DEV_LOOP_ROUTE_KIND.ROUTE,
|
|
249
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.ISSUE_INTAKE,
|
|
250
|
+
summary: "issue canonical state without a linked PR routes to issue intake",
|
|
251
|
+
}),
|
|
252
|
+
Object.freeze({
|
|
253
|
+
gate: DEV_LOOP_GATE.EXTERNAL_PR_FOLLOWUP,
|
|
254
|
+
routeKind: DEV_LOOP_ROUTE_KIND.ROUTE,
|
|
255
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.EXTERNAL_PR_FOLLOWUP,
|
|
256
|
+
summary: "external-human PR ownership routes to external PR follow-up",
|
|
257
|
+
}),
|
|
258
|
+
Object.freeze({
|
|
259
|
+
gate: DEV_LOOP_GATE.REVIEWER_FIXER,
|
|
260
|
+
routeKind: DEV_LOOP_ROUTE_KIND.ROUTE,
|
|
261
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.REVIEWER_FIXER,
|
|
262
|
+
summary: "reviewer-owned or reviewer-next PR state routes to reviewer/fixer",
|
|
263
|
+
}),
|
|
264
|
+
Object.freeze({
|
|
265
|
+
gate: DEV_LOOP_GATE.COPILOT_PR_FOLLOWUP,
|
|
266
|
+
routeKind: DEV_LOOP_ROUTE_KIND.ROUTE,
|
|
267
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.COPILOT_PR_FOLLOWUP,
|
|
268
|
+
summary: "Copilot-owned PR state routes to Copilot PR follow-up; an already-linked open PR stays the canonical artifact for that issue until reconciled",
|
|
269
|
+
}),
|
|
270
|
+
Object.freeze({
|
|
271
|
+
gate: DEV_LOOP_GATE.FAIL_CLOSED_RECONCILE,
|
|
272
|
+
routeKind: DEV_LOOP_ROUTE_KIND.NEEDS_RECONCILE,
|
|
273
|
+
selectedStrategy: INTERNAL_DEV_LOOP_STRATEGY.NONE,
|
|
274
|
+
summary: "ambiguous, conflicting, or unsupported canonical state fails closed to reconcile",
|
|
275
|
+
}),
|
|
276
|
+
]);
|
|
277
|
+
|