@devenius/junamis-skills 0.0.0-stage → 1.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 (311) hide show
  1. package/CHANGELOG.md +150 -0
  2. package/LICENSE +21 -0
  3. package/README.md +231 -2
  4. package/SECURITY.md +81 -0
  5. package/bin/junamis-skills.js +7 -0
  6. package/dist/cli.d.ts +59 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +564 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/color.d.ts +40 -0
  11. package/dist/color.d.ts.map +1 -0
  12. package/dist/color.js +55 -0
  13. package/dist/color.js.map +1 -0
  14. package/dist/design/atomic.d.ts +4 -0
  15. package/dist/design/atomic.d.ts.map +1 -0
  16. package/dist/design/atomic.js +14 -0
  17. package/dist/design/atomic.js.map +1 -0
  18. package/dist/design/bootstrap.d.ts +23 -0
  19. package/dist/design/bootstrap.d.ts.map +1 -0
  20. package/dist/design/bootstrap.js +411 -0
  21. package/dist/design/bootstrap.js.map +1 -0
  22. package/dist/design/cli.d.ts +86 -0
  23. package/dist/design/cli.d.ts.map +1 -0
  24. package/dist/design/cli.js +425 -0
  25. package/dist/design/cli.js.map +1 -0
  26. package/dist/design/delta.d.ts +45 -0
  27. package/dist/design/delta.d.ts.map +1 -0
  28. package/dist/design/delta.js +557 -0
  29. package/dist/design/delta.js.map +1 -0
  30. package/dist/design/drift.d.ts +26 -0
  31. package/dist/design/drift.d.ts.map +1 -0
  32. package/dist/design/drift.js +341 -0
  33. package/dist/design/drift.js.map +1 -0
  34. package/dist/design/errors.d.ts +25 -0
  35. package/dist/design/errors.d.ts.map +1 -0
  36. package/dist/design/errors.js +30 -0
  37. package/dist/design/errors.js.map +1 -0
  38. package/dist/design/events.d.ts +18 -0
  39. package/dist/design/events.d.ts.map +1 -0
  40. package/dist/design/events.js +44 -0
  41. package/dist/design/events.js.map +1 -0
  42. package/dist/design/fingerprint.d.ts +10 -0
  43. package/dist/design/fingerprint.d.ts.map +1 -0
  44. package/dist/design/fingerprint.js +66 -0
  45. package/dist/design/fingerprint.js.map +1 -0
  46. package/dist/design/index-gen.d.ts +16 -0
  47. package/dist/design/index-gen.d.ts.map +1 -0
  48. package/dist/design/index-gen.js +94 -0
  49. package/dist/design/index-gen.js.map +1 -0
  50. package/dist/design/schema.d.ts +54 -0
  51. package/dist/design/schema.d.ts.map +1 -0
  52. package/dist/design/schema.js +408 -0
  53. package/dist/design/schema.js.map +1 -0
  54. package/dist/design/yaml.d.ts +12 -0
  55. package/dist/design/yaml.d.ts.map +1 -0
  56. package/dist/design/yaml.js +264 -0
  57. package/dist/design/yaml.js.map +1 -0
  58. package/dist/external.d.ts +61 -0
  59. package/dist/external.d.ts.map +1 -0
  60. package/dist/external.js +426 -0
  61. package/dist/external.js.map +1 -0
  62. package/dist/guide.d.ts +17 -0
  63. package/dist/guide.d.ts.map +1 -0
  64. package/dist/guide.js +219 -0
  65. package/dist/guide.js.map +1 -0
  66. package/dist/index.d.ts +2 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +7 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/install-external.d.ts +3 -0
  71. package/dist/install-external.d.ts.map +1 -0
  72. package/dist/install-external.js +37 -0
  73. package/dist/install-external.js.map +1 -0
  74. package/dist/library-install.d.ts +39 -0
  75. package/dist/library-install.d.ts.map +1 -0
  76. package/dist/library-install.js +663 -0
  77. package/dist/library-install.js.map +1 -0
  78. package/dist/orchestrator/boot.d.ts +3 -0
  79. package/dist/orchestrator/boot.d.ts.map +1 -0
  80. package/dist/orchestrator/boot.js +515 -0
  81. package/dist/orchestrator/boot.js.map +1 -0
  82. package/dist/orchestrator/cli.d.ts +37 -0
  83. package/dist/orchestrator/cli.d.ts.map +1 -0
  84. package/dist/orchestrator/cli.js +563 -0
  85. package/dist/orchestrator/cli.js.map +1 -0
  86. package/dist/orchestrator/commands.d.ts +46 -0
  87. package/dist/orchestrator/commands.d.ts.map +1 -0
  88. package/dist/orchestrator/commands.js +752 -0
  89. package/dist/orchestrator/commands.js.map +1 -0
  90. package/dist/orchestrator/compaction.d.ts +21 -0
  91. package/dist/orchestrator/compaction.d.ts.map +1 -0
  92. package/dist/orchestrator/compaction.js +93 -0
  93. package/dist/orchestrator/compaction.js.map +1 -0
  94. package/dist/orchestrator/drift.d.ts +11 -0
  95. package/dist/orchestrator/drift.d.ts.map +1 -0
  96. package/dist/orchestrator/drift.js +181 -0
  97. package/dist/orchestrator/drift.js.map +1 -0
  98. package/dist/orchestrator/errors.d.ts +52 -0
  99. package/dist/orchestrator/errors.d.ts.map +1 -0
  100. package/dist/orchestrator/errors.js +96 -0
  101. package/dist/orchestrator/errors.js.map +1 -0
  102. package/dist/orchestrator/frontmatter.d.ts +6 -0
  103. package/dist/orchestrator/frontmatter.d.ts.map +1 -0
  104. package/dist/orchestrator/frontmatter.js +50 -0
  105. package/dist/orchestrator/frontmatter.js.map +1 -0
  106. package/dist/orchestrator/fsx.d.ts +45 -0
  107. package/dist/orchestrator/fsx.d.ts.map +1 -0
  108. package/dist/orchestrator/fsx.js +295 -0
  109. package/dist/orchestrator/fsx.js.map +1 -0
  110. package/dist/orchestrator/handoff.d.ts +8 -0
  111. package/dist/orchestrator/handoff.d.ts.map +1 -0
  112. package/dist/orchestrator/handoff.js +246 -0
  113. package/dist/orchestrator/handoff.js.map +1 -0
  114. package/dist/orchestrator/hash.d.ts +10 -0
  115. package/dist/orchestrator/hash.d.ts.map +1 -0
  116. package/dist/orchestrator/hash.js +65 -0
  117. package/dist/orchestrator/hash.js.map +1 -0
  118. package/dist/orchestrator/journal.d.ts +35 -0
  119. package/dist/orchestrator/journal.d.ts.map +1 -0
  120. package/dist/orchestrator/journal.js +163 -0
  121. package/dist/orchestrator/journal.js.map +1 -0
  122. package/dist/orchestrator/lease.d.ts +31 -0
  123. package/dist/orchestrator/lease.d.ts.map +1 -0
  124. package/dist/orchestrator/lease.js +175 -0
  125. package/dist/orchestrator/lease.js.map +1 -0
  126. package/dist/orchestrator/plan.d.ts +27 -0
  127. package/dist/orchestrator/plan.d.ts.map +1 -0
  128. package/dist/orchestrator/plan.js +240 -0
  129. package/dist/orchestrator/plan.js.map +1 -0
  130. package/dist/orchestrator/report.d.ts +49 -0
  131. package/dist/orchestrator/report.d.ts.map +1 -0
  132. package/dist/orchestrator/report.js +244 -0
  133. package/dist/orchestrator/report.js.map +1 -0
  134. package/dist/orchestrator/state.d.ts +43 -0
  135. package/dist/orchestrator/state.d.ts.map +1 -0
  136. package/dist/orchestrator/state.js +369 -0
  137. package/dist/orchestrator/state.js.map +1 -0
  138. package/dist/orchestrator/store.d.ts +42 -0
  139. package/dist/orchestrator/store.d.ts.map +1 -0
  140. package/dist/orchestrator/store.js +202 -0
  141. package/dist/orchestrator/store.js.map +1 -0
  142. package/dist/orchestrator/test-hooks.d.ts +5 -0
  143. package/dist/orchestrator/test-hooks.d.ts.map +1 -0
  144. package/dist/orchestrator/test-hooks.js +31 -0
  145. package/dist/orchestrator/test-hooks.js.map +1 -0
  146. package/dist/orchestrator/time.d.ts +11 -0
  147. package/dist/orchestrator/time.d.ts.map +1 -0
  148. package/dist/orchestrator/time.js +38 -0
  149. package/dist/orchestrator/time.js.map +1 -0
  150. package/dist/paths.d.ts +9 -0
  151. package/dist/paths.d.ts.map +1 -0
  152. package/dist/paths.js +42 -0
  153. package/dist/paths.js.map +1 -0
  154. package/dist/pinned-source.d.ts +13 -0
  155. package/dist/pinned-source.d.ts.map +1 -0
  156. package/dist/pinned-source.js +238 -0
  157. package/dist/pinned-source.js.map +1 -0
  158. package/dist/reconcile/cli.d.ts +17 -0
  159. package/dist/reconcile/cli.d.ts.map +1 -0
  160. package/dist/reconcile/cli.js +171 -0
  161. package/dist/reconcile/cli.js.map +1 -0
  162. package/dist/reconcile/detectors.d.ts +29 -0
  163. package/dist/reconcile/detectors.d.ts.map +1 -0
  164. package/dist/reconcile/detectors.js +294 -0
  165. package/dist/reconcile/detectors.js.map +1 -0
  166. package/dist/reconcile/manifest.d.ts +11 -0
  167. package/dist/reconcile/manifest.d.ts.map +1 -0
  168. package/dist/reconcile/manifest.js +118 -0
  169. package/dist/reconcile/manifest.js.map +1 -0
  170. package/dist/reconcile/queue.d.ts +3 -0
  171. package/dist/reconcile/queue.d.ts.map +1 -0
  172. package/dist/reconcile/queue.js +723 -0
  173. package/dist/reconcile/queue.js.map +1 -0
  174. package/dist/reconcile/score.d.ts +19 -0
  175. package/dist/reconcile/score.d.ts.map +1 -0
  176. package/dist/reconcile/score.js +58 -0
  177. package/dist/reconcile/score.js.map +1 -0
  178. package/dist/scripts/check-opencode-config.d.ts +12 -0
  179. package/dist/scripts/check-opencode-config.d.ts.map +1 -0
  180. package/dist/scripts/check-opencode-config.js +216 -0
  181. package/dist/scripts/check-opencode-config.js.map +1 -0
  182. package/dist/scripts/check-pack.d.ts +3 -0
  183. package/dist/scripts/check-pack.d.ts.map +1 -0
  184. package/dist/scripts/check-pack.js +74 -0
  185. package/dist/scripts/check-pack.js.map +1 -0
  186. package/dist/scripts/check-pins.d.ts +9 -0
  187. package/dist/scripts/check-pins.d.ts.map +1 -0
  188. package/dist/scripts/check-pins.js +65 -0
  189. package/dist/scripts/check-pins.js.map +1 -0
  190. package/dist/scripts/check-security.d.ts +3 -0
  191. package/dist/scripts/check-security.d.ts.map +1 -0
  192. package/dist/scripts/check-security.js +47 -0
  193. package/dist/scripts/check-security.js.map +1 -0
  194. package/dist/scripts/check-skills-lock.d.ts +7 -0
  195. package/dist/scripts/check-skills-lock.d.ts.map +1 -0
  196. package/dist/scripts/check-skills-lock.js +36 -0
  197. package/dist/scripts/check-skills-lock.js.map +1 -0
  198. package/dist/scripts/check-skills-sync.d.ts +7 -0
  199. package/dist/scripts/check-skills-sync.d.ts.map +1 -0
  200. package/dist/scripts/check-skills-sync.js +146 -0
  201. package/dist/scripts/check-skills-sync.js.map +1 -0
  202. package/dist/scripts/check-yaml.d.ts +3 -0
  203. package/dist/scripts/check-yaml.d.ts.map +1 -0
  204. package/dist/scripts/check-yaml.js +41 -0
  205. package/dist/scripts/check-yaml.js.map +1 -0
  206. package/dist/scripts/publish-npm.d.ts +3 -0
  207. package/dist/scripts/publish-npm.d.ts.map +1 -0
  208. package/dist/scripts/publish-npm.js +67 -0
  209. package/dist/scripts/publish-npm.js.map +1 -0
  210. package/dist/scripts/release-check.d.ts +3 -0
  211. package/dist/scripts/release-check.d.ts.map +1 -0
  212. package/dist/scripts/release-check.js +97 -0
  213. package/dist/scripts/release-check.js.map +1 -0
  214. package/dist/scripts/support.d.ts +41 -0
  215. package/dist/scripts/support.d.ts.map +1 -0
  216. package/dist/scripts/support.js +78 -0
  217. package/dist/scripts/support.js.map +1 -0
  218. package/dist/targets/claude.d.ts +4 -0
  219. package/dist/targets/claude.d.ts.map +1 -0
  220. package/dist/targets/claude.js +42 -0
  221. package/dist/targets/claude.js.map +1 -0
  222. package/dist/targets/cline.d.ts +4 -0
  223. package/dist/targets/cline.d.ts.map +1 -0
  224. package/dist/targets/cline.js +39 -0
  225. package/dist/targets/cline.js.map +1 -0
  226. package/dist/targets/cursor.d.ts +4 -0
  227. package/dist/targets/cursor.d.ts.map +1 -0
  228. package/dist/targets/cursor.js +40 -0
  229. package/dist/targets/cursor.js.map +1 -0
  230. package/dist/targets/index.d.ts +4 -0
  231. package/dist/targets/index.d.ts.map +1 -0
  232. package/dist/targets/index.js +11 -0
  233. package/dist/targets/index.js.map +1 -0
  234. package/dist/targets/opencode.d.ts +4 -0
  235. package/dist/targets/opencode.d.ts.map +1 -0
  236. package/dist/targets/opencode.js +48 -0
  237. package/dist/targets/opencode.js.map +1 -0
  238. package/dist/targets/windsurf.d.ts +4 -0
  239. package/dist/targets/windsurf.d.ts.map +1 -0
  240. package/dist/targets/windsurf.js +41 -0
  241. package/dist/targets/windsurf.js.map +1 -0
  242. package/dist/types/common.d.ts +193 -0
  243. package/dist/types/common.d.ts.map +1 -0
  244. package/dist/types/common.js +6 -0
  245. package/dist/types/common.js.map +1 -0
  246. package/dist/types/design.d.ts +185 -0
  247. package/dist/types/design.d.ts.map +1 -0
  248. package/dist/types/design.js +3 -0
  249. package/dist/types/design.js.map +1 -0
  250. package/dist/types/guards.d.ts +13 -0
  251. package/dist/types/guards.d.ts.map +1 -0
  252. package/dist/types/guards.js +64 -0
  253. package/dist/types/guards.js.map +1 -0
  254. package/dist/types/handoff.d.ts +29 -0
  255. package/dist/types/handoff.d.ts.map +1 -0
  256. package/dist/types/handoff.js +3 -0
  257. package/dist/types/handoff.js.map +1 -0
  258. package/dist/types/index.d.ts +7 -0
  259. package/dist/types/index.d.ts.map +1 -0
  260. package/dist/types/index.js +11 -0
  261. package/dist/types/index.js.map +1 -0
  262. package/dist/types/orchestrator.d.ts +414 -0
  263. package/dist/types/orchestrator.d.ts.map +1 -0
  264. package/dist/types/orchestrator.js +4 -0
  265. package/dist/types/orchestrator.js.map +1 -0
  266. package/dist/types/reconcile.d.ts +160 -0
  267. package/dist/types/reconcile.d.ts.map +1 -0
  268. package/dist/types/reconcile.js +3 -0
  269. package/dist/types/reconcile.js.map +1 -0
  270. package/docs/RECONCILE.md +505 -0
  271. package/docs/design/_schema.md +506 -0
  272. package/junamis-skills.yml +328 -0
  273. package/library/EXTERNAL.md +35 -0
  274. package/library/HANDOFF.md +93 -0
  275. package/library/RESUME.md +429 -0
  276. package/library/SAFETY.md +83 -0
  277. package/library/agents/context-keeper.md +41 -0
  278. package/library/agents/frontend.md +43 -0
  279. package/library/agents/maintainer.md +44 -0
  280. package/library/agents/nestjs.md +40 -0
  281. package/library/agents/nextjs.md +40 -0
  282. package/library/agents/operator.md +42 -0
  283. package/library/agents/orchestrator.md +313 -0
  284. package/library/agents/researcher.md +40 -0
  285. package/library/agents/reviewer.md +40 -0
  286. package/library/skills/db-migrate/SKILL.md +50 -0
  287. package/library/skills/decision-record/SKILL.md +74 -0
  288. package/library/skills/dependency-upgrade/SKILL.md +57 -0
  289. package/library/skills/deploy-verify/SKILL.md +51 -0
  290. package/library/skills/document/SKILL.md +51 -0
  291. package/library/skills/env-doctor/SKILL.md +65 -0
  292. package/library/skills/frontend/SKILL.md +63 -0
  293. package/library/skills/handoff/SKILL.md +79 -0
  294. package/library/skills/incident-response/SKILL.md +69 -0
  295. package/library/skills/nestjs/SKILL.md +49 -0
  296. package/library/skills/nextjs/SKILL.md +48 -0
  297. package/library/skills/perf-budget/SKILL.md +62 -0
  298. package/library/skills/refactor-safely/SKILL.md +48 -0
  299. package/library/skills/release-prep/SKILL.md +75 -0
  300. package/library/skills/research/SKILL.md +66 -0
  301. package/library/skills/rollback/SKILL.md +49 -0
  302. package/library/skills/route/SKILL.md +107 -0
  303. package/library/skills/route-external/SKILL.md +67 -0
  304. package/library/skills/security-audit/SKILL.md +64 -0
  305. package/library/skills/skill-author/SKILL.md +49 -0
  306. package/opencode.json +5906 -0
  307. package/package.json +88 -4
  308. package/scripts/design-registry.mjs +7 -0
  309. package/scripts/orchestrator-state.mjs +7 -0
  310. package/scripts/reconcile.mjs +7 -0
  311. package/skills-lock.json +197 -0
