@wardby/cli 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +8 -1
- package/README.md +3 -1
- package/deploy/local/docker-compose.quickstart-coding.yml +27 -0
- package/dist/claude-coding-worker/driver.d.ts +2 -0
- package/dist/claude-coding-worker/driver.js +19 -3
- package/dist/claude-coding-worker/sdk.js +1 -1
- package/dist/cli.js +41 -22
- package/dist/coding/continuation-wording.d.ts +10 -0
- package/dist/coding/continuation-wording.js +13 -0
- package/dist/coding/docker-preflight.d.ts +12 -0
- package/dist/coding/docker-preflight.js +40 -0
- package/dist/coding/local-git.d.ts +22 -0
- package/dist/coding/local-git.js +102 -0
- package/dist/coding/local-repo-status.d.ts +7 -0
- package/dist/coding/local-repo-status.js +56 -0
- package/dist/coding/local-repo.d.ts +17 -0
- package/dist/coding/local-repo.js +65 -0
- package/dist/coding/observability.d.ts +1 -1
- package/dist/coding/observability.js +1 -0
- package/dist/coding/profile.d.ts +6 -0
- package/dist/coding/profile.js +13 -4
- package/dist/coding/protocol.d.ts +32 -7
- package/dist/coding/protocol.js +66 -4
- package/dist/coding-worker/artifact.d.ts +1 -0
- package/dist/coding-worker/errors.js +2 -0
- package/dist/config/providers.d.ts +13 -0
- package/dist/config/providers.js +21 -9
- package/dist/core/attribution.d.ts +13 -0
- package/dist/core/attribution.js +30 -0
- package/dist/core/budget-groups.d.ts +3 -1
- package/dist/core/budget-groups.js +53 -5
- package/dist/core/ci-context.d.ts +8 -0
- package/dist/core/ci-context.js +59 -0
- package/dist/core/delegation-siblings.d.ts +22 -0
- package/dist/core/delegation-siblings.js +40 -0
- package/dist/core/dispatch.d.ts +28 -4
- package/dist/core/dispatch.js +57 -15
- package/dist/core/engine-native.d.ts +16 -0
- package/dist/core/engine-native.js +49 -2
- package/dist/core/host-events.d.ts +25 -2
- package/dist/core/host-events.js +361 -19
- package/dist/core/host-status.d.ts +8 -3
- package/dist/core/host-status.js +38 -7
- package/dist/core/issue-events.d.ts +2 -6
- package/dist/core/issue-events.js +13 -19
- package/dist/core/pull-request-state-sync.d.ts +17 -0
- package/dist/core/pull-request-state-sync.js +53 -0
- package/dist/core/reconciler.d.ts +10 -1
- package/dist/core/reconciler.js +15 -2
- package/dist/core/related-pull-requests.d.ts +95 -0
- package/dist/core/related-pull-requests.js +338 -0
- package/dist/core/repo-access.d.ts +5 -1
- package/dist/core/repo-access.js +17 -1
- package/dist/core/review-fix-ledger.d.ts +20 -0
- package/dist/core/review-fix-ledger.js +41 -0
- package/dist/core/review-fix.d.ts +60 -0
- package/dist/core/review-fix.js +155 -0
- package/dist/core/review-host-tools.d.ts +13 -2
- package/dist/core/review-host-tools.js +72 -11
- package/dist/core/runner.d.ts +2 -2
- package/dist/core/runner.js +379 -184
- package/dist/core/serial-gate.d.ts +11 -0
- package/dist/core/serial-gate.js +19 -0
- package/dist/core/timing.d.ts +7 -0
- package/dist/core/timing.js +7 -0
- package/dist/env.js +6 -1
- package/dist/generated/prisma/browser.d.ts +23 -0
- package/dist/generated/prisma/client.d.ts +23 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +22 -0
- package/dist/generated/prisma/internal/class.d.ts +33 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +274 -1
- package/dist/generated/prisma/internal/prismaNamespace.js +47 -2
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +48 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +47 -2
- package/dist/generated/prisma/models/Agent.d.ts +422 -1
- package/dist/generated/prisma/models/AgentRepository.d.ts +120 -2
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +42 -1
- package/dist/generated/prisma/models/CodingRun.d.ts +205 -1
- package/dist/generated/prisma/models/DeferredReview.d.ts +1336 -0
- package/dist/generated/prisma/models/DeferredReview.js +1 -0
- package/dist/generated/prisma/models/LocalPullRequest.d.ts +1384 -0
- package/dist/generated/prisma/models/LocalPullRequest.js +1 -0
- package/dist/generated/prisma/models/LocalReview.d.ts +1315 -0
- package/dist/generated/prisma/models/LocalReview.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +223 -0
- package/dist/generated/prisma/models/RunHostCheck.d.ts +148 -1
- package/dist/generated/prisma/models.d.ts +3 -0
- package/dist/help-index.json +476 -37
- package/dist/import/neutral-schema.d.ts +2 -2
- package/dist/mcp/auth/access.d.ts +3 -1
- package/dist/mcp/auth/host-account-cli.js +2 -2
- package/dist/mcp/auth/repo-authorization.d.ts +6 -7
- package/dist/mcp/auth/repo-authorization.js +21 -0
- package/dist/mcp/index.js +4 -1
- package/dist/mcp/tools/agents.js +46 -4
- package/dist/mcp/tools/host-accounts.js +2 -2
- package/dist/mcp/tools/repositories.js +71 -12
- package/dist/mcp/tools/runs.js +23 -0
- package/dist/mcp/tools/trigger.js +153 -24
- package/dist/providers/engine/types.d.ts +11 -0
- package/dist/providers/executor/composition.js +12 -7
- package/dist/providers/executor/container.d.ts +40 -3
- package/dist/providers/executor/container.js +140 -9
- package/dist/providers/executor/types.d.ts +1 -1
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +3 -2
- package/dist/providers/jobs/fake-kubernetes-api.js +3 -0
- package/dist/providers/jobs/kubernetes-api.d.ts +3 -1
- package/dist/providers/jobs/kubernetes-client.d.ts +2 -1
- package/dist/providers/jobs/kubernetes-client.js +3 -0
- package/dist/providers/jobs/kubernetes-isolation.d.ts +7 -0
- package/dist/providers/jobs/kubernetes-isolation.js +8 -3
- package/dist/providers/jobs/kubernetes-preflight.d.ts +8 -0
- package/dist/providers/jobs/kubernetes-preflight.js +7 -0
- package/dist/providers/jobs/kubernetes-quota.d.ts +31 -0
- package/dist/providers/jobs/kubernetes-quota.js +110 -0
- package/dist/providers/jobs/kubernetes.d.ts +9 -0
- package/dist/providers/jobs/kubernetes.js +50 -0
- package/dist/providers/jobs/types.d.ts +7 -0
- package/dist/providers/review-host/ci.d.ts +7 -0
- package/dist/providers/review-host/ci.js +20 -0
- package/dist/providers/review-host/github-events.d.ts +7 -0
- package/dist/providers/review-host/github-events.js +31 -7
- package/dist/providers/review-host/github.d.ts +19 -2
- package/dist/providers/review-host/github.js +145 -2
- package/dist/providers/review-host/index.d.ts +8 -2
- package/dist/providers/review-host/index.js +14 -3
- package/dist/providers/review-host/local.d.ts +72 -0
- package/dist/providers/review-host/local.js +434 -0
- package/dist/providers/review-host/types.d.ts +65 -3
- package/dist/providers/review-host/types.js +5 -3
- package/dist/providers/vcs/git.d.ts +10 -20
- package/dist/providers/vcs/git.js +71 -127
- package/dist/providers/vcs/github-remote.d.ts +67 -0
- package/dist/providers/vcs/github-remote.js +201 -0
- package/dist/providers/vcs/github.d.ts +81 -0
- package/dist/providers/vcs/github.js +203 -6
- package/dist/providers/vcs/index.d.ts +16 -1
- package/dist/providers/vcs/index.js +43 -15
- package/dist/providers/vcs/local-remote.d.ts +44 -0
- package/dist/providers/vcs/local-remote.js +108 -0
- package/dist/providers/vcs/remote.d.ts +58 -0
- package/dist/providers/vcs/remote.js +1 -0
- package/dist/providers/vcs/routing.d.ts +33 -0
- package/dist/providers/vcs/routing.js +52 -0
- package/dist/providers/vcs/types.d.ts +12 -1
- package/dist/quickstart/coding-db.d.ts +11 -0
- package/dist/quickstart/coding-db.js +75 -0
- package/dist/quickstart/coding-doctor.d.ts +13 -0
- package/dist/quickstart/coding-doctor.js +88 -0
- package/dist/quickstart/coding-images.d.ts +15 -0
- package/dist/quickstart/coding-images.js +79 -0
- package/dist/quickstart/coding-seed.d.ts +63 -0
- package/dist/quickstart/coding-seed.js +85 -0
- package/dist/quickstart/coding.d.ts +66 -0
- package/dist/quickstart/coding.js +430 -0
- package/dist/quickstart/images.d.ts +19 -0
- package/dist/quickstart/images.js +63 -0
- package/dist/quickstart/index.d.ts +6 -0
- package/dist/quickstart/index.js +72 -40
- package/dist/quickstart/starter-services.d.ts +45 -0
- package/dist/quickstart/starter-services.js +186 -0
- package/dist/quickstart-images.json +1 -0
- package/dist/serve.js +14 -1
- package/dist/viewer/api-schema.d.ts +176 -0
- package/dist/viewer/api-schema.js +27 -2
- package/dist/viewer/graph.d.ts +7 -2
- package/dist/viewer/graph.js +25 -11
- package/dist/viewer/http.d.ts +7 -1
- package/dist/viewer/http.js +8 -3
- package/dist/viewer/infra.d.ts +2 -0
- package/dist/viewer/infra.js +23 -0
- package/dist/viewer/run-detail.d.ts +2 -1
- package/dist/viewer/run-detail.js +2 -2
- package/docs/agent-recipes.md +123 -2
- package/docs/code-review-agents.md +293 -38
- package/docs/coding-agent-setup.md +141 -2
- package/docs/coding-packages.md +21 -0
- package/docs/coding-services.md +3 -0
- package/docs/coding-worker-isolation.md +87 -24
- package/docs/getting-started-gke.md +24 -0
- package/docs/getting-started.md +82 -8
- package/docs/jira-agents.md +26 -5
- package/docs/security-deployment.md +9 -0
- package/docs/viewer-api.md +21 -2
- package/help/admin-viewer.md +11 -1
- package/help/agent-recipes.md +25 -1
- package/help/builder-agent.md +4 -0
- package/help/code-review-agents.md +82 -2
- package/help/coding-packages.md +12 -1
- package/help/coding-services.md +4 -0
- package/help/cost-attribution.md +3 -1
- package/help/creating-agents.md +3 -0
- package/help/deploy-gke.md +2 -1
- package/help/errors/coding-provider-not-configured.md +60 -0
- package/help/errors/coding-turn-limit.md +25 -0
- package/help/errors/continuation-closed.md +75 -0
- package/help/errors/local-branch-conflict.md +37 -0
- package/help/errors/local-path-invalid.md +30 -0
- package/help/errors/local-ref-invalid.md +36 -0
- package/help/errors/local-ref-not-found.md +41 -0
- package/help/errors/local-repo-not-allowed.md +46 -0
- package/help/errors/local-repo-not-found.md +39 -0
- package/help/errors/model-unavailable.md +7 -6
- package/help/errors/vcs-github-not-configured.md +34 -0
- package/help/getting-started.md +4 -0
- package/help/github.md +22 -5
- package/help/jira.md +9 -2
- package/help/local-repositories.md +182 -0
- package/help/related-pull-requests.md +89 -0
- package/help/review-fix-rounds.md +69 -0
- package/help/troubleshooting/budgets.md +11 -0
- package/help/troubleshooting/coding-workers.md +22 -0
- package/help/troubleshooting/repository-access.md +5 -0
- package/package.json +5 -3
- package/prisma/migrations/20261004100000_delegations_and_coding_turns/migration.sql +12 -0
- package/prisma/migrations/20261005000000_review_fix_rounds/migration.sql +5 -0
- package/prisma/migrations/20261006000000_parallel_delegations/migration.sql +6 -0
- package/prisma/migrations/20261007000000_ci_rereview/migration.sql +4 -0
- package/prisma/migrations/20261008000000_review_after_ci/migration.sql +33 -0
- package/prisma/migrations/20261009000001_coding_run_local_branch/migration.sql +7 -0
- package/prisma/migrations/20261009000002_local_review/migration.sql +50 -0
- package/prisma/schema.prisma +98 -1
package/dist/viewer/graph.js
CHANGED
|
@@ -39,7 +39,15 @@ function declaredServices(snapshot) {
|
|
|
39
39
|
return snapshot.filter(isRecord).map((s) => ({ name: String(s.name), version: String(s.version) }));
|
|
40
40
|
}
|
|
41
41
|
const iso = (date) => (date ? date.toISOString() : null);
|
|
42
|
-
|
|
42
|
+
/** The tracker's page for an issue (and, with a comment id, that comment); null without a known site. */
|
|
43
|
+
export function issueUrl(sites, provider, issueKey, commentId) {
|
|
44
|
+
const site = sites[provider];
|
|
45
|
+
if (!site || provider !== "jira")
|
|
46
|
+
return null;
|
|
47
|
+
const page = `${site}/browse/${encodeURIComponent(issueKey)}`;
|
|
48
|
+
return commentId ? `${page}?focusedCommentId=${encodeURIComponent(commentId)}` : page;
|
|
49
|
+
}
|
|
50
|
+
function triggerFor(row, sites) {
|
|
43
51
|
switch (row.trigger) {
|
|
44
52
|
case "scheduled":
|
|
45
53
|
return { kind: "scheduled", schedule: row.agent.schedule };
|
|
@@ -51,7 +59,12 @@ function triggerFor(row) {
|
|
|
51
59
|
return { kind: "manual" };
|
|
52
60
|
case "host_event":
|
|
53
61
|
if (row.issueStatus) {
|
|
54
|
-
return {
|
|
62
|
+
return {
|
|
63
|
+
kind: "issue",
|
|
64
|
+
provider: row.issueStatus.provider,
|
|
65
|
+
issueKey: row.issueStatus.issueKey,
|
|
66
|
+
url: issueUrl(sites, row.issueStatus.provider, row.issueStatus.issueKey),
|
|
67
|
+
};
|
|
55
68
|
}
|
|
56
69
|
if (row.hostStatus) {
|
|
57
70
|
return {
|
|
@@ -74,7 +87,7 @@ function triggerFor(row) {
|
|
|
74
87
|
return { kind: "host_event" };
|
|
75
88
|
}
|
|
76
89
|
}
|
|
77
|
-
function outcomesFor(row, pullRequests) {
|
|
90
|
+
function outcomesFor(row, pullRequests, sites) {
|
|
78
91
|
const outcomes = pullRequests.map((pr) => ({
|
|
79
92
|
kind: "pull_request",
|
|
80
93
|
provider: pr.codeProvider,
|
|
@@ -112,6 +125,7 @@ function outcomesFor(row, pullRequests) {
|
|
|
112
125
|
kind: "issue_comment",
|
|
113
126
|
provider: row.issueStatus.provider,
|
|
114
127
|
issueKey: row.issueStatus.issueKey,
|
|
128
|
+
url: issueUrl(sites, row.issueStatus.provider, row.issueStatus.issueKey, row.issueStatus.commentId),
|
|
115
129
|
at: (row.issueStatus.completedAt ?? row.issueStatus.createdAt).toISOString(),
|
|
116
130
|
});
|
|
117
131
|
}
|
|
@@ -128,7 +142,7 @@ function outcomesFor(row, pullRequests) {
|
|
|
128
142
|
return outcomes;
|
|
129
143
|
}
|
|
130
144
|
/** The one row -> GraphRun mapping (also used by run detail). `pullRequests` are the IssuePullRequest rows this run opened. */
|
|
131
|
-
export function toGraphRun(row, pullRequests) {
|
|
145
|
+
export function toGraphRun(row, pullRequests, sites = {}) {
|
|
132
146
|
return {
|
|
133
147
|
id: row.id,
|
|
134
148
|
parentRunId: row.parentRunId,
|
|
@@ -138,7 +152,7 @@ export function toGraphRun(row, pullRequests) {
|
|
|
138
152
|
model: row.codingRun?.model ?? row.agent.model,
|
|
139
153
|
codingProvider: row.codingRun?.provider ?? null,
|
|
140
154
|
status: row.status,
|
|
141
|
-
trigger: triggerFor(row),
|
|
155
|
+
trigger: triggerFor(row, sites),
|
|
142
156
|
turns: row.turns,
|
|
143
157
|
tokensIn: row.tokensIn,
|
|
144
158
|
tokensOut: row.tokensOut,
|
|
@@ -147,7 +161,7 @@ export function toGraphRun(row, pullRequests) {
|
|
|
147
161
|
startedAt: row.startedAt.toISOString(),
|
|
148
162
|
finishedAt: iso(row.finishedAt),
|
|
149
163
|
heartbeatAt: iso(row.heartbeatAt),
|
|
150
|
-
outcomes: outcomesFor(row, pullRequests),
|
|
164
|
+
outcomes: outcomesFor(row, pullRequests, sites),
|
|
151
165
|
declaredServices: declaredServices(row.codingRun?.services),
|
|
152
166
|
services: row.serviceStatuses.map((s) => ({
|
|
153
167
|
name: s.name,
|
|
@@ -160,7 +174,7 @@ export function toGraphRun(row, pullRequests) {
|
|
|
160
174
|
})),
|
|
161
175
|
};
|
|
162
176
|
}
|
|
163
|
-
async function mapRows(db, rows) {
|
|
177
|
+
async function mapRows(db, rows, sites) {
|
|
164
178
|
if (rows.length === 0)
|
|
165
179
|
return [];
|
|
166
180
|
const pullRequests = await db.issuePullRequest.findMany({
|
|
@@ -170,14 +184,14 @@ async function mapRows(db, rows) {
|
|
|
170
184
|
const byRun = new Map();
|
|
171
185
|
for (const pr of pullRequests)
|
|
172
186
|
byRun.set(pr.openedByRunId, [...(byRun.get(pr.openedByRunId) ?? []), pr]);
|
|
173
|
-
return rows.map((row) => toGraphRun(row, byRun.get(row.id) ?? []));
|
|
187
|
+
return rows.map((row) => toGraphRun(row, byRun.get(row.id) ?? [], sites));
|
|
174
188
|
}
|
|
175
189
|
/** Loads the given runs as GraphRuns (shared with run detail); unknown ids are skipped. */
|
|
176
|
-
export async function loadGraphRuns(db, runIds) {
|
|
190
|
+
export async function loadGraphRuns(db, runIds, sites = {}) {
|
|
177
191
|
if (runIds.length === 0)
|
|
178
192
|
return [];
|
|
179
193
|
const rows = await db.run.findMany({ where: { id: { in: [...runIds] } }, include: runInclude });
|
|
180
|
-
return mapRows(db, rows);
|
|
194
|
+
return mapRows(db, rows, sites);
|
|
181
195
|
}
|
|
182
196
|
export async function loadGraph(db, options) {
|
|
183
197
|
const now = options.now ?? new Date();
|
|
@@ -207,7 +221,7 @@ export async function loadGraph(db, options) {
|
|
|
207
221
|
}
|
|
208
222
|
const dayStart = periodStart("day", now);
|
|
209
223
|
const [runs, today, groups] = await Promise.all([
|
|
210
|
-
mapRows(db, rows),
|
|
224
|
+
mapRows(db, rows, options.issueSites ?? {}),
|
|
211
225
|
db.run.aggregate({ where: { startedAt: { gte: dayStart } }, _sum: { costUsd: true } }),
|
|
212
226
|
db.budgetGroup.findMany({
|
|
213
227
|
where: { dailyBudgetUsd: { not: null } },
|
package/dist/viewer/http.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Viewer HTTP routes: GET /admin/api/graph, /admin/api/runs/:id and the
|
|
2
|
+
* Viewer HTTP routes: GET /admin/api/graph, /admin/api/runs/:id, /admin/api/infra and the
|
|
3
3
|
* /admin/api/events SSE stream. Read-only and deployment-wide, so every route
|
|
4
4
|
* authenticates and then requires the privileged `admin:view` scope (admin role
|
|
5
5
|
* only) BEFORE touching the database or the event bus. McpErrors propagate to
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
9
9
|
import type { PrismaClient } from "#prisma";
|
|
10
10
|
import type { McpRequestContext } from "../mcp/context.js";
|
|
11
|
+
import type { InfraInfo } from "./api-schema.js";
|
|
12
|
+
import { type IssueSites } from "./graph.js";
|
|
11
13
|
import type { ViewerEventBus } from "./event-bus.js";
|
|
12
14
|
export declare const VIEWER_API_PREFIX = "/admin/api/";
|
|
13
15
|
export declare const SSE_HEARTBEAT_MS = 15000;
|
|
@@ -18,6 +20,10 @@ export interface ViewerApiDeps {
|
|
|
18
20
|
bus: ViewerEventBus;
|
|
19
21
|
authenticate: (authorization: string | undefined) => Promise<McpRequestContext>;
|
|
20
22
|
canonicalUri: string;
|
|
23
|
+
/** How this deployment runs coding jobs (built once at startup; GET /admin/api/infra). */
|
|
24
|
+
infra: InfraInfo;
|
|
25
|
+
/** Issue-tracker site origins by provider, for issue and comment links (empty when none is configured). */
|
|
26
|
+
issueSites?: IssueSites;
|
|
21
27
|
heartbeatMs?: number;
|
|
22
28
|
maxBufferedBytes?: number;
|
|
23
29
|
}
|
package/dist/viewer/http.js
CHANGED
|
@@ -77,7 +77,8 @@ export function createViewerApi(deps) {
|
|
|
77
77
|
const runMatch = /^\/admin\/api\/runs\/([^/]*)$/.exec(path);
|
|
78
78
|
const isGraph = path === "/admin/api/graph";
|
|
79
79
|
const isEvents = path === "/admin/api/events";
|
|
80
|
-
|
|
80
|
+
const isInfra = path === "/admin/api/infra";
|
|
81
|
+
if (!isGraph && !isEvents && !isInfra && !runMatch)
|
|
81
82
|
return false;
|
|
82
83
|
const ctx = await deps.authenticate(req.headers.authorization);
|
|
83
84
|
requireScope(ctx, deps.canonicalUri, "admin:view");
|
|
@@ -85,6 +86,10 @@ export function createViewerApi(deps) {
|
|
|
85
86
|
sendJson(res, 405, { error: "method_not_allowed" }, { allow: "GET" });
|
|
86
87
|
return true;
|
|
87
88
|
}
|
|
89
|
+
if (isInfra) {
|
|
90
|
+
sendJson(res, 200, deps.infra);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
88
93
|
if (isGraph) {
|
|
89
94
|
const limitParam = url.searchParams.get("limit");
|
|
90
95
|
let limit = DEFAULT_GRAPH_LIMIT;
|
|
@@ -104,7 +109,7 @@ export function createViewerApi(deps) {
|
|
|
104
109
|
sendJson(res, 400, { error: "invalid_since" });
|
|
105
110
|
return true;
|
|
106
111
|
}
|
|
107
|
-
sendJson(res, 200, await loadGraph(deps.db, { since, limit, now }));
|
|
112
|
+
sendJson(res, 200, await loadGraph(deps.db, { since, limit, now, issueSites: deps.issueSites }));
|
|
108
113
|
return true;
|
|
109
114
|
}
|
|
110
115
|
if (runMatch) {
|
|
@@ -115,7 +120,7 @@ export function createViewerApi(deps) {
|
|
|
115
120
|
catch {
|
|
116
121
|
/* malformed escape: fails the id check below */
|
|
117
122
|
}
|
|
118
|
-
const detail = RUN_ID.test(id) ? await loadRunDetail(deps.db, id) : null;
|
|
123
|
+
const detail = RUN_ID.test(id) ? await loadRunDetail(deps.db, id, deps.issueSites) : null;
|
|
119
124
|
if (!detail)
|
|
120
125
|
sendJson(res, 404, { error: "not_found" });
|
|
121
126
|
else
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** The read model behind GET /admin/api/infra (docs/viewer-api.md): built once at startup, no cluster reads. */
|
|
2
|
+
import { loadKubernetesJobConfig, loadProviderConfig } from "../config/providers.js";
|
|
3
|
+
import { RUN_COMPONENT_LABEL, RUN_MANAGED_BY_LABEL, RUN_SHA_CHARS, RUN_SHA_LABEL, } from "../providers/jobs/kubernetes-isolation.js";
|
|
4
|
+
export function buildInfraInfo(env = process.env) {
|
|
5
|
+
const raw = loadProviderConfig(env).jobs;
|
|
6
|
+
const launcher = raw === "docker" || raw === "kubernetes" ? raw : "local";
|
|
7
|
+
if (launcher !== "kubernetes")
|
|
8
|
+
return { launcher, kubernetes: null };
|
|
9
|
+
const k8s = loadKubernetesJobConfig(env);
|
|
10
|
+
return {
|
|
11
|
+
launcher,
|
|
12
|
+
kubernetes: {
|
|
13
|
+
namespace: k8s.namespace,
|
|
14
|
+
platform: k8s.platform,
|
|
15
|
+
runtimeClass: k8s.runtimeClassName ?? null,
|
|
16
|
+
proxyService: k8s.proxyService,
|
|
17
|
+
runLabel: RUN_SHA_LABEL,
|
|
18
|
+
runLabelHashChars: RUN_SHA_CHARS,
|
|
19
|
+
componentLabel: { ...RUN_COMPONENT_LABEL },
|
|
20
|
+
managedByLabel: { ...RUN_MANAGED_BY_LABEL },
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** The run detail read model behind GET /admin/api/runs/:id (docs/viewer-api.md). */
|
|
2
2
|
import type { PrismaClient } from "#prisma";
|
|
3
3
|
import type { RunDetail } from "./api-schema.js";
|
|
4
|
-
|
|
4
|
+
import { type IssueSites } from "./graph.js";
|
|
5
|
+
export declare function loadRunDetail(db: PrismaClient, runId: string, issueSites?: IssueSites): Promise<RunDetail | null>;
|
|
@@ -11,8 +11,8 @@ function serviceDetails(snapshot) {
|
|
|
11
11
|
envNames: isRecord(s.testEnv) ? Object.keys(s.testEnv).sort() : [],
|
|
12
12
|
}));
|
|
13
13
|
}
|
|
14
|
-
export async function loadRunDetail(db, runId) {
|
|
15
|
-
const [graphRun] = await loadGraphRuns(db, [runId]);
|
|
14
|
+
export async function loadRunDetail(db, runId, issueSites = {}) {
|
|
15
|
+
const [graphRun] = await loadGraphRuns(db, [runId], issueSites);
|
|
16
16
|
if (!graphRun)
|
|
17
17
|
return null;
|
|
18
18
|
const [row, children] = await Promise.all([
|
package/docs/agent-recipes.md
CHANGED
|
@@ -48,7 +48,7 @@ These recipes go beyond the quickstart. Check each item.
|
|
|
48
48
|
[GKE](getting-started-gke.md). Scheduled and manually triggered runs need no
|
|
49
49
|
webhook.
|
|
50
50
|
5. **App events.** Tick the events each trigger needs in the App's settings:
|
|
51
|
-
Pull request and Check
|
|
51
|
+
Pull request, Check run, and Check suite for reviews; Issue comment, Pull request review
|
|
52
52
|
comment, and Issues for mentions; and **Push** for the merge watcher. Each is
|
|
53
53
|
its own checkbox
|
|
54
54
|
([registering the App](code-review-agents.md#registering-the-github-app)).
|
|
@@ -358,6 +358,125 @@ pip use inside the same run, and `packageAllowlist` has no entry for other
|
|
|
358
358
|
ecosystems. If services are allowed, the image must be built on driver v11 or
|
|
359
359
|
later.
|
|
360
360
|
|
|
361
|
+
### Fanning out to several builders
|
|
362
|
+
|
|
363
|
+
A router delegates once per run by default: it routes a request to exactly one
|
|
364
|
+
sub-agent and never retries into a second. To have one native agent split a
|
|
365
|
+
request across several repositories, attach one builder per repository and set
|
|
366
|
+
the lead's `maxDelegationsPerRun` (1 to 20) with `create_agent` or
|
|
367
|
+
`update_agent`:
|
|
368
|
+
|
|
369
|
+
```json
|
|
370
|
+
{ "id": "<lead agent id>", "maxDelegationsPerRun": 6 }
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
- Each `delegate_to_<name>` call still goes to a different sub-agent; a second
|
|
374
|
+
call to the same one in the same run is refused with `already_dispatched`.
|
|
375
|
+
A delegation waiting for budget (see below) also holds its place against
|
|
376
|
+
`maxDelegationsPerRun`: a call beyond the limit is refused with
|
|
377
|
+
`already_dispatched` and a message naming both counts, e.g. "This run
|
|
378
|
+
reached its limit of 6 delegations: 4 made and 2 waiting for budget."
|
|
379
|
+
- By default the calls run one after another, in the order the lead makes
|
|
380
|
+
them. To run them at the same time, also set `parallelDelegations`:
|
|
381
|
+
|
|
382
|
+
```json
|
|
383
|
+
{ "id": "<lead agent id>", "maxDelegationsPerRun": 6, "parallelDelegations": true }
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Only the **consecutive** `delegate_to_*` calls of one model turn start
|
|
387
|
+
together: `[delegate_a, delegate_b]` starts both at once, but
|
|
388
|
+
`[delegate_a, jira_comment, delegate_b]` runs `delegate_a`, then the
|
|
389
|
+
`jira_comment` call, then `delegate_b` one at a time — nothing is
|
|
390
|
+
reordered, and a non-delegation call between two delegations splits them
|
|
391
|
+
into separate steps. The lead gets every call's result, in the same order
|
|
392
|
+
the calls were made, before its next turn. Tell the lead to make all of
|
|
393
|
+
its independent delegations consecutively, in one turn, with no other
|
|
394
|
+
tool call between them. A prompt that asks for delegations "in dependency
|
|
395
|
+
order", one per turn, still runs them one after another. Use
|
|
396
|
+
`parallelDelegations` only when every builder's task already carries the
|
|
397
|
+
whole cross-repository contract, so no builder needs another's output.
|
|
398
|
+
|
|
399
|
+
- With `parallelDelegations`, builders compete for coding slots: runs beyond
|
|
400
|
+
`CODING_MAX_CONCURRENT` (or beyond a Kubernetes quota set with
|
|
401
|
+
`KUBERNETES_RESOURCE_QUOTA`) wait in the queue and start as others finish.
|
|
402
|
+
A builder that waits longer than `CODING_QUEUE_TIMEOUT_SEC` fails with
|
|
403
|
+
`coding_queue_timeout`, and the lead sees that in its result.
|
|
404
|
+
- Each coding sub-agent's result tells the lead its `status`, its summary
|
|
405
|
+
(`finalText`), cost and tokens, and, when it opened or pushed to a pull
|
|
406
|
+
request, `pullRequest` (`outcome` `opened` or `updated`, `repository`,
|
|
407
|
+
`number`, `url`) taken from Wardby's own record of the run. A lead prompt can
|
|
408
|
+
ask the agent to report those links.
|
|
409
|
+
- The whole run tree shares one budget: give the lead a `budgetUsd` that
|
|
410
|
+
covers every builder it may start, plus its own planning. Builders started
|
|
411
|
+
together each reserve their own `budgetUsd` up front, so the ones admitted
|
|
412
|
+
last get what the earlier ones leave. A builder admitted after the tree's
|
|
413
|
+
budget is spent waits for a still-running sibling to finish and free its
|
|
414
|
+
reservation, then retries — up to its own normal wait bound, so the total
|
|
415
|
+
wait can run to roughly twice that bound before it gives up. With no
|
|
416
|
+
sibling still running, it is refused immediately with `run_tree_exhausted`.
|
|
417
|
+
The check behind that wait is an estimate, so a retry can still end in the
|
|
418
|
+
same refusal. Size the lead for the sum of its builders' budgets.
|
|
419
|
+
- Each builder works only in its own repository and can't see the others, so
|
|
420
|
+
the lead's task to each one must carry everything that crosses a repository
|
|
421
|
+
boundary (routes, field names and types, error codes), word for word the same.
|
|
422
|
+
- Wardby adds a **Related pull requests** section to each pull request the
|
|
423
|
+
builders open, listing the others with links, states (open, draft, merged,
|
|
424
|
+
closed) and the originating issue. With a Jira issue, the list covers every
|
|
425
|
+
pull request recorded for that issue in any run. Open ones are numbered as a
|
|
426
|
+
**Suggested merge order** — the order the lead delegated in, not a
|
|
427
|
+
guarantee; merged and closed ones are listed separately as context. A pull
|
|
428
|
+
request lists the ones opened before it as soon as it is opened; when the
|
|
429
|
+
lead run finishes, and whenever a later run pushes to one of them, every
|
|
430
|
+
open one is rewritten with the full list. Text you add inside the section is
|
|
431
|
+
replaced; the rest of the description is not touched. Only pull requests the
|
|
432
|
+
App opened and that are still open are edited.
|
|
433
|
+
- The section, and the follow-up hints below, list every pull request in the
|
|
434
|
+
set by repository name and number. A request that spans repositories of
|
|
435
|
+
different visibility can therefore show a private repository's name in a
|
|
436
|
+
public repository's pull request: if you mix public and private
|
|
437
|
+
repositories, keep that work in separate requests (separate Jira issues, or
|
|
438
|
+
separate lead agents).
|
|
439
|
+
|
|
440
|
+
#### Follow-ups across the set
|
|
441
|
+
|
|
442
|
+
A human-triggered follow-up task (an `@<app-slug>` mention, or a Jira issue
|
|
443
|
+
event — never an automatic review fix round) lists every open sibling pull
|
|
444
|
+
request in the set, each as `owner/name#n (url): … pass continuePriorRun set
|
|
445
|
+
to exactly "<run id>"`. Recommend this line in your lead agent's own prompt
|
|
446
|
+
too:
|
|
447
|
+
|
|
448
|
+
Continue the pull request you were asked about, and any listed open
|
|
449
|
+
sibling the change requires; never open a new pull request in a
|
|
450
|
+
repository that already has an open sibling for this request.
|
|
451
|
+
|
|
452
|
+
The usual delegation rails still apply on top of this: `maxDelegationsPerRun`
|
|
453
|
+
caps calls per run; a second `delegate_to_<name>` call to the same sub-agent
|
|
454
|
+
in one run is refused with `already_dispatched`; dispatch re-checks every
|
|
455
|
+
`continuePriorRun` id (refusing with `continuation_refused` when this
|
|
456
|
+
deployment can't continue the run it names — for example it belongs to a
|
|
457
|
+
different owner's agent); every push to a sibling pull request still gets its
|
|
458
|
+
own review; and fix rounds stay capped and run one at a time per pull
|
|
459
|
+
request. A continuation whose pull request has since been merged or closed
|
|
460
|
+
fails with category `continuation_closed` and pushes nothing — see
|
|
461
|
+
[Continuation's pull request is no longer open](../help/errors/continuation-closed.md).
|
|
462
|
+
|
|
463
|
+
#### Limits
|
|
464
|
+
|
|
465
|
+
- Cancelling the lead run does not stop a native sub-agent that is already
|
|
466
|
+
running; it keeps running to completion. A coding sub-agent is stopped.
|
|
467
|
+
- If Wardby restarts mid-batch, the batch's delegation calls replay and each
|
|
468
|
+
one already dispatched reports `already_dispatched`, so the lead does not
|
|
469
|
+
get those sub-agents' results. A native sub-agent that was running stops
|
|
470
|
+
with the restart and is marked `lost`, as is a coding sub-agent whose
|
|
471
|
+
replica crashed. Check the run tree with `get_run` and re-trigger the lead.
|
|
472
|
+
- The lead's own remaining (unspent) budget is not reserved against its
|
|
473
|
+
children's dispatch, so give the lead's `budgetUsd` headroom beyond the
|
|
474
|
+
plain sum of its builders' budgets, not just that sum exactly.
|
|
475
|
+
- With nested fan-out — a native sub-agent that itself has
|
|
476
|
+
`parallelDelegations` and delegates further — two branches dispatching at
|
|
477
|
+
the same time can briefly both see the same remaining run-tree budget and
|
|
478
|
+
both be admitted against it.
|
|
479
|
+
|
|
361
480
|
### Together with Recipe A
|
|
362
481
|
|
|
363
482
|
Coding runs automatically receive the repository's knowledge index and base
|
|
@@ -371,7 +490,9 @@ bundle current.
|
|
|
371
490
|
A mention from someone with write access gets a "Working on it" status comment
|
|
372
491
|
from the App. The router either asks a question or delegates, the builder
|
|
373
492
|
pushes a unique branch and opens at most one draft pull request, and the App
|
|
374
|
-
edits the status comment with the pull request link or the failure.
|
|
493
|
+
edits the status comment with the pull request link or the failure. The
|
|
494
|
+
link carries ⚠️ instead of ✅ when any of the builder's own checks failed in
|
|
495
|
+
the run; the pull request description says which. A person
|
|
375
496
|
reviews and merges; Wardby never merges for you. A later mention on that pull
|
|
376
497
|
request continues the same branch.
|
|
377
498
|
|