agent-dealer 1.2.7 → 1.2.9

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 (112) hide show
  1. package/bundle/server/dist/adapters/agent-deck-bind.js +16 -6
  2. package/bundle/server/dist/adapters/agent-deck-bind.test.js +74 -0
  3. package/bundle/server/dist/adapters/agent-health.js +14 -3
  4. package/bundle/server/dist/adapters/github.js +84 -5
  5. package/bundle/server/dist/adapters/github.test.js +83 -1
  6. package/bundle/server/dist/adapters/muse-capability.js +443 -24
  7. package/bundle/server/dist/adapters/muse-capability.test.js +469 -25
  8. package/bundle/server/dist/adapters/muse-visual-qa.js +114 -0
  9. package/bundle/server/dist/adapters/muse-visual-qa.test.js +68 -0
  10. package/bundle/server/dist/adapters/worktree-deps.js +96 -0
  11. package/bundle/server/dist/adapters/worktree-deps.test.js +144 -0
  12. package/bundle/server/dist/capacity/muse-probe.js +56 -9
  13. package/bundle/server/dist/capacity/muse-probe.test.js +188 -1
  14. package/bundle/server/dist/coordinator/admission.js +14 -1
  15. package/bundle/server/dist/coordinator/admission.test.js +197 -4
  16. package/bundle/server/dist/coordinator/auto-merge.integration.test.js +276 -0
  17. package/bundle/server/dist/coordinator/auto-merge.js +244 -4
  18. package/bundle/server/dist/coordinator/checks-wait-config.js +19 -0
  19. package/bundle/server/dist/coordinator/commands.js +284 -23
  20. package/bundle/server/dist/coordinator/commands.test.js +47 -0
  21. package/bundle/server/dist/coordinator/deck-outage.integration.test.js +4 -2
  22. package/bundle/server/dist/coordinator/developer-effect.js +224 -4
  23. package/bundle/server/dist/coordinator/developer-effect.test.js +288 -3
  24. package/bundle/server/dist/coordinator/execution-report.js +6 -0
  25. package/bundle/server/dist/coordinator/execution-report.test.js +7 -0
  26. package/bundle/server/dist/coordinator/failure-cause.js +64 -1
  27. package/bundle/server/dist/coordinator/failure-cause.test.js +92 -1
  28. package/bundle/server/dist/coordinator/failure-reason.js +7 -0
  29. package/bundle/server/dist/coordinator/failure-reason.test.js +14 -0
  30. package/bundle/server/dist/coordinator/human-resolution.js +36 -1
  31. package/bundle/server/dist/coordinator/human-resolution.test.js +33 -0
  32. package/bundle/server/dist/coordinator/merge-conflict-sync.js +647 -0
  33. package/bundle/server/dist/coordinator/merge-conflict-sync.test.js +121 -0
  34. package/bundle/server/dist/coordinator/muse-developer.integration.test.js +9 -4
  35. package/bundle/server/dist/coordinator/muse-spawn.js +122 -29
  36. package/bundle/server/dist/coordinator/muse-spawn.test.js +210 -0
  37. package/bundle/server/dist/coordinator/operator-criteria.js +168 -0
  38. package/bundle/server/dist/coordinator/operator-criteria.test.js +78 -0
  39. package/bundle/server/dist/coordinator/operator-verification.integration.test.js +347 -0
  40. package/bundle/server/dist/coordinator/playbook-feedback.js +693 -0
  41. package/bundle/server/dist/coordinator/playbook-feedback.test.js +702 -0
  42. package/bundle/server/dist/coordinator/projection.js +10 -4
  43. package/bundle/server/dist/coordinator/projection.test.js +13 -0
  44. package/bundle/server/dist/coordinator/prompts-execution-contract.test.js +107 -0
  45. package/bundle/server/dist/coordinator/prompts.js +211 -2
  46. package/bundle/server/dist/coordinator/prompts.test.js +231 -0
  47. package/bundle/server/dist/coordinator/recovery.js +57 -3
  48. package/bundle/server/dist/coordinator/recovery.test.js +67 -8
  49. package/bundle/server/dist/coordinator/reflect-trigger.js +33 -169
  50. package/bundle/server/dist/coordinator/reflect-trigger.test.js +149 -200
  51. package/bundle/server/dist/coordinator/repair-cycle.integration.test.js +1 -0
  52. package/bundle/server/dist/coordinator/reviewer-effect.js +16 -1
  53. package/bundle/server/dist/coordinator/reviewer-result.js +6 -0
  54. package/bundle/server/dist/coordinator/routing.js +45 -6
  55. package/bundle/server/dist/coordinator/routing.test.js +76 -15
  56. package/bundle/server/dist/coordinator/session-timeouts.js +30 -0
  57. package/bundle/server/dist/coordinator/usage-cap-defer.js +61 -0
  58. package/bundle/server/dist/coordinator/usage-cap.integration.test.js +1 -1
  59. package/bundle/server/dist/coordinator/worker-loop.js +18 -4
  60. package/bundle/server/dist/db/ci-attempts-migration.test.js +70 -0
  61. package/bundle/server/dist/db/index.js +18 -0
  62. package/bundle/server/dist/db/schema.sql +5 -0
  63. package/bundle/server/dist/docs-execution-analysis.test.js +1 -0
  64. package/bundle/server/dist/repository/artifacts-for-issue.js +3 -3
  65. package/bundle/server/dist/repository/human-actions.js +14 -0
  66. package/bundle/server/dist/repository/issues.js +67 -6
  67. package/bundle/server/dist/repository/work-items.js +7 -0
  68. package/bundle/server/dist/repository/worker-sessions.js +51 -2
  69. package/bundle/server/dist/routes/human-actions.js +10 -8
  70. package/bundle/server/dist/routes/issues-execution-contract.test.js +321 -0
  71. package/bundle/server/dist/routes/issues.js +19 -2
  72. package/bundle/server/dist/runners/muse-code-args.js +25 -0
  73. package/bundle/server/dist/runners/muse-code-args.test.js +30 -0
  74. package/bundle/server/dist/runners/muse-code-jsonl.js +106 -11
  75. package/bundle/server/dist/runners/muse-config-core.js +18 -1
  76. package/bundle/server/dist/runners/muse-config.test.js +37 -0
  77. package/bundle/server/dist/runners/muse-serve-session.js +5 -0
  78. package/bundle/server/dist/runners/spawn-cli.js +116 -0
  79. package/bundle/server/dist/runners/spawn-cli.test.js +124 -0
  80. package/bundle/server/package.json +2 -2
  81. package/bundle/server/static-ui/assets/index-CU6fNntg.js +64 -0
  82. package/bundle/server/static-ui/assets/{index-DyAJNyfV.css → index-K_YcYkQU.css} +1 -1
  83. package/bundle/server/static-ui/index.html +2 -2
  84. package/bundle/shared/dist/execution-analysis.d.ts +22 -22
  85. package/bundle/shared/dist/execution-contract.d.ts +117 -0
  86. package/bundle/shared/dist/execution-contract.js +307 -0
  87. package/bundle/shared/dist/execution-contract.test.d.ts +2 -0
  88. package/bundle/shared/dist/execution-contract.test.js +499 -0
  89. package/bundle/shared/dist/execution-report.d.ts +9 -9
  90. package/bundle/shared/dist/execution-report.js +2 -0
  91. package/bundle/shared/dist/failure-cause.d.ts +4 -4
  92. package/bundle/shared/dist/failure-cause.js +2 -0
  93. package/bundle/shared/dist/human-actions.d.ts +4 -4
  94. package/bundle/shared/dist/human-actions.js +17 -0
  95. package/bundle/shared/dist/index.d.ts +85 -84
  96. package/bundle/shared/dist/index.js +3 -0
  97. package/bundle/shared/dist/issues.d.ts +176 -16
  98. package/bundle/shared/dist/issues.js +22 -0
  99. package/bundle/shared/dist/issues.test.js +3 -0
  100. package/bundle/shared/dist/outbound-draft.d.ts +12 -12
  101. package/bundle/shared/dist/worker-sessions.d.ts +10 -0
  102. package/bundle/shared/dist/worker-sessions.js +8 -0
  103. package/bundle/shared/dist/worker-sessions.test.js +1 -0
  104. package/bundle/shared/dist/workflow.d.ts +4 -4
  105. package/bundle/shared/dist/workflow.js +16 -0
  106. package/bundle/shared/dist/workflow.test.js +3 -0
  107. package/bundle/shared/package.json +1 -1
  108. package/dist/action.js +4 -1
  109. package/dist/action.test.js +42 -0
  110. package/dist/index.js +1 -1
  111. package/package.json +1 -1
  112. package/bundle/server/static-ui/assets/index-yLyxRd-7.js +0 -64
