@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.
Files changed (54) hide show
  1. package/bin/capture-deep-persona-signals.mjs +143 -0
  2. package/bin/ensure-phase-files.mjs +7 -0
  3. package/bin/log-bash-exit-1.mjs +7 -0
  4. package/bin/parse-review-threads.mjs +7 -0
  5. package/package.json +78 -0
  6. package/src/analysis/change-classifier.mjs +146 -0
  7. package/src/analysis/diff-analyzer.mjs +285 -0
  8. package/src/bash-exit-one.mjs +130 -0
  9. package/src/cli/helpers.mjs +22 -0
  10. package/src/cli/primitives.mjs +70 -0
  11. package/src/cli/retry-wrapper.mjs +169 -0
  12. package/src/cli/subcommand-runner.mjs +246 -0
  13. package/src/config/config.mjs +965 -0
  14. package/src/debt/cluster.mjs +240 -0
  15. package/src/debt/debt-finding.mjs +68 -0
  16. package/src/debt/debt-signal.mjs +46 -0
  17. package/src/debt/deep-persona-signals.mjs +266 -0
  18. package/src/debt/remediation-to-issue.mjs +121 -0
  19. package/src/debt/score.mjs +127 -0
  20. package/src/debt/shape.mjs +214 -0
  21. package/src/github/copilot-helpers.mjs +343 -0
  22. package/src/github/repo-slug.mjs +105 -0
  23. package/src/github/review-threads.mjs +343 -0
  24. package/src/harness/adapter.mjs +57 -0
  25. package/src/harness/index.mjs +3 -0
  26. package/src/harness/noop-adapter.mjs +22 -0
  27. package/src/harness/pi-adapter.mjs +47 -0
  28. package/src/loop/async-start-contract.mjs +170 -0
  29. package/src/loop/conductor-routing.mjs +817 -0
  30. package/src/loop/copilot-ci-status.mjs +255 -0
  31. package/src/loop/copilot-loop-iterations.mjs +161 -0
  32. package/src/loop/copilot-loop-state.mjs +510 -0
  33. package/src/loop/handoff-envelope.mjs +800 -0
  34. package/src/loop/issue-refinement-artifact.mjs +268 -0
  35. package/src/loop/lifecycle-state.mjs +342 -0
  36. package/src/loop/phase-files.mjs +187 -0
  37. package/src/loop/policy-constants.mjs +17 -0
  38. package/src/loop/pr-gate-coordination.mjs +1278 -0
  39. package/src/loop/public-dev-loop-routing-contract.mjs +277 -0
  40. package/src/loop/public-dev-loop-routing.mjs +1746 -0
  41. package/src/loop/queue-board-ordering.mjs +38 -0
  42. package/src/loop/queue-board-sync.mjs +223 -0
  43. package/src/loop/queue-driver.mjs +164 -0
  44. package/src/loop/queue-parallel.mjs +190 -0
  45. package/src/loop/queue-state.mjs +230 -0
  46. package/src/loop/retrospective-checkpoint.mjs +178 -0
  47. package/src/loop/reviewer-loop-state.mjs +456 -0
  48. package/src/loop/run-inspection.mjs +604 -0
  49. package/src/loop/steering.mjs +793 -0
  50. package/src/loop/timeout-policy.mjs +73 -0
  51. package/src/loop/tracker-first-loop-state.mjs +87 -0
  52. package/src/loop/tracker-pr-state.mjs +301 -0
  53. package/src/loop/worktree-guard.mjs +141 -0
  54. 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
+