@@ -0,0 +1,723 @@
1
+ // RECONCILE: detectors, dedupe, resolution, dependency closure, scoring,
2
+ // overrides, escalation, and deterministic work-queue emission.
3
+ //
4
+ // This module never writes the design registry or plan.json and never invokes
5
+ // a model or a skill. It reads state, journal, plan, design surfaces, and the
6
+ // detector manifest, then writes work-queue.json, reconcile-report.md, and the
7
+ // reconcile journal events.
8
+ import { join } from "node:path";
9
+ import { atomicWriteFile, exists, readJsonFile } from "../orchestrator/fsx.js";
10
+ import { computeFingerprint } from "../orchestrator/drift.js";
11
+ import { canonicalJson, sha256Hex } from "../orchestrator/hash.js";
12
+ import { JournalWriter, readJournal } from "../orchestrator/journal.js";
13
+ import { renderDrift } from "../orchestrator/report.js";
14
+ import { loadRun, refreshLoaded } from "../orchestrator/store.js";
15
+ import { allTasksDone, writeState } from "../orchestrator/state.js";
16
+ import { loadSurfaces } from "../design/schema.js";
17
+ import { DETECTOR_RUNNERS } from "./detectors.js";
18
+ import { loadDetectorManifest } from "./manifest.js";
19
+ import { compareCandidates, isKnownReason, reasonWeight, score } from "./score.js";
20
+ import { isOneOf, isRecord } from "../types/guards.js";
21
+ const CAPABILITY_RE = /^[a-z0-9][a-z0-9-]*$/;
22
+ const PRIORITIES = ["p0", "p1", "p2", "p3"];
23
+ function cell(value) {
24
+ const text = value === null || value === undefined ? "" : String(value);
25
+ return text.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
26
+ }
27
+ function short(value) {
28
+ return typeof value === "string" ? value : "not present";
29
+ }
30
+ function candidateId(target, reason) {
31
+ return `cand-${sha256Hex(`${target.kind}:${target.id}:${reason}`).slice(0, 16)}`;
32
+ }
33
+ function isReconcileEvent(event) {
34
+ return event?.type === "reconcile_pass" || event?.reconcile === true;
35
+ }
36
+ function lastMeaningfulEvent(events) {
37
+ for (let index = events.length - 1; index >= 0; index--) {
38
+ const event = events[index];
39
+ if (!isReconcileEvent(event))
40
+ return event ?? null;
41
+ }
42
+ return null;
43
+ }
44
+ async function resolveSkill({ capability, libraryRoot, manifestPath, }) {
45
+ if (!CAPABILITY_RE.test(capability))
46
+ return { resolved_skill: null, resolution_source: "needs_review" };
47
+ if (libraryRoot && (await exists(join(libraryRoot, "skills", capability, "SKILL.md")))) {
48
+ return { resolved_skill: `library/${capability}`, resolution_source: "internal_override" };
49
+ }
50
+ if (manifestPath) {
51
+ const parsed = await readJsonFile(manifestPath);
52
+ if (parsed.exists && !parsed.error && isRecord(parsed.value) && isRecord(parsed.value["skills"])) {
53
+ const skills = parsed.value["skills"];
54
+ if (skills[capability]) {
55
+ return { resolved_skill: `external/${capability}`, resolution_source: "manifest" };
56
+ }
57
+ }
58
+ }
59
+ return { resolved_skill: null, resolution_source: "needs_review" };
60
+ }
61
+ function mergeProvenance(existing, incoming) {
62
+ const seen = new Set(existing.map((entry) => `${entry.detector}:${entry.at_seq}`));
63
+ for (const entry of incoming) {
64
+ const key = `${entry.detector}:${entry.at_seq}`;
65
+ if (!seen.has(key)) {
66
+ existing.push(entry);
67
+ seen.add(key);
68
+ }
69
+ }
70
+ }
71
+ function groupCandidates(rawCandidates) {
72
+ const groups = new Map();
73
+ for (const raw of rawCandidates) {
74
+ const key = `${raw.target.kind}\0${raw.target.id}`;
75
+ const existing = groups.get(key);
76
+ if (!existing) {
77
+ groups.set(key, {
78
+ primary: raw,
79
+ rationales: [raw.rationale],
80
+ provenance: [...raw.provenance],
81
+ nonDispatchable: raw.non_dispatchable === true,
82
+ });
83
+ continue;
84
+ }
85
+ mergeProvenance(existing.provenance, raw.provenance);
86
+ if (raw.rationale && !existing.rationales.includes(raw.rationale))
87
+ existing.rationales.push(raw.rationale);
88
+ existing.nonDispatchable = existing.nonDispatchable || raw.non_dispatchable === true;
89
+ if (reasonWeight(raw.reason) < reasonWeight(existing.primary.reason))
90
+ existing.primary = raw;
91
+ }
92
+ return [...groups.values()];
93
+ }
94
+ function blockersFor(candidate, { plan, tasks, surfaces }) {
95
+ const blockers = [];
96
+ if (candidate.target.kind === "task") {
97
+ const planTask = (plan?.tasks ?? []).find((task) => task.task_id === candidate.target.id);
98
+ const byId = new Map((tasks ?? []).map((task) => [task.task_id, task]));
99
+ for (const dep of planTask?.depends_on ?? []) {
100
+ if (byId.get(dep)?.status !== "done")
101
+ blockers.push(dep);
102
+ }
103
+ // A surface awaiting operator review is a design-level gate on plan work.
104
+ for (const surface of surfaces.values()) {
105
+ if (surface.frontmatter?.status === "needs_review")
106
+ blockers.push(surface.surface_id);
107
+ }
108
+ }
109
+ if (candidate.target.kind === "surface") {
110
+ const surface = surfaces.get(candidate.target.id);
111
+ for (const dep of surface?.frontmatter?.depends_on ?? []) {
112
+ const dependency = surfaces.get(dep);
113
+ if (dependency && dependency.frontmatter?.status !== "active")
114
+ blockers.push(dep);
115
+ }
116
+ }
117
+ return [...new Set(blockers)];
118
+ }
119
+ async function buildCandidate(group, { plan, tasks, surfaces, libraryRoot, manifestPath, shadowConflict, }) {
120
+ const primary = group.primary;
121
+ let capability = primary.capability;
122
+ let reason = primary.reason;
123
+ let severity = primary.severity;
124
+ let resolved = await resolveSkill({ capability, libraryRoot, manifestPath });
125
+ let nonDispatchable = group.nonDispatchable || reason === "needs_review" || reason === "shadow_conflict";
126
+ if (!nonDispatchable && resolved.resolution_source === "needs_review")
127
+ nonDispatchable = true;
128
+ if (!nonDispatchable && shadowConflict && resolved.resolution_source === "internal_override")
129
+ nonDispatchable = true;
130
+ if (nonDispatchable) {
131
+ if (reason !== "needs_review")
132
+ reason = "shadow_conflict";
133
+ capability = "needs_review";
134
+ severity = "critical";
135
+ resolved = { resolved_skill: "needs_review", resolution_source: "needs_review" };
136
+ }
137
+ const blockers = nonDispatchable ? [] : blockersFor(primary, { plan, tasks, surfaces });
138
+ const planPosition = reason === "plan_pending" && Number.isInteger(primary.plan_position)
139
+ ? primary.plan_position
140
+ : null;
141
+ const { priority } = score({ reason, severity, planPosition });
142
+ return {
143
+ candidate_id: candidateId(primary.target, reason),
144
+ capability,
145
+ target: primary.target,
146
+ reason,
147
+ priority,
148
+ severity,
149
+ effort: "unknown",
150
+ ready: nonDispatchable ? false : blockers.length === 0,
151
+ blocked_by: blockers,
152
+ resolved_skill: resolved.resolved_skill,
153
+ resolution_source: resolved.resolution_source,
154
+ provenance: group.provenance,
155
+ rationale: [
156
+ ...group.rationales,
157
+ ...(shadowConflict ? ["shadow conflict: library overrides changed"] : []),
158
+ ...(nonDispatchable && resolved.resolution_source === "needs_review" && !group.nonDispatchable
159
+ ? ["capability has no dispatchable skill"]
160
+ : []),
161
+ ].filter(Boolean).join(" · "),
162
+ plan_position: planPosition,
163
+ ...(reason === "shadow_conflict" ? { shadow_conflict: true } : {}),
164
+ };
165
+ }
166
+ function summaryFor(queue, { stalled = false, blockingSet = [] } = {}) {
167
+ const byPriority = { p0: 0, p1: 0, p2: 0, p3: 0 };
168
+ let ready = 0;
169
+ let blocked = 0;
170
+ let needsReview = 0;
171
+ for (const candidate of queue) {
172
+ byPriority[candidate.priority] = (byPriority[candidate.priority] ?? 0) + 1;
173
+ if (candidate.ready)
174
+ ready += 1;
175
+ else
176
+ blocked += 1;
177
+ if (candidate.resolution_source === "needs_review")
178
+ needsReview += 1;
179
+ }
180
+ return {
181
+ total: queue.length,
182
+ ready,
183
+ blocked,
184
+ needs_review: needsReview,
185
+ by_priority: byPriority,
186
+ ...(stalled ? { stalled: true, blocking_set: blockingSet } : {}),
187
+ };
188
+ }
189
+ function blockedCandidate({ status, drift, seq, ts }) {
190
+ const target = { kind: "repo", id: "drift" };
191
+ return {
192
+ candidate_id: candidateId(target, "needs_review"),
193
+ capability: "needs_review",
194
+ target,
195
+ reason: "needs_review",
196
+ priority: "p0",
197
+ severity: "critical",
198
+ effort: "unknown",
199
+ ready: false,
200
+ blocked_by: [],
201
+ resolved_skill: "needs_review",
202
+ resolution_source: "needs_review",
203
+ provenance: [{ detector: "drift_guard", at_seq: seq ?? 0, at_ts: ts ?? null }],
204
+ rationale: `resume status ${String(status)}: reconcile is blocked until the drift is reviewed`,
205
+ plan_position: null,
206
+ drift: drift ?? null,
207
+ };
208
+ }
209
+ function makeQueue({ passId, generatedAt, inputFingerprint, status, queue, drift, stalled = false, blockingSet = [], }) {
210
+ return {
211
+ schema_version: 1,
212
+ pass_id: passId,
213
+ generated_at: generatedAt,
214
+ input_fingerprint: inputFingerprint,
215
+ status,
216
+ summary: summaryFor(queue, { stalled, blockingSet }),
217
+ queue,
218
+ ...(stalled ? { stalled: true } : {}),
219
+ ...(status === "blocked_drift" ? { drift: drift ?? null } : {}),
220
+ };
221
+ }
222
+ function renderReport({ queue, detectorStatus, tick }) {
223
+ const lines = [
224
+ "# Reconcile Report",
225
+ "",
226
+ `- Pass: ${queue.pass_id}`,
227
+ `- Generated: ${queue.generated_at}`,
228
+ `- Status: ${queue.status}`,
229
+ `- Tick: ${tick ? "yes" : "no"}`,
230
+ `- Input fingerprint: journal@${queue.input_fingerprint.journal_head_seq} · plan ${short(queue.input_fingerprint.plan_checksum)} · design ${short(queue.input_fingerprint.design_index_sha256)}`,
231
+ "",
232
+ "## Head",
233
+ "",
234
+ ];
235
+ const head = queue.queue[0];
236
+ if (!head) {
237
+ lines.push("- Candidate: none");
238
+ }
239
+ else {
240
+ lines.push(`- Candidate: ${head.candidate_id}`);
241
+ lines.push(`- Capability: ${head.capability} → ${head.resolved_skill ?? "unresolved"} (${head.resolution_source})`);
242
+ lines.push(`- Target: ${head.target.id}`);
243
+ lines.push(`- Reason: ${head.reason} (provenance: ${head.provenance.map((entry) => `${entry.detector}@${entry.at_seq}`).join(", ")})`);
244
+ lines.push(`- Priority: ${head.priority} · severity: ${head.severity} · ready: ${head.ready}`);
245
+ }
246
+ if (queue.stalled) {
247
+ lines.push(`- Stalled: yes (blocking: ${(queue.summary.blocking_set ?? []).join(", ") || "none"})`);
248
+ }
249
+ lines.push("", "## Queue", "", "| # | priority | ready | capability | target | reason | skill |", "|---|----------|-------|-----------|--------|--------|-------|");
250
+ if (queue.queue.length === 0) {
251
+ lines.push("| (none) | | | | | | |");
252
+ }
253
+ else {
254
+ queue.queue.forEach((candidate, index) => {
255
+ lines.push(`| ${index + 1} | ${candidate.priority} | ${candidate.ready ? "yes" : "no"} | ${cell(candidate.capability)} | ${cell(candidate.target.id)} | ${cell(candidate.reason)} | ${cell(candidate.resolved_skill ?? "none")} |`);
256
+ });
257
+ }
258
+ lines.push("", "## Blocked", "");
259
+ const blocked = queue.queue.filter((candidate) => !candidate.ready);
260
+ if (blocked.length === 0)
261
+ lines.push("- none");
262
+ for (const candidate of blocked) {
263
+ if (candidate.blocked_by.length > 0) {
264
+ lines.push(`- ${candidate.candidate_id} blocked_by: [${candidate.blocked_by.join(", ")}]`);
265
+ }
266
+ else {
267
+ lines.push(`- ${candidate.candidate_id} requires operator review (${candidate.reason})`);
268
+ }
269
+ }
270
+ lines.push("", "## Detector status", "", "| detector | enabled | fired | candidates |", "|----------|---------|-------|------------|");
271
+ if (detectorStatus.length === 0) {
272
+ lines.push("| (not run) | | | |");
273
+ }
274
+ else {
275
+ for (const detector of detectorStatus) {
276
+ lines.push(`| ${detector.id} | ${detector.enabled ? "yes" : "no"} | ${detector.fired} | ${detector.candidates} |`);
277
+ }
278
+ }
279
+ if (queue.status === "blocked_drift") {
280
+ const driftLines = renderDrift(queue.drift);
281
+ if (driftLines.length > 0)
282
+ lines.push("", ...driftLines);
283
+ }
284
+ lines.push("");
285
+ return lines.join("\n");
286
+ }
287
+ function mismatchedField(previous, current) {
288
+ const record = isRecord(previous) ? previous : {};
289
+ for (const key of ["journal_head_seq", "plan_checksum", "design_index_sha256", "env_fingerprint"]) {
290
+ if (canonicalJson(record[key] ?? null) !== canonicalJson(current[key] ?? null))
291
+ return key;
292
+ }
293
+ return "unknown";
294
+ }
295
+ function readOverrides(events) {
296
+ const applied = new Map();
297
+ const rejected = [];
298
+ const alreadyRejected = new Set(events
299
+ .filter((event) => event.type === "priority_override_rejected" && Number.isInteger(event.override_seq))
300
+ .map((event) => event.override_seq));
301
+ for (const event of events) {
302
+ if (event.type !== "priority_override")
303
+ continue;
304
+ let reason = null;
305
+ const candidateKey = event["candidate_id"];
306
+ const from = event["from"];
307
+ const to = event["to"];
308
+ const rationale = event["rationale"];
309
+ const by = event["by"];
310
+ if (typeof candidateKey !== "string" || candidateKey.length === 0)
311
+ reason = "missing candidate_id";
312
+ else if (!isOneOf(from, PRIORITIES) || !isOneOf(to, PRIORITIES))
313
+ reason = "invalid priority value";
314
+ else if (typeof rationale !== "string" || rationale.trim().length === 0)
315
+ reason = "missing rationale";
316
+ else if (typeof by !== "string" || by.trim().length === 0)
317
+ reason = "missing by";
318
+ if (reason) {
319
+ if (!alreadyRejected.has(event.seq)) {
320
+ rejected.push({
321
+ type: "priority_override_rejected",
322
+ candidate_id: candidateKey ?? null,
323
+ from: from ?? null,
324
+ to: to ?? null,
325
+ by: by ?? null,
326
+ reason,
327
+ override_seq: event.seq,
328
+ });
329
+ }
330
+ continue;
331
+ }
332
+ if (typeof candidateKey === "string" && isOneOf(to, PRIORITIES))
333
+ applied.set(candidateKey, to);
334
+ }
335
+ return { applied, rejected };
336
+ }
337
+ function stalledInfo(queueItems, surfaces) {
338
+ const planItems = queueItems.filter((candidate) => candidate.target.kind === "task" && candidate.reason === "plan_pending");
339
+ if (planItems.length === 0)
340
+ return null;
341
+ const byId = new Map(planItems.map((candidate) => [candidate.target.id, candidate]));
342
+ const blocking = new Set();
343
+ const visiting = new Set();
344
+ const blockedByDesign = (candidate) => {
345
+ if (candidate.ready)
346
+ return false;
347
+ if (candidate.blocked_by.length === 0)
348
+ return false;
349
+ let reachedDesign = false;
350
+ for (const blocker of candidate.blocked_by) {
351
+ const surface = surfaces.get(blocker);
352
+ if (surface && surface.frontmatter?.status === "needs_review") {
353
+ blocking.add(blocker);
354
+ reachedDesign = true;
355
+ continue;
356
+ }
357
+ const dependency = byId.get(blocker);
358
+ if (dependency && !visiting.has(blocker)) {
359
+ visiting.add(blocker);
360
+ const ok = blockedByDesign(dependency);
361
+ visiting.delete(blocker);
362
+ if (!ok)
363
+ return false;
364
+ reachedDesign = true;
365
+ continue;
366
+ }
367
+ return false;
368
+ }
369
+ return reachedDesign;
370
+ };
371
+ for (const candidate of planItems) {
372
+ if (!blockedByDesign(candidate))
373
+ return null;
374
+ }
375
+ return { blocking_set: [...blocking].sort((a, b) => Buffer.compare(Buffer.from(a, "utf8"), Buffer.from(b, "utf8"))) };
376
+ }
377
+ function tickDue(events, tickEvery) {
378
+ let lastPassSeq = 0;
379
+ for (const event of events) {
380
+ if (event?.type === "reconcile_pass" && Number.isInteger(event.seq) && event.seq > lastPassSeq) {
381
+ lastPassSeq = event.seq;
382
+ }
383
+ }
384
+ const stepEnds = events.filter((event) => event?.type === "step_end" && event.seq > lastPassSeq).length;
385
+ return stepEnds >= tickEvery;
386
+ }
387
+ async function appendEvent({ loaded, stateRoot, payload }) {
388
+ if (loaded) {
389
+ return loaded.journal.append({
390
+ ...payload,
391
+ run_id: loaded.run?.run_id ?? null,
392
+ });
393
+ }
394
+ const journalPath = join(stateRoot, "journal.ndjson");
395
+ const info = await readJournal(journalPath);
396
+ if (!info.exists || info.errors.length > 0)
397
+ return null;
398
+ const last = info.events.at(-1) ?? null;
399
+ const writer = new JournalWriter({
400
+ path: journalPath,
401
+ events: info.events,
402
+ prevHash: last?.hash ?? null,
403
+ lastSeq: last?.seq ?? 0,
404
+ });
405
+ return writer.append({
406
+ ...payload,
407
+ run_id: last?.run_id ?? null,
408
+ });
409
+ }
410
+ export async function runReconcile({ stateRoot, projectRoot, designRoot = null, libraryRoot = null, manifestPath = null, packageVersion = "0.0.0", trigger = "manual", status = null, drift = null, loaded: providedLoaded = null, sessionId = "s-reconcile", }) {
411
+ const current = await computeFingerprint({
412
+ libraryRoot,
413
+ manifestPath,
414
+ designRoot,
415
+ version: packageVersion,
416
+ });
417
+ let loaded = providedLoaded;
418
+ if (!loaded) {
419
+ try {
420
+ if (await exists(join(stateRoot, "journal.ndjson")))
421
+ loaded = await loadRun(stateRoot);
422
+ }
423
+ catch {
424
+ loaded = null;
425
+ }
426
+ }
427
+ const resolvedStatus = status ?? loaded?.run?.run_status ?? null;
428
+ const blocked = resolvedStatus === "BLOCKED_DRIFT" || resolvedStatus === "HALT_CORRUPT";
429
+ const events = loaded?.journal?.events ?? [];
430
+ const last = lastMeaningfulEvent(events);
431
+ const stateFile = loaded ? null : await readJsonFile(join(stateRoot, "state.json"));
432
+ const stateUpdatedAt = stateFile && isRecord(stateFile.value) && typeof stateFile.value["updated_at"] === "string"
433
+ ? stateFile.value["updated_at"]
434
+ : null;
435
+ const generatedAt = loaded?.run?.updated_at ?? stateUpdatedAt ?? last?.ts ?? "1970-01-01T00:00:00Z";
436
+ const inputFingerprint = {
437
+ journal_head_seq: last?.seq ?? 0,
438
+ plan_checksum: loaded?.plan?.checksum ?? null,
439
+ design_index_sha256: current.design_registry?.index_sha256 ?? null,
440
+ env_fingerprint: {
441
+ skills_lock_sha256: current.skills_lock_sha256,
442
+ library_overrides_sha256: current.library_overrides_sha256,
443
+ },
444
+ };
445
+ const passId = `rec-${sha256Hex(canonicalJson(inputFingerprint)).slice(0, 16)}`;
446
+ const previousQueue = await readJsonFile(join(stateRoot, "work-queue.json"));
447
+ const previousValue = isRecord(previousQueue.value) ? previousQueue.value : null;
448
+ const stale = previousQueue.exists &&
449
+ !previousQueue.error &&
450
+ previousValue &&
451
+ isRecord(previousValue["input_fingerprint"]) &&
452
+ canonicalJson(previousValue["input_fingerprint"]) !== canonicalJson(inputFingerprint)
453
+ ? {
454
+ pass_id: typeof previousValue["pass_id"] === "string" ? previousValue["pass_id"] : null,
455
+ mismatched_field: mismatchedField(previousValue["input_fingerprint"], inputFingerprint),
456
+ }
457
+ : null;
458
+ let queue;
459
+ const detectorStatus = [];
460
+ let tick = false;
461
+ const unknownReasons = new Map();
462
+ const overrides = readOverrides(events);
463
+ const driftForReport = drift ?? loaded?.run?.drift ?? null;
464
+ if (blocked) {
465
+ const item = blockedCandidate({
466
+ status: resolvedStatus,
467
+ drift: driftForReport,
468
+ seq: inputFingerprint.journal_head_seq,
469
+ ts: generatedAt,
470
+ });
471
+ queue = makeQueue({
472
+ passId,
473
+ generatedAt,
474
+ inputFingerprint,
475
+ status: "blocked_drift",
476
+ queue: [item],
477
+ drift: driftForReport,
478
+ });
479
+ }
480
+ else {
481
+ const manifest = await loadDetectorManifest(stateRoot);
482
+ tick = tickDue(events, manifest.tickEvery);
483
+ const loadedDesign = designRoot
484
+ ? await loadSurfaces(designRoot, { validate: false })
485
+ : { surfaces: [] };
486
+ const surfaces = new Map(loadedDesign.surfaces.map((surface) => [surface.surface_id, surface]));
487
+ const overridesStale = Boolean(loaded?.run?.env_fingerprint?.library_overrides_sha256 &&
488
+ current.library_overrides_sha256 &&
489
+ loaded.run.env_fingerprint.library_overrides_sha256 !== current.library_overrides_sha256);
490
+ const rawCandidates = [];
491
+ for (const detector of manifest.detectors) {
492
+ if (!detector.enabled) {
493
+ detectorStatus.push({ id: detector.id, enabled: false, fired: 0, candidates: 0 });
494
+ continue;
495
+ }
496
+ const runner = DETECTOR_RUNNERS[detector.id];
497
+ if (!runner) {
498
+ detectorStatus.push({ id: detector.id, enabled: true, fired: 0, candidates: 0, skipped: "not_implemented" });
499
+ continue;
500
+ }
501
+ try {
502
+ const produced = await runner({
503
+ plan: loaded?.plan ?? null,
504
+ tasks: loaded?.tasks ?? [],
505
+ events,
506
+ surfaces: [...surfaces.values()],
507
+ designRoot,
508
+ projectRoot,
509
+ libraryRoot,
510
+ manifestPath,
511
+ overridesStale,
512
+ lastSeq: inputFingerprint.journal_head_seq,
513
+ lastTs: last?.ts ?? generatedAt,
514
+ params: detector.params,
515
+ });
516
+ for (const raw of produced) {
517
+ if (!isKnownReason(raw.reason)) {
518
+ unknownReasons.set(`${raw.reason}:${detector.id}`, { reason: raw.reason, detector: detector.id });
519
+ }
520
+ }
521
+ rawCandidates.push(...produced);
522
+ detectorStatus.push({ id: detector.id, enabled: true, fired: produced.length > 0 ? 1 : 0, candidates: produced.length });
523
+ }
524
+ catch (error) {
525
+ detectorStatus.push({
526
+ id: detector.id,
527
+ enabled: true,
528
+ fired: 0,
529
+ candidates: 0,
530
+ error: error instanceof Error ? error.message : String(error),
531
+ });
532
+ }
533
+ }
534
+ const queueItems = [];
535
+ for (const group of groupCandidates(rawCandidates)) {
536
+ queueItems.push(await buildCandidate(group, {
537
+ plan: loaded?.plan ?? null,
538
+ tasks: loaded?.tasks ?? [],
539
+ surfaces,
540
+ libraryRoot,
541
+ manifestPath,
542
+ shadowConflict: overridesStale,
543
+ }));
544
+ }
545
+ for (const candidate of queueItems) {
546
+ const override = overrides.applied.get(candidate.candidate_id);
547
+ if (override) {
548
+ candidate.priority = override;
549
+ }
550
+ }
551
+ const stall = stalledInfo(queueItems, surfaces);
552
+ queueItems.sort(compareCandidates);
553
+ const queueStatus = queueItems.length === 0 || stall ? "no_work" : "ready";
554
+ queue = makeQueue({
555
+ passId,
556
+ generatedAt,
557
+ inputFingerprint,
558
+ status: queueStatus,
559
+ queue: queueItems,
560
+ stalled: Boolean(stall),
561
+ blockingSet: stall?.blocking_set ?? [],
562
+ });
563
+ }
564
+ const queuePath = join(stateRoot, "work-queue.json");
565
+ const reportPath = join(stateRoot, "reconcile-report.md");
566
+ await atomicWriteFile(queuePath, `${JSON.stringify(queue, null, 2)}\n`);
567
+ await atomicWriteFile(reportPath, renderReport({ queue, detectorStatus, tick }));
568
+ const emitted = [];
569
+ const passEvent = await appendEvent({
570
+ loaded,
571
+ stateRoot,
572
+ payload: {
573
+ type: "reconcile_pass",
574
+ session_id: sessionId,
575
+ trigger,
576
+ pass_id: queue.pass_id,
577
+ input_fingerprint: queue.input_fingerprint,
578
+ candidate_count: queue.summary.total,
579
+ ready_count: queue.summary.ready,
580
+ head_candidate_id: queue.queue[0]?.candidate_id ?? null,
581
+ status: queue.status,
582
+ queue_status: queue.status,
583
+ stalled: Boolean(queue.stalled),
584
+ tick,
585
+ reconcile: true,
586
+ },
587
+ });
588
+ emitted.push(passEvent);
589
+ if (stale) {
590
+ emitted.push(await appendEvent({
591
+ loaded,
592
+ stateRoot,
593
+ payload: {
594
+ type: "queue_stale",
595
+ session_id: sessionId,
596
+ pass_id: stale.pass_id,
597
+ mismatched_field: stale.mismatched_field,
598
+ reconcile: true,
599
+ },
600
+ }));
601
+ }
602
+ for (const entry of unknownReasons.values()) {
603
+ emitted.push(await appendEvent({
604
+ loaded,
605
+ stateRoot,
606
+ payload: {
607
+ type: "unknown_reason",
608
+ session_id: sessionId,
609
+ reason: entry.reason,
610
+ detector: entry.detector,
611
+ reconcile: true,
612
+ },
613
+ }));
614
+ }
615
+ for (const rejection of overrides.rejected) {
616
+ emitted.push(await appendEvent({
617
+ loaded,
618
+ stateRoot,
619
+ payload: {
620
+ ...rejection,
621
+ session_id: sessionId,
622
+ reconcile: true,
623
+ },
624
+ }));
625
+ }
626
+ const head = queue.queue[0] ?? null;
627
+ if (queue.status === "blocked_drift" && head) {
628
+ emitted.push(await appendEvent({
629
+ loaded,
630
+ stateRoot,
631
+ payload: {
632
+ type: "escalation",
633
+ session_id: sessionId,
634
+ reason: "drift",
635
+ candidate_id: head.candidate_id,
636
+ reconcile: true,
637
+ },
638
+ }));
639
+ }
640
+ else if (queue.status === "no_work") {
641
+ if (queue.stalled) {
642
+ emitted.push(await appendEvent({
643
+ loaded,
644
+ stateRoot,
645
+ payload: {
646
+ type: "run_stalled",
647
+ session_id: sessionId,
648
+ blocking_set: queue.summary.blocking_set ?? [],
649
+ reconcile: true,
650
+ },
651
+ }));
652
+ }
653
+ else if (loaded?.plan && loaded.plan.tasks.length > 0 && allTasksDone(loaded.plan, loaded.tasks) && !loaded.run?.completed_at) {
654
+ emitted.push(await appendEvent({
655
+ loaded,
656
+ stateRoot,
657
+ payload: {
658
+ type: "run_complete",
659
+ session_id: sessionId,
660
+ reconcile: true,
661
+ },
662
+ }));
663
+ }
664
+ }
665
+ else if (head) {
666
+ if (!head.ready && head.blocked_by.length > 0) {
667
+ emitted.push(await appendEvent({
668
+ loaded,
669
+ stateRoot,
670
+ payload: {
671
+ type: "queue_blocked",
672
+ session_id: sessionId,
673
+ candidate_id: head.candidate_id,
674
+ blocked_by: head.blocked_by,
675
+ reconcile: true,
676
+ },
677
+ }));
678
+ }
679
+ if (head.resolution_source === "needs_review") {
680
+ emitted.push(await appendEvent({
681
+ loaded,
682
+ stateRoot,
683
+ payload: {
684
+ type: "escalation",
685
+ session_id: sessionId,
686
+ reason: "shadow_conflict",
687
+ candidate_id: head.candidate_id,
688
+ reconcile: true,
689
+ },
690
+ }));
691
+ }
692
+ }
693
+ if (loaded) {
694
+ // Replay all new events so the state model carries reconcile, then write
695
+ // state.json only. plan.json is owned by the plan and is never rewritten.
696
+ refreshLoaded(loaded);
697
+ const run = loaded.run;
698
+ if (run) {
699
+ run.reconcile = queue.status === "ready" ? "ready" : queue.status === "no_work" ? "no_work" : "blocked_drift";
700
+ run.stalled = Boolean(queue.stalled);
701
+ run.journal_head = loaded.journal.head;
702
+ if (queue.stalled)
703
+ run.stalled = true;
704
+ await writeState(loaded.paths.root, run);
705
+ }
706
+ }
707
+ return {
708
+ ok: true,
709
+ status: queue.status,
710
+ passId: queue.pass_id,
711
+ queue,
712
+ queuePath,
713
+ reportPath,
714
+ head,
715
+ detectorStatus,
716
+ event: passEvent,
717
+ events: emitted.filter((event) => event !== null),
718
+ tick,
719
+ stale,
720
+ overridesRejected: overrides.rejected,
721
+ };
722
+ }
723
+ //# sourceMappingURL=queue.js.map