@@ -1,198 +1,62 @@
1
- import { parseProfileSnapshot, parseStringList } from "@agent-dealer/shared";
2
- import { randomUUID } from "node:crypto";
3
1
  import { checkAgentDeckHealth } from "../adapters/agent-deck.js";
4
2
  import { callDeckTool } from "../adapters/reflect-authority.js";
5
3
  import { getIssue } from "../repository/issues.js";
6
- import { getAgent } from "../repository/agents.js";
7
- import { listFindingsForIssue } from "../repository/findings.js";
8
- import { listWorkflowEventsForIssue } from "../repository/workflow-events.js";
9
- import { listWorkerSessionsForIssue } from "../repository/worker-sessions.js";
10
- import { createIssueArtifact, latestIssueArtifact } from "../repository/artifacts.js";
11
- import { listArtifactsForIssueByKind } from "../repository/artifacts-for-issue.js";
4
+ import { createIssueArtifact } from "../repository/artifacts.js";
5
+ import { collectPlaybookUseReceiptsForIssue, latestReceiptErrors, reportDeckFailureSignals, } from "./playbook-feedback.js";
12
6
  import { getHumanAction, resolveHumanAction, } from "../repository/human-actions.js";
13
- const REFLECT_TOOL_TIMEOUT_MS = 15_000;
14
- /**
15
- * Reflect targets the deck the developer actually ran with (frozen snapshot). Playbook
16
- * ids are no longer on the snapshot (NOT-149) — only dead legacy agent columns still
17
- * carry them for in-flight profiles. New agents with an empty legacy list skip reflect
18
- * until a follow-up discovers playbooks dynamically from the Deck.
19
- */
20
- function resolveReflectTargets(issue) {
21
- const developerSessions = listWorkerSessionsForIssue(issue.id).filter((s) => s.role === "developer");
22
- const finalSession = developerSessions[developerSessions.length - 1] ?? null;
23
- const snapshot = finalSession ? parseProfileSnapshot(finalSession.profileSnapshotJson) : null;
24
- const developerAgent = issue.developerAgentId ? getAgent(issue.developerAgentId) : null;
25
- const deckId = snapshot?.deckId ?? developerAgent?.deckId ?? null;
26
- if (!developerAgent)
27
- return { deckId, playbookIds: [] };
28
- const fromList = parseStringList(developerAgent.playbookIdsJson);
29
- if (fromList.length)
30
- return { deckId, playbookIds: fromList };
31
- return { deckId, playbookIds: developerAgent.playbookId ? [developerAgent.playbookId] : [] };
32
- }
33
7
  const defaultDeps = {
34
8
  checkHealth: checkAgentDeckHealth,
35
9
  callTool: callDeckTool,
36
10
  };
