dev-loops 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 (156) hide show
  1. package/.pi/dev-loop/defaults.yaml +477 -0
  2. package/AGENTS.md +25 -0
  3. package/CHANGELOG.md +18 -0
  4. package/LICENSE +21 -0
  5. package/README.md +178 -0
  6. package/agents/dev-loop.agent.md +82 -0
  7. package/agents/developer.agent.md +37 -0
  8. package/agents/docs.agent.md +33 -0
  9. package/agents/fixer.agent.md +53 -0
  10. package/agents/quality.agent.md +28 -0
  11. package/agents/refiner.agent.md +87 -0
  12. package/agents/review.agent.md +64 -0
  13. package/cli/index.mjs +424 -0
  14. package/extension/README.md +233 -0
  15. package/extension/checks.ts +94 -0
  16. package/extension/index.ts +131 -0
  17. package/extension/post-merge-update.ts +512 -0
  18. package/extension/presentation.ts +107 -0
  19. package/lib/dev-loops-core.mjs +284 -0
  20. package/package.json +103 -0
  21. package/scripts/README.md +1007 -0
  22. package/scripts/_cli-primitives.mjs +10 -0
  23. package/scripts/_core-helpers.mjs +30 -0
  24. package/scripts/docs/validate-links.mjs +567 -0
  25. package/scripts/docs/validate-no-duplicate-rules.mjs +250 -0
  26. package/scripts/github/_review-thread-mutations.mjs +214 -0
  27. package/scripts/github/capture-review-threads.mjs +180 -0
  28. package/scripts/github/create-draft-pr.mjs +108 -0
  29. package/scripts/github/detect-checkpoint-evidence.mjs +393 -0
  30. package/scripts/github/detect-linked-issue-pr.mjs +331 -0
  31. package/scripts/github/manage-sub-issues.mjs +394 -0
  32. package/scripts/github/probe-copilot-review.mjs +323 -0
  33. package/scripts/github/ready-for-review.mjs +93 -0
  34. package/scripts/github/reconcile-draft-gate.mjs +328 -0
  35. package/scripts/github/reply-resolve-review-thread.mjs +42 -0
  36. package/scripts/github/reply-resolve-review-threads.mjs +329 -0
  37. package/scripts/github/request-copilot-review.mjs +551 -0
  38. package/scripts/github/resolve-tracker-local-spec.mjs +205 -0
  39. package/scripts/github/stage-reviewer-draft.mjs +191 -0
  40. package/scripts/github/upsert-checkpoint-verdict.mjs +694 -0
  41. package/scripts/github/verify-fresh-review-context.mjs +125 -0
  42. package/scripts/github/write-gate-findings-log.mjs +212 -0
  43. package/scripts/loop/_checkpoint-io.mjs +55 -0
  44. package/scripts/loop/_checkpoint-paths.mjs +28 -0
  45. package/scripts/loop/_handoff-contract.mjs +230 -0
  46. package/scripts/loop/_inspect-run-viewer-adapter.mjs +345 -0
  47. package/scripts/loop/_loop-evidence.mjs +32 -0
  48. package/scripts/loop/_pr-runner-coordination.mjs +611 -0
  49. package/scripts/loop/_stale-runner-detection.mjs +145 -0
  50. package/scripts/loop/_steering-state-file.mjs +134 -0
  51. package/scripts/loop/build-handoff-envelope.mjs +181 -0
  52. package/scripts/loop/checkpoint-contract.mjs +49 -0
  53. package/scripts/loop/conductor-monitor.mjs +1850 -0
  54. package/scripts/loop/conductor.mjs +214 -0
  55. package/scripts/loop/copilot-pr-handoff.mjs +493 -0
  56. package/scripts/loop/debt-remediate.mjs +304 -0
  57. package/scripts/loop/detect-change-scope.mjs +102 -0
  58. package/scripts/loop/detect-copilot-loop-state.mjs +454 -0
  59. package/scripts/loop/detect-copilot-session-activity.mjs +186 -0
  60. package/scripts/loop/detect-initial-copilot-pr-state.mjs +318 -0
  61. package/scripts/loop/detect-internal-only-pr.mjs +270 -0
  62. package/scripts/loop/detect-issue-refinement-artifact.mjs +163 -0
  63. package/scripts/loop/detect-pr-gate-coordination-state.mjs +509 -0
  64. package/scripts/loop/detect-reviewer-loop-state.mjs +231 -0
  65. package/scripts/loop/detect-stale-runner.mjs +250 -0
  66. package/scripts/loop/detect-tracker-first-loop-state.mjs +76 -0
  67. package/scripts/loop/detect-tracker-pr-state.mjs +102 -0
  68. package/scripts/loop/info.mjs +267 -0
  69. package/scripts/loop/inspect-run-viewer/cli.mjs +117 -0
  70. package/scripts/loop/inspect-run-viewer/constants.mjs +80 -0
  71. package/scripts/loop/inspect-run-viewer/graph.mjs +757 -0
  72. package/scripts/loop/inspect-run-viewer/handoff-envelope-renderer.mjs +398 -0
  73. package/scripts/loop/inspect-run-viewer/inbox.mjs +308 -0
  74. package/scripts/loop/inspect-run-viewer/managed-instance.mjs +750 -0
  75. package/scripts/loop/inspect-run-viewer/rendering.mjs +411 -0
  76. package/scripts/loop/inspect-run-viewer/server.mjs +638 -0
  77. package/scripts/loop/inspect-run-viewer/shared.mjs +103 -0
  78. package/scripts/loop/inspect-run-viewer/status.mjs +715 -0
  79. package/scripts/loop/inspect-run-viewer-ci-changes.mjs +77 -0
  80. package/scripts/loop/inspect-run-viewer.mjs +82 -0
  81. package/scripts/loop/inspect-run.mjs +382 -0
  82. package/scripts/loop/outer-loop.mjs +419 -0
  83. package/scripts/loop/pr-runner-coordination.mjs +143 -0
  84. package/scripts/loop/pre-commit-branch-guard.mjs +68 -0
  85. package/scripts/loop/pre-flight-gate.mjs +236 -0
  86. package/scripts/loop/pre-pr-ready-gate.mjs +183 -0
  87. package/scripts/loop/pre-push-main-guard.mjs +103 -0
  88. package/scripts/loop/pre-write-remote-freshness-guard.mjs +32 -0
  89. package/scripts/loop/print-gates.mjs +42 -0
  90. package/scripts/loop/resolve-dev-loop-startup.mjs +533 -0
  91. package/scripts/loop/run-conductor-cycle.mjs +322 -0
  92. package/scripts/loop/run-queue.mjs +124 -0
  93. package/scripts/loop/run-refinement-audit.mjs +513 -0
  94. package/scripts/loop/run-watch-cycle.mjs +358 -0
  95. package/scripts/loop/steer-loop.mjs +841 -0
  96. package/scripts/loop/ui-designer-review-contract.mjs +76 -0
  97. package/scripts/loop/watch-initial-copilot-pr.mjs +253 -0
  98. package/scripts/projects/add-queue-item.mjs +528 -0
  99. package/scripts/projects/ensure-queue-board.mjs +837 -0
  100. package/scripts/projects/list-queue-items.mjs +489 -0
  101. package/scripts/projects/move-queue-item.mjs +549 -0
  102. package/scripts/projects/reorder-queue-item.mjs +518 -0
  103. package/scripts/refine/_refine-helpers.mjs +258 -0
  104. package/scripts/refine/prose-linkage-detector.mjs +92 -0
  105. package/scripts/refine/refinement-completeness-checker.mjs +88 -0
  106. package/scripts/refine/scope-boundary-cross-checker.mjs +163 -0
  107. package/scripts/refine/tree-integrity-validator.mjs +211 -0
  108. package/scripts/refine/verify.mjs +178 -0
  109. package/scripts/repo-wiki-local.mjs +156 -0
  110. package/scripts/repo-wiki.mjs +119 -0
  111. package/skills/copilot-pr-followup/SKILL.md +380 -0
  112. package/skills/dev-loop/SKILL.md +141 -0
  113. package/skills/dev-loop/scripts/dev-mode-context.mjs +152 -0
  114. package/skills/dev-loop/scripts/dev-mode-context.test.mjs +80 -0
  115. package/skills/dev-loop/scripts/init-phase.mjs +71 -0
  116. package/skills/dev-loop/scripts/log-bash-exit-1.mjs +25 -0
  117. package/skills/dev-loop/scripts/phase-files.mjs +29 -0
  118. package/skills/dev-loop/scripts/post-gate-verdict-fallback.mjs +480 -0
  119. package/skills/dev-loop/scripts/post-gate-verdict-fallback.test.mjs +732 -0
  120. package/skills/dev-loop/scripts/render-template.mjs +82 -0
  121. package/skills/dev-loop/scripts/render-template.test.mjs +63 -0
  122. package/skills/dev-loop/templates/bootstrap-agents.md +26 -0
  123. package/skills/dev-loop/templates/bootstrap-implementation-state.md +31 -0
  124. package/skills/dev-loop/templates/bootstrap-implementation-workflow.md +17 -0
  125. package/skills/dev-loop/templates/dev-mode-retrospective.md +15 -0
  126. package/skills/dev-loop/templates/dev-mode-review.md +17 -0
  127. package/skills/dev-loop/templates/dev-mode-skill-changes.md +11 -0
  128. package/skills/dev-loop/templates/merged-phase-plan.md +19 -0
  129. package/skills/dev-loop/templates/phase-doc.md +27 -0
  130. package/skills/dev-loop/templates/phase-summary.md +13 -0
  131. package/skills/dev-loop/templates/phase-variant.md +15 -0
  132. package/skills/dev-loop/templates/retrospective.md +11 -0
  133. package/skills/dev-loop/templates/review.md +32 -0
  134. package/skills/dev-loop/templates/ui-vision-review.md +55 -0
  135. package/skills/docs/acceptance-criteria-verification.md +21 -0
  136. package/skills/docs/anti-patterns.md +21 -0
  137. package/skills/docs/artifact-authority-contract.md +119 -0
  138. package/skills/docs/confirmation-rules.md +28 -0
  139. package/skills/docs/copilot-ci-status-contract.md +52 -0
  140. package/skills/docs/copilot-loop-operations.md +233 -0
  141. package/skills/docs/debt-remediation-contract.md +107 -0
  142. package/skills/docs/entrypoint-strategies.md +115 -0
  143. package/skills/docs/epic-tree-refinement-procedure.md +234 -0
  144. package/skills/docs/issue-intake-procedure.md +235 -0
  145. package/skills/docs/main-agent-contract.md +72 -0
  146. package/skills/docs/merge-preconditions.md +29 -0
  147. package/skills/docs/pr-lifecycle-contract.md +209 -0
  148. package/skills/docs/public-dev-loop-contract.md +497 -0
  149. package/skills/docs/retrospective-checkpoint-contract.md +159 -0
  150. package/skills/docs/stop-conditions.md +29 -0
  151. package/skills/docs/structural-quality.md +42 -0
  152. package/skills/docs/tracker-first-loop-state.md +281 -0
  153. package/skills/docs/validation-policy.md +27 -0
  154. package/skills/docs/workflow-handoff-contract.md +135 -0
  155. package/skills/final-approval/SKILL.md +19 -0
  156. package/skills/local-implementation/SKILL.md +640 -0
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env node
2
+ import { runConductorCycle } from "./run-conductor-cycle.mjs";
3
+ import { runConductorMonitor } from "./conductor-monitor.mjs";
4
+ import { requireOptionValue } from "../_cli-primitives.mjs";
5
+ import { buildParseError, formatCliError, isDirectCliRun } from "../_core-helpers.mjs";
6
+ import { parseRepoSlug } from "@dev-loops/core/github/repo-slug";
7
+ import {
8
+ loadDevLoopConfig,
9
+ resolveWorkflowConfig,
10
+ resolveAutonomyStopAt,
11
+ resolveGateConfig,
12
+ } from "@dev-loops/core/config";
13
+ import { readFileSync } from "node:fs";
14
+ import path from "node:path";
15
+ const USAGE = `Usage: conductor.mjs --repo <owner/name> [--auto-resume] [--cycle-only] [--monitor-only] [--require-retrospective]
16
+ Unified conductor entrypoint for dev-loop lifecycle orchestration.`.trim();
17
+ const parseError = buildParseError(USAGE);
18
+ function checkRetrospectiveGate(cwd, requireRetrospective) {
19
+ if (!requireRetrospective) return { blocked: false };
20
+ try {
21
+ const checkpointPath = path.join(cwd, ".pi", "dev-loop-retrospective-checkpoint.json");
22
+ const checkpointText = readFileSync(checkpointPath, "utf8");
23
+ const checkpoint = JSON.parse(checkpointText);
24
+ const state = typeof checkpoint?.state === "string" ? checkpoint.state.trim().toLowerCase() : null;
25
+ if (state === "none" || state === "complete" || state === "skipped") {
26
+ return { blocked: false };
27
+ }
28
+ if (state === "required" || state === "missing" || state === null || state === "") {
29
+ return {
30
+ blocked: true,
31
+ reason: state === "required" || state === "missing"
32
+ ? `Retrospective checkpoint pending (state: ${state}). Complete the retrospective before running the conductor.`
33
+ : "Retrospective checkpoint file exists but has an unrecognized or empty state; cannot determine retrospective status safely.",
34
+ };
35
+ }
36
+ return {
37
+ blocked: true,
38
+ reason: `Retrospective checkpoint has an unrecognized state: "${state}".`,
39
+ };
40
+ } catch (err) {
41
+ if (err?.code === "ENOENT") return { blocked: false };
42
+ return { blocked: true, reason: `Cannot read retrospective checkpoint: ${err.message}` };
43
+ }
44
+ }
45
+ function parseCliArgs(argv) {
46
+ const args = [...argv];
47
+ const options = {
48
+ help: false,
49
+ repo: undefined,
50
+ autoResume: false,
51
+ cycleOnly: false,
52
+ monitorOnly: false,
53
+ requireRetrospective: false,
54
+ };
55
+ while (args.length > 0) {
56
+ const token = args.shift();
57
+ if (token === "--help" || token === "-h") {
58
+ options.help = true;
59
+ return options;
60
+ }
61
+ if (token === "--repo") {
62
+ options.repo = requireOptionValue(args, "--repo", parseError).trim();
63
+ continue;
64
+ }
65
+ if (token === "--auto-resume") {
66
+ options.autoResume = true;
67
+ continue;
68
+ }
69
+ if (token === "--cycle-only") {
70
+ options.cycleOnly = true;
71
+ continue;
72
+ }
73
+ if (token === "--monitor-only") {
74
+ options.monitorOnly = true;
75
+ continue;
76
+ }
77
+ if (token === "--require-retrospective") {
78
+ options.requireRetrospective = true;
79
+ continue;
80
+ }
81
+ throw parseError(`Unknown argument: ${token}`);
82
+ }
83
+ if (options.repo === undefined) {
84
+ throw parseError("conductor requires --repo <owner/name>");
85
+ }
86
+ if (options.cycleOnly && options.monitorOnly) {
87
+ throw parseError("--cycle-only and --monitor-only are mutually exclusive");
88
+ }
89
+ try {
90
+ parseRepoSlug(options.repo);
91
+ } catch (error) {
92
+ throw parseError(error instanceof Error ? error.message : String(error));
93
+ }
94
+ return options;
95
+ }
96
+ export async function runConductor(options, runtime = {}) {
97
+ const { cycleOnly = false, monitorOnly = false, autoResume = false, requireRetrospective: forceRetrospective = false } = options;
98
+ const cwd = runtime.repoRoot || process.cwd();
99
+ const loadConfig = runtime.loadConfigImpl || loadDevLoopConfig;
100
+ let configLoadResult;
101
+ let requireRetrospective = false;
102
+ let autonomyStopAt = ["merge"];
103
+ let gateConfig = { draft: { requireCi: true }, preApproval: { requireCi: true } };
104
+ try {
105
+ configLoadResult = await loadConfig({ repoRoot: cwd });
106
+ const hasErrors = Array.isArray(configLoadResult.errors) && configLoadResult.errors.length > 0;
107
+ if (hasErrors) {
108
+ configLoadResult = { ...configLoadResult };
109
+ } else {
110
+ const cfg = configLoadResult.config ?? {};
111
+ requireRetrospective = resolveWorkflowConfig(cfg, "requireRetrospective");
112
+ autonomyStopAt = resolveAutonomyStopAt(cfg);
113
+ const draftCfg = resolveGateConfig(cfg, "draft");
114
+ const preApprovalCfg = resolveGateConfig(cfg, "preApproval");
115
+ gateConfig = {
116
+ draft: { requireCi: draftCfg.requireCi },
117
+ preApproval: { requireCi: preApprovalCfg.requireCi },
118
+ };
119
+ }
120
+ } catch (error) {
121
+ const errorMessage = error instanceof Error ? error.message : String(error);
122
+ configLoadResult = { config: null, warnings: [], errors: [{ path: "<config>", message: `Failed to load config: ${errorMessage}`, layer: "merged" }] };
123
+ }
124
+ const effectiveRequireRetrospective = forceRetrospective || requireRetrospective;
125
+ const retroGate = checkRetrospectiveGate(cwd, effectiveRequireRetrospective);
126
+ if (retroGate.blocked) {
127
+ return {
128
+ ok: false,
129
+ error: retroGate.reason,
130
+ repo: options.repo,
131
+ blockedByRetrospective: true,
132
+ checkedAt: new Date().toISOString(),
133
+ };
134
+ }
135
+ const runCycle = !monitorOnly;
136
+ const runMonitor = !cycleOnly;
137
+ const cycleResult = runCycle
138
+ ? await runConductorCycle({ repo: options.repo, autonomyStopAt, gateConfig }, runtime).catch((error) => ({
139
+ ok: false,
140
+ error: error instanceof Error ? error.message : String(error),
141
+ }))
142
+ : null;
143
+ const monitorResult = runMonitor
144
+ ? await runConductorMonitor({ repo: options.repo, autoResume }, runtime).catch((error) => ({
145
+ ok: false,
146
+ error: error instanceof Error ? error.message : String(error),
147
+ }))
148
+ : null;
149
+ const cycleOk = cycleResult?.ok === true;
150
+ const monitorOk = monitorResult?.ok === true;
151
+ return {
152
+ ok: (runCycle ? cycleOk : true) && (runMonitor ? monitorOk : true),
153
+ repo: options.repo,
154
+ checkedAt: new Date().toISOString(),
155
+ cycle: cycleResult ?? null,
156
+ monitor: monitorResult ?? null,
157
+ cycleOk,
158
+ monitorOk,
159
+ config: {
160
+ requireRetrospective: effectiveRequireRetrospective,
161
+ configRequireRetrospective: requireRetrospective,
162
+ autonomyStopAt,
163
+ gateConfig,
164
+ configErrors: configLoadResult?.errors?.length ?? 0,
165
+ },
166
+ summary: {
167
+ totalPrs: (cycleResult?.prCount ?? 0) || (monitorResult?.prCount ?? 0),
168
+ cycleActions: cycleResult?.actions?.length ?? 0,
169
+ needsSubagent: cycleResult?.summary?.needsSubagent ?? 0,
170
+ readyToMerge: cycleResult?.summary?.readyToMerge ?? 0,
171
+ waiting: cycleResult?.summary?.waiting ?? 0,
172
+ blocked: cycleResult?.summary?.blocked ?? 0,
173
+ done: cycleResult?.summary?.done ?? 0,
174
+ errors: cycleResult?.summary?.errors ?? 0,
175
+ queueStatus: monitorResult?.queueStatus ?? "unknown",
176
+ needsAttentionCount: monitorResult?.needsAttentionCount ?? 0,
177
+ orphanedPrCount: monitorResult?.orphanedPrCount ?? 0,
178
+ resumePlanCount: monitorResult?.resumePlanCount ?? 0,
179
+ manualAttentionCount: monitorResult?.manualAttentionCount ?? 0,
180
+ },
181
+ };
182
+ }
183
+ export async function runCli(
184
+ argv = process.argv.slice(2),
185
+ {
186
+ stdout = process.stdout,
187
+ env = process.env,
188
+ ghCommand = "gh",
189
+ cwd = process.cwd(),
190
+ } = {},
191
+ ) {
192
+ const options = parseCliArgs(argv);
193
+ if (options.help) {
194
+ stdout.write(`${USAGE}\n`);
195
+ return;
196
+ }
197
+ const result = await runConductor(options, {
198
+ env,
199
+ ghCommand,
200
+ repoRoot: cwd,
201
+ });
202
+ if (result.ok === false) {
203
+ process.stderr.write(`${JSON.stringify(result)}\n`);
204
+ process.exitCode = 1;
205
+ return;
206
+ }
207
+ stdout.write(`${JSON.stringify(result)}\n`);
208
+ }
209
+ if (isDirectCliRun(import.meta.url)) {
210
+ runCli().catch((error) => {
211
+ process.stderr.write(`${formatCliError(error)}\n`);
212
+ process.exitCode = 1;
213
+ });
214
+ }