37
- function readConclusionExcerpt(issueId) {
38
- const artifact = latestIssueArtifact(issueId, "implementation_conclusion");
39
- if (!artifact?.contentJson)
40
- return null;
41
- try {
42
- const text = JSON.parse(artifact.contentJson).text?.trim();
43
- if (!text)
44
- return null;
45
- return text.length > 800 ? `${text.slice(0, 800)}…` : text;
46
- }
47
- catch {
48
- return null;
49
- }
50
- }
51
- function reviewRoundCount(issueId) {
52
- const verdicts = listWorkflowEventsForIssue(issueId)
53
- .filter((e) => e.type === "review.submitted")
54
- .map((e) => {
55
- try {
56
- return JSON.parse(e.payloadJson ?? "{}").verdict ?? "unknown";
57
- }
58
- catch {
59
- return "unknown";
60
- }
61
- });
62
- return { rounds: verdicts.length, verdicts };
63
- }
64
- function buildRationale(issueId) {
65
- const issue = getIssue(issueId);
66
- const findings = listFindingsForIssue(issueId);
67
- const resolved = findings.filter((f) => f.status === "resolved").length;
68
- const recurring = findings.filter((f) => f.status === "recurring").length;
69
- const { rounds, verdicts } = reviewRoundCount(issueId);
70
- const conclusion = readConclusionExcerpt(issueId);
71
- const parts = [
72
- `Issue "${issue.title}" completed after ${rounds} review round(s)${verdicts.length ? ` (${verdicts.join(" → ")})` : ""}.`,
73
- `${findings.length} finding(s) tracked across rounds (${resolved} resolved, ${recurring} recurring).`,
74
- ];
75
- if (conclusion)
76
- parts.push(`Final implementation conclusion: ${conclusion}`);
77
- return parts.join(" ");
78
- }
79
- /**
80
- * Playbook ids this issue already has a `playbook_patch` artifact for, from any earlier
81
- * reflect attempt (i.e. a prior attempt that parked partway through, before a `retry`).
82
- * The retry loop skips these instead of re-proposing — otherwise a park on playbook N
83
- * after playbooks `1..N-1` already succeeded would duplicate their Notes items on retry
84
- * (PR #21 review finding #1). Reflect fires at most once per issue outside of retries, so
85
- * every artifact this finds genuinely belongs to this same reflection, never a later
86
- * unrelated one.
87
- *
88
- * NOT-96: queries `playbook_patch` rows by kind directly rather than scanning the
89
- * newest-first, all-kinds `listArtifactsForIssue` window — on an artifact-heavy issue an
90
- * older `playbook_patch` could otherwise fall outside that window and get re-proposed.
91
- */
92
- function alreadyProposedPlaybookIds(issueId) {
93
- const ids = new Set();
94
- for (const artifact of listArtifactsForIssueByKind(issueId, "playbook_patch")) {
95
- try {
96
- const playbookId = JSON.parse(artifact.contentJson ?? "{}").playbookId;
97
- if (playbookId)
98
- ids.add(playbookId);
99
- }
100
- catch {
101
- // malformed content — nothing to skip on its account
102
- }
103
- }
104
- return ids;
105
- }
106
- function recordStatus(issueId, content) {
107
- createIssueArtifact({ issueId, kind: "reflect_status", author: "system", content });
108
- }
109
11
  /**
110
- * Fires once per completed workflow instance, only on final_review:complete. Never throws —
111
- * every failure mode (no deck/playbooks configured, Agent Deck offline, a failed patch
112
- * proposal) is recorded as a `reflect_status`/`playbook_patch` artifact and reported back
113
- * as a result the caller can log, not an exception that would undo the already-committed
114
- * human-action resolution.
12
+ * Records completion evidence for a terminal issue: actual-use receipts for every
13
+ * terminal worker session, then one idempotent `signal_only` Deck report per
14
+ * failure/correction trigger. Never throws — every failure mode is recorded as a
15
+ * `reflect_status`/`playbook_use_receipt` artifact, never as an exception that would
16
+ * undo the already-committed human-action resolution.
115
17
  */
116
18
  export async function triggerIssueReflect(issueId, deps = defaultDeps) {
117
19
  const issue = getIssue(issueId);
118
20
  if (!issue)
119
21
  return "skipped";
120
- const { deckId, playbookIds } = resolveReflectTargets(issue);
121
- if (!deckId || playbookIds.length === 0)
122
- return "skipped";
123
- const healthy = await deps.checkHealth().catch(() => false);
124
- if (!healthy) {
125
- recordStatus(issueId, { status: "skipped", reason: "Agent Deck offline" });
126
- return "skipped";
127
- }
128
- const attemptId = randomUUID();
129
- const rationale = buildRationale(issueId);
130
- const alreadyProposed = alreadyProposedPlaybookIds(issueId);
131
- let anySucceeded = false;
132
- let anyFailed = false;
133
- for (const playbookId of playbookIds) {
134
- if (alreadyProposed.has(playbookId)) {
135
- // A prior attempt for this issue already proposed this playbook's patch — a retry
136
- // must not duplicate it (PR #21 review finding #1).
137
- anySucceeded = true;
138
- continue;
139
- }
140
- const playbook = await deps.callTool({
141
- deckId,
142
- toolName: "get_playbook",
143
- arguments: { playbook_id: playbookId },
144
- timeoutMs: REFLECT_TOOL_TIMEOUT_MS,
145
- });
146
- if (!playbook.ok) {
147
- recordStatus(issueId, { status: "failed", attemptId, error: playbook.reason });
148
- anyFailed = true;
149
- continue;
150
- }
151
- const proposed = await deps.callTool({
152
- deckId,
153
- toolName: "propose_playbook_patch",
154
- arguments: {
155
- kind: "update",
156
- playbook_id: playbookId,
157
- ops: [{ op: "add_item", section: "Notes", text: rationale }],
158
- rationale,
159
- },
160
- timeoutMs: REFLECT_TOOL_TIMEOUT_MS,
161
- });
162
- if (!proposed.ok) {
163
- recordStatus(issueId, { status: "failed", attemptId, error: proposed.reason });
164
- anyFailed = true;
165
- continue;
166
- }
22
+ const receipts = await collectPlaybookUseReceiptsForIssue(issueId, deps);
23
+ const signals = await reportDeckFailureSignals(issueId, deps);
24
+ // Incomplete receipt collection is a visible issue-level status even when no
25
+ // signal candidate exists — otherwise missing evidence leaves no trace. The reason
26
+ // names the actual receipt errors (Deck offline vs. malformed correlation
27
+ // response), never a blanket "offline". Collection resumes the next time issue
28
+ // reflection runs — a later instance-completing trigger re-attempts every session
29
+ // still missing a receipt — or via an explicit reflection retry. Never changes
30
+ // the issue outcome.
31
+ if (receipts.errors > 0) {
32
+ const details = latestReceiptErrors(issueId);
167
33
  createIssueArtifact({
168
34
  issueId,
169
- kind: "playbook_patch",
35
+ kind: "reflect_status",
170
36
  author: "system",
171
37
  content: {
172
- patchId: proposed.data.id,
173
- playbookId,
174
- playbookTitle: playbook.data.title,
175
- rationale,
176
- status: "proposed",
38
+ status: "failed",
39
+ reason: details.length > 0
40
+ ? `playbook-use receipt collection incomplete — retried on the next reflection trigger: ${details.join("; ")}`
41
+ : "playbook-use receipt collection incomplete — retried on the next reflection trigger",
42
+ pendingReceipts: receipts.pending,
177
43
  },
178
44
  });
179
- anySucceeded = true;
180
45
  }
181
- recordStatus(issueId, {
182
- status: anySucceeded ? (anyFailed ? "partial" : "completed") : "failed",
183
- attemptId,
184
- playbookCount: playbookIds.length,
185
- });
186
- return anySucceeded ? "triggered" : "failed";
46
+ if (receipts.collected > 0 || signals.sent.length > 0)
47
+ return "triggered";
48
+ if (receipts.errors > 0 || signals.error)
49
+ return "failed";
50
+ return "skipped";
187
51
  }
188
52
  /**
189
53
  * Resolves an open `reflection_interaction_required` action. Deliberately bypasses
190
54
  * `resolveHumanActionAndAdvance`'s workflow state machine entirely (commands.ts) — that
191
55
  * machine requires an active workflow instance to advance, but this action is raised
192
- * against an issue that is already `done` with no active instance, and resolving it must
193
- * never reopen the issue or enqueue developer/reviewer work (NOT-94). `retry` starts a
194
- * brand new correlated reflection attempt with its own new authority; `dismiss` makes no
195
- * further Deck call.
56
+ * against an issue that is already terminal with no active instance, and resolving it
57
+ * must never reopen the issue or enqueue developer/reviewer work (NOT-94). `retry`
58
+ * starts a brand new correlated evidence-collection attempt with its own new authority;
59
+ * `dismiss` makes no further Deck call.
196
60
  */
197
61
  export function resolveReflectionInteractionAction(actionId, resolvedBy, choice, deps = defaultDeps) {
198
62
  const action = getHumanAction(actionId);