@wardby/cli 0.2.0 → 0.2.1

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 (157) hide show
  1. package/README.md +142 -67
  2. package/dist/claude-coding-worker/driver.d.ts +1 -0
  3. package/dist/claude-coding-worker/driver.js +4 -1
  4. package/dist/claude-coding-worker/main.js +3 -2
  5. package/dist/coding/protocol.d.ts +28 -3
  6. package/dist/coding/protocol.js +53 -2
  7. package/dist/coding-worker/artifact.d.ts +12 -0
  8. package/dist/coding-worker/artifact.js +48 -6
  9. package/dist/coding-worker/driver.d.ts +1 -0
  10. package/dist/coding-worker/driver.js +4 -1
  11. package/dist/coding-worker/errors.d.ts +7 -0
  12. package/dist/coding-worker/errors.js +18 -0
  13. package/dist/coding-worker/main.js +3 -2
  14. package/dist/core/budget-groups.d.ts +1 -1
  15. package/dist/core/coding-queue.d.ts +1 -1
  16. package/dist/core/datastores.d.ts +1 -1
  17. package/dist/core/db.d.ts +36 -2
  18. package/dist/core/db.js +69 -2
  19. package/dist/core/dispatch.d.ts +16 -1
  20. package/dist/core/dispatch.js +33 -5
  21. package/dist/core/http-runtime.js +3 -4
  22. package/dist/core/lease.d.ts +1 -1
  23. package/dist/core/private-directory.d.ts +20 -0
  24. package/dist/core/private-directory.js +36 -0
  25. package/dist/core/reconciler.d.ts +1 -1
  26. package/dist/core/runner.d.ts +1 -1
  27. package/dist/core/scheduler.d.ts +1 -1
  28. package/dist/core/secrets.d.ts +1 -1
  29. package/dist/core/subagent-memory-tools.d.ts +1 -1
  30. package/dist/core/webhooks.d.ts +1 -1
  31. package/dist/generated/prisma/browser.d.ts +228 -0
  32. package/dist/generated/prisma/browser.js +17 -0
  33. package/dist/generated/prisma/client.d.ts +247 -0
  34. package/dist/generated/prisma/client.js +34 -0
  35. package/dist/generated/prisma/commonInputTypes.d.ts +809 -0
  36. package/dist/generated/prisma/commonInputTypes.js +10 -0
  37. package/dist/generated/prisma/enums.d.ts +53 -0
  38. package/dist/generated/prisma/enums.js +54 -0
  39. package/dist/generated/prisma/internal/class.d.ts +462 -0
  40. package/dist/generated/prisma/internal/class.js +49 -0
  41. package/dist/generated/prisma/internal/prismaNamespace.d.ts +3325 -0
  42. package/dist/generated/prisma/internal/prismaNamespace.js +455 -0
  43. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +449 -0
  44. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +426 -0
  45. package/dist/generated/prisma/models/Agent.d.ts +3267 -0
  46. package/dist/generated/prisma/models/Agent.js +1 -0
  47. package/dist/generated/prisma/models/AgentDatastore.d.ts +1210 -0
  48. package/dist/generated/prisma/models/AgentDatastore.js +1 -0
  49. package/dist/generated/prisma/models/AgentMemory.d.ts +986 -0
  50. package/dist/generated/prisma/models/AgentMemory.js +1 -0
  51. package/dist/generated/prisma/models/AgentSecret.d.ts +1212 -0
  52. package/dist/generated/prisma/models/AgentSecret.js +1 -0
  53. package/dist/generated/prisma/models/AgentSubAgent.d.ts +1217 -0
  54. package/dist/generated/prisma/models/AgentSubAgent.js +1 -0
  55. package/dist/generated/prisma/models/AgentTool.d.ts +1309 -0
  56. package/dist/generated/prisma/models/AgentTool.js +1 -0
  57. package/dist/generated/prisma/models/AuthFormChallenge.d.ts +1298 -0
  58. package/dist/generated/prisma/models/AuthFormChallenge.js +1 -0
  59. package/dist/generated/prisma/models/AuthLoginKey.d.ts +1245 -0
  60. package/dist/generated/prisma/models/AuthLoginKey.js +1 -0
  61. package/dist/generated/prisma/models/AuthRateLimit.d.ts +979 -0
  62. package/dist/generated/prisma/models/AuthRateLimit.js +1 -0
  63. package/dist/generated/prisma/models/AuthSession.d.ts +1376 -0
  64. package/dist/generated/prisma/models/AuthSession.js +1 -0
  65. package/dist/generated/prisma/models/AuthUser.d.ts +1645 -0
  66. package/dist/generated/prisma/models/AuthUser.js +1 -0
  67. package/dist/generated/prisma/models/BudgetGroup.d.ts +1548 -0
  68. package/dist/generated/prisma/models/BudgetGroup.js +1 -0
  69. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +1430 -0
  70. package/dist/generated/prisma/models/CodingAgentProfile.js +1 -0
  71. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +1749 -0
  72. package/dist/generated/prisma/models/CodingProxyRequest.js +1 -0
  73. package/dist/generated/prisma/models/CodingProxySession.d.ts +1505 -0
  74. package/dist/generated/prisma/models/CodingProxySession.js +1 -0
  75. package/dist/generated/prisma/models/CodingRun.d.ts +2402 -0
  76. package/dist/generated/prisma/models/CodingRun.js +1 -0
  77. package/dist/generated/prisma/models/Datastore.d.ts +1434 -0
  78. package/dist/generated/prisma/models/Datastore.js +1 -0
  79. package/dist/generated/prisma/models/DatastoreEntry.d.ts +1314 -0
  80. package/dist/generated/prisma/models/DatastoreEntry.js +1 -0
  81. package/dist/generated/prisma/models/OAuthAuthorizationCode.d.ts +1526 -0
  82. package/dist/generated/prisma/models/OAuthAuthorizationCode.js +1 -0
  83. package/dist/generated/prisma/models/OAuthAuthorizationRequest.d.ts +1350 -0
  84. package/dist/generated/prisma/models/OAuthAuthorizationRequest.js +1 -0
  85. package/dist/generated/prisma/models/OAuthClient.d.ts +1289 -0
  86. package/dist/generated/prisma/models/OAuthClient.js +1 -0
  87. package/dist/generated/prisma/models/OAuthFamily.d.ts +1540 -0
  88. package/dist/generated/prisma/models/OAuthFamily.js +1 -0
  89. package/dist/generated/prisma/models/OAuthGrant.d.ts +1280 -0
  90. package/dist/generated/prisma/models/OAuthGrant.js +1 -0
  91. package/dist/generated/prisma/models/Principal.d.ts +1790 -0
  92. package/dist/generated/prisma/models/Principal.js +1 -0
  93. package/dist/generated/prisma/models/Run.d.ts +2281 -0
  94. package/dist/generated/prisma/models/Run.js +1 -0
  95. package/dist/generated/prisma/models/SchedulerLease.d.ts +970 -0
  96. package/dist/generated/prisma/models/SchedulerLease.js +1 -0
  97. package/dist/generated/prisma/models/Secret.d.ts +1399 -0
  98. package/dist/generated/prisma/models/Secret.js +1 -0
  99. package/dist/generated/prisma/models/SecretElicitationOutcome.d.ts +973 -0
  100. package/dist/generated/prisma/models/SecretElicitationOutcome.js +1 -0
  101. package/dist/generated/prisma/models/Task.d.ts +1176 -0
  102. package/dist/generated/prisma/models/Task.js +1 -0
  103. package/dist/generated/prisma/models/Tool.d.ts +1478 -0
  104. package/dist/generated/prisma/models/Tool.js +1 -0
  105. package/dist/generated/prisma/models/Webhook.d.ts +1386 -0
  106. package/dist/generated/prisma/models/Webhook.js +1 -0
  107. package/dist/generated/prisma/models.d.ts +32 -0
  108. package/dist/generated/prisma/models.js +1 -0
  109. package/dist/import/create.d.ts +1 -1
  110. package/dist/import/create.js +1 -1
  111. package/dist/import/index.d.ts +1 -1
  112. package/dist/mcp/auth/ownership.d.ts +19 -19
  113. package/dist/mcp/auth/principal.d.ts +1 -1
  114. package/dist/mcp/auth/resource-server.d.ts +1 -1
  115. package/dist/mcp/auth/self-hosted/browser.js +20 -6
  116. package/dist/mcp/auth/self-hosted/cli.d.ts +1 -1
  117. package/dist/mcp/auth/self-hosted/credentials.d.ts +1 -1
  118. package/dist/mcp/auth/self-hosted/rate-limit.d.ts +1 -1
  119. package/dist/mcp/auth/self-hosted/session.d.ts +1 -1
  120. package/dist/mcp/context.d.ts +1 -1
  121. package/dist/mcp/server.d.ts +1 -1
  122. package/dist/mcp/shared/page-style.d.ts +16 -0
  123. package/dist/mcp/shared/page-style.js +129 -0
  124. package/dist/mcp/tasks/manager.d.ts +1 -1
  125. package/dist/mcp/tools/agents.js +1 -1
  126. package/dist/mcp/tools/datastore.js +1 -1
  127. package/dist/mcp/tools/scheduling.js +1 -1
  128. package/dist/mcp/tools/secret-elicitation-form.d.ts +1 -1
  129. package/dist/mcp/tools/secret-elicitation-form.js +10 -28
  130. package/dist/mcp/tools/secret-elicitation.d.ts +1 -1
  131. package/dist/mcp/tools/subagents.js +1 -1
  132. package/dist/mcp/tools/tools.js +1 -1
  133. package/dist/mcp/transport/streamable-http.d.ts +1 -1
  134. package/dist/mcp/unattended-schedules.d.ts +1 -1
  135. package/dist/mcp/webhooks/ingress.d.ts +1 -1
  136. package/dist/providers/auth/index.d.ts +1 -1
  137. package/dist/providers/auth/self-hosted.d.ts +2 -2
  138. package/dist/providers/coding-proxy/prisma-ledger.d.ts +1 -1
  139. package/dist/providers/coding-proxy/runtime.d.ts +1 -1
  140. package/dist/providers/datastore/postgres.d.ts +1 -1
  141. package/dist/providers/executor/build.d.ts +1 -1
  142. package/dist/providers/executor/composition.d.ts +1 -1
  143. package/dist/providers/executor/container.d.ts +1 -1
  144. package/dist/providers/executor/container.js +10 -3
  145. package/dist/providers/executor/dbos.d.ts +1 -1
  146. package/dist/providers/jobs/docker.d.ts +11 -0
  147. package/dist/providers/jobs/docker.js +34 -18
  148. package/dist/providers/jobs/kubernetes.js +5 -10
  149. package/dist/providers/jobs/types.d.ts +2 -0
  150. package/dist/providers/memory/postgres.d.ts +1 -1
  151. package/dist/providers/vcs/git.js +2 -1
  152. package/dist/quickstart/index.js +22 -31
  153. package/dist/quickstart/migrate.d.ts +23 -0
  154. package/dist/quickstart/migrate.js +125 -0
  155. package/package.json +20 -10
  156. package/prisma/migrate.config.mjs +20 -0
  157. package/prisma/schema.prisma +10 -2
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { readCodingInput, writeCodingOutputAtomic } from "./artifact.js";
3
3
  import { runCodingWorker } from "./driver.js";
4
- import { safeWorkerErrorCode } from "./errors.js";
4
+ import { safeOutputIssues, safeWorkerErrorCode } from "./errors.js";
5
5
  import { createCodexSdkClient } from "./sdk.js";
6
6
  const INPUT_PATH = "/run/wardby/input/input.json";
7
7
  const OUTPUT_PATH = "/run/wardby/output/result.json";
@@ -38,6 +38,7 @@ catch (error) {
38
38
  : safeCode === "worker_failed"
39
39
  ? `worker_${stage}_failed`
40
40
  : safeCode;
41
- process.stderr.write(`${JSON.stringify({ error: code })}\n`);
41
+ const issues = code === "coding_output_invalid" ? safeOutputIssues(error) : undefined;
42
+ process.stderr.write(`${JSON.stringify({ error: code, ...(issues ? { issues } : {}) })}\n`);
42
43
  process.exitCode = controller.signal.aborted ? 143 : 1;
43
44
  }
@@ -12,7 +12,7 @@
12
12
  * budget of 0, which the engine's turn-1 gate already refuses exactly
13
13
  * like any other zero/negative budget.
14
14
  */
15
- import type { Agent, BudgetGroup, PrismaClient } from "@prisma/client";
15
+ import type { Agent, BudgetGroup, PrismaClient } from "#prisma";
16
16
  export type Period = "day" | "week" | "month";
17
17
  export type BudgetGroupsDb = Pick<PrismaClient, "budgetGroup" | "run" | "agent">;
18
18
  /**
@@ -14,7 +14,7 @@
14
14
  * Called on the scheduler leader's tick and immediately in any process
15
15
  * whose coding run just finished (ContainerExecutor onSlotReleased).
16
16
  */
17
- import type { PrismaClient } from "@prisma/client";
17
+ import type { PrismaClient } from "#prisma";
18
18
  import type { Executor } from "../providers/executor/types.js";
19
19
  export declare const CODING_QUEUE_TIMEOUT_ERROR = "coding_queue_timeout";
20
20
  export type CodingQueueDb = Pick<PrismaClient, "run" | "codingRun" | "$transaction">;
@@ -4,7 +4,7 @@
4
4
  * by a per-attachment `boundName` (sharedDatastore.get(boundName, key)) —
5
5
  * same boundName convention as AgentSecret.
6
6
  */
7
- import type { PrismaClient, Datastore as DatastoreRow } from "@prisma/client";
7
+ import type { PrismaClient, Datastore as DatastoreRow } from "#prisma";
8
8
  import type { Datastore, DatastoreSetOptions, DatastoreValue } from "../providers/datastore/types.js";
9
9
  export type DatastoreMetadata = Pick<DatastoreRow, "id" | "name" | "ownerId" | "createdAt" | "updatedAt">;
10
10
  export interface SharedDatastoreAccessor {
package/dist/core/db.d.ts CHANGED
@@ -1,2 +1,36 @@
1
- import { PrismaClient } from "@prisma/client";
2
- export declare const prisma: PrismaClient<import("@prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library").DefaultArgs>;
1
+ import { PrismaClient } from "#prisma";
2
+ /**
3
+ * Connection-pool sizing for the node-postgres pool behind @prisma/adapter-pg.
4
+ *
5
+ * Prisma 6's query engine owned the pool: `connection_limit` defaulted to
6
+ * cpus * 2 + 1 and a caller waited at most `pool_timeout` = 10 s for a free
7
+ * connection (then P2024). Prisma 7 hands the pool to `pg`, whose defaults are
8
+ * max = 10 and connectionTimeoutMillis = 0 — wait for a connection *forever*,
9
+ * so a saturated pool would hang requests instead of failing them. Both values
10
+ * are therefore set explicitly, to Prisma 6's defaults:
11
+ *
12
+ * - max: availableParallelism() * 2 + 1 (Prisma 6 counted physical cores; the
13
+ * logical count is the closest portable Node equivalent).
14
+ * - connectionTimeoutMillis: 10 000 (Prisma 6's pool_timeout). A timeout now
15
+ * surfaces as a pg "timeout exceeded when trying to connect" error, not P2024.
16
+ *
17
+ * `pg` ignores Prisma's own URL parameters, so the two that tuned these same
18
+ * knobs (`connection_limit`, `pool_timeout` in seconds) are still honoured here
19
+ * for URLs that set them. idleTimeoutMillis stays at pg's 10 s default.
20
+ *
21
+ * TLS is whatever the URL asks for (`sslmode`, `sslrootcert`, ...); certificate
22
+ * validation is never disabled here.
23
+ */
24
+ export declare const DEFAULT_POOL_TIMEOUT_MS = 10000;
25
+ export declare function defaultPoolMax(): number;
26
+ export interface PoolSettings {
27
+ max: number;
28
+ connectionTimeoutMillis: number;
29
+ }
30
+ export declare function poolSettings(connectionString: string): PoolSettings;
31
+ /**
32
+ * The one way wardby builds a Prisma client. `url` defaults to DATABASE_URL
33
+ * as read at call time.
34
+ */
35
+ export declare function createPrismaClient(url?: string | undefined): PrismaClient;
36
+ export declare const prisma: PrismaClient;
package/dist/core/db.js CHANGED
@@ -1,2 +1,69 @@
1
- import { PrismaClient } from "@prisma/client";
2
- export const prisma = new PrismaClient();
1
+ import { availableParallelism } from "node:os";
2
+ import { PrismaPg } from "@prisma/adapter-pg";
3
+ import { PrismaClient } from "#prisma";
4
+ /**
5
+ * Connection-pool sizing for the node-postgres pool behind @prisma/adapter-pg.
6
+ *
7
+ * Prisma 6's query engine owned the pool: `connection_limit` defaulted to
8
+ * cpus * 2 + 1 and a caller waited at most `pool_timeout` = 10 s for a free
9
+ * connection (then P2024). Prisma 7 hands the pool to `pg`, whose defaults are
10
+ * max = 10 and connectionTimeoutMillis = 0 — wait for a connection *forever*,
11
+ * so a saturated pool would hang requests instead of failing them. Both values
12
+ * are therefore set explicitly, to Prisma 6's defaults:
13
+ *
14
+ * - max: availableParallelism() * 2 + 1 (Prisma 6 counted physical cores; the
15
+ * logical count is the closest portable Node equivalent).
16
+ * - connectionTimeoutMillis: 10 000 (Prisma 6's pool_timeout). A timeout now
17
+ * surfaces as a pg "timeout exceeded when trying to connect" error, not P2024.
18
+ *
19
+ * `pg` ignores Prisma's own URL parameters, so the two that tuned these same
20
+ * knobs (`connection_limit`, `pool_timeout` in seconds) are still honoured here
21
+ * for URLs that set them. idleTimeoutMillis stays at pg's 10 s default.
22
+ *
23
+ * TLS is whatever the URL asks for (`sslmode`, `sslrootcert`, ...); certificate
24
+ * validation is never disabled here.
25
+ */
26
+ export const DEFAULT_POOL_TIMEOUT_MS = 10_000;
27
+ export function defaultPoolMax() {
28
+ return availableParallelism() * 2 + 1;
29
+ }
30
+ export function poolSettings(connectionString) {
31
+ const settings = { max: defaultPoolMax(), connectionTimeoutMillis: DEFAULT_POOL_TIMEOUT_MS };
32
+ let params;
33
+ try {
34
+ params = new URL(connectionString).searchParams;
35
+ }
36
+ catch {
37
+ return settings;
38
+ }
39
+ const limit = Number(params.get("connection_limit"));
40
+ if (Number.isInteger(limit) && limit > 0)
41
+ settings.max = limit;
42
+ const timeout = params.get("pool_timeout");
43
+ if (timeout !== null && timeout !== "" && Number.isFinite(Number(timeout)) && Number(timeout) >= 0) {
44
+ // Prisma's pool_timeout=0 meant "no timeout"; pg's 0 means the same.
45
+ settings.connectionTimeoutMillis = Number(timeout) * 1000;
46
+ }
47
+ return settings;
48
+ }
49
+ /**
50
+ * Without a URL, pg would silently fall back to PGHOST/localhost:5432 as the
51
+ * OS user. Prisma 6 failed the first query instead ("Environment variable not
52
+ * found: DATABASE_URL"); keep that: construction succeeds, connecting fails.
53
+ */
54
+ class MissingUrlAdapter extends PrismaPg {
55
+ async connect() {
56
+ throw new Error("DATABASE_URL is not set: cannot connect to the database.");
57
+ }
58
+ }
59
+ /**
60
+ * The one way wardby builds a Prisma client. `url` defaults to DATABASE_URL
61
+ * as read at call time.
62
+ */
63
+ export function createPrismaClient(url = process.env.DATABASE_URL) {
64
+ const adapter = url
65
+ ? new PrismaPg({ connectionString: url, ...poolSettings(url) })
66
+ : new MissingUrlAdapter({ connectionString: "" });
67
+ return new PrismaClient({ adapter });
68
+ }
69
+ export const prisma = createPrismaClient();
@@ -1,4 +1,4 @@
1
- import type { Prisma, PrismaClient, Run, RunTrigger, Task } from "@prisma/client";
1
+ import type { Prisma, PrismaClient, Run, RunTrigger, Task } from "#prisma";
2
2
  import type { Executor } from "../providers/executor/types.js";
3
3
  export type DispatchDb = Pick<PrismaClient, "agent" | "run" | "codingRun" | "task" | "webhook" | "$transaction" | "$queryRaw">;
4
4
  type DispatchTx = Pick<Prisma.TransactionClient, "agent" | "run" | "codingRun" | "task" | "webhook" | "$queryRaw">;
@@ -63,6 +63,21 @@ export interface DispatchRunResult {
63
63
  run: Run;
64
64
  task?: Task;
65
65
  }
66
+ /**
67
+ * A transient transaction conflict in the Serializable persist transaction:
68
+ * a serialization failure (40001) or a deadlock (40P01). It arrives in one of
69
+ * three shapes:
70
+ * - on a model statement: P2034;
71
+ * - on a raw statement ($queryRaw, e.g. the FOR UPDATE SKIP LOCKED below, or
72
+ * anything a beforePersist callback runs): P2010, with the SQLSTATE at
73
+ * meta.driverAdapterError.cause.originalCode under the pg driver adapter
74
+ * (Prisma 7) -- Prisma 6's engine put 40001 at meta.code, still accepted;
75
+ * - at COMMIT (e.g. SSI write skew): an unwrapped DriverAdapterError, no
76
+ * code or meta, with the SQLSTATE at cause.originalCode.
77
+ *
78
+ * @internal Exported only for the real-PostgreSQL tests.
79
+ */
80
+ export declare function isSerializationConflict(err: unknown): boolean;
66
81
  /**
67
82
  * Record an executor-level failure on a run that never reached a terminal
68
83
  * state itself. Deliberately idempotent: the same failure can arrive twice —
@@ -1,12 +1,38 @@
1
- import { CODING_PROTOCOL_VERSION, CodingTaskInputSchema, normalizeGitHubRepository, publicCodingRunResult, } from "../coding/protocol.js";
1
+ import { CODING_PROTOCOL_VERSION, CodingTaskInputSchema, normalizeGitHubRepository, publicCodingRunResult, composeCodingTask, } from "../coding/protocol.js";
2
2
  import { assertCodingProviderModel } from "../coding/provider.js";
3
3
  import { logger } from "./logger.js";
4
4
  const dispatchLog = logger.child({ module: "dispatch" });
5
- function isSerializationConflict(err) {
5
+ /** SQLSTATEs worth retrying the persist transaction for: serialization failure, deadlock. */
6
+ const RETRYABLE_SQLSTATES = new Set(["40001", "40P01"]);
7
+ /**
8
+ * A transient transaction conflict in the Serializable persist transaction:
9
+ * a serialization failure (40001) or a deadlock (40P01). It arrives in one of
10
+ * three shapes:
11
+ * - on a model statement: P2034;
12
+ * - on a raw statement ($queryRaw, e.g. the FOR UPDATE SKIP LOCKED below, or
13
+ * anything a beforePersist callback runs): P2010, with the SQLSTATE at
14
+ * meta.driverAdapterError.cause.originalCode under the pg driver adapter
15
+ * (Prisma 7) -- Prisma 6's engine put 40001 at meta.code, still accepted;
16
+ * - at COMMIT (e.g. SSI write skew): an unwrapped DriverAdapterError, no
17
+ * code or meta, with the SQLSTATE at cause.originalCode.
18
+ *
19
+ * @internal Exported only for the real-PostgreSQL tests.
20
+ */
21
+ export function isSerializationConflict(err) {
6
22
  if (!err || typeof err !== "object")
7
23
  return false;
8
24
  const candidate = err;
9
- return candidate.code === "P2034" || (candidate.code === "P2010" && candidate.meta?.code === "40001");
25
+ if (candidate.code === "P2034")
26
+ return true;
27
+ if (candidate.code === "P2010") {
28
+ const sqlState = candidate.meta?.driverAdapterError?.cause?.originalCode;
29
+ return (typeof sqlState === "string" && RETRYABLE_SQLSTATES.has(sqlState)) || candidate.meta?.code === "40001";
30
+ }
31
+ if (candidate.name === "DriverAdapterError") {
32
+ const sqlState = candidate.cause?.originalCode;
33
+ return typeof sqlState === "string" && RETRYABLE_SQLSTATES.has(sqlState);
34
+ }
35
+ return false;
10
36
  }
11
37
  /**
12
38
  * Record an executor-level failure on a run that never reached a terminal
@@ -66,9 +92,11 @@ export async function dispatchRun(options) {
66
92
  if (!agent.codingProfile)
67
93
  throw new Error(`Coding agent "${agent.id}" has no coding profile.`);
68
94
  assertCodingProviderModel(agent.codingProfile.provider, agent.model);
69
- const task = options.codingTask ?? agent.codingProfile.defaultTask;
70
- if (!task)
95
+ const request = options.codingTask ?? agent.codingProfile.defaultTask;
96
+ if (!request)
71
97
  throw new Error(`Coding agent "${agent.id}" requires a task.`);
98
+ // The worker sees only the task text, so the agent's own instructions ride in it.
99
+ const task = composeCodingTask(agent.systemPrompt, request);
72
100
  const budgetUsd = options.budgetUsdOverride ?? Number(agent.budgetUsd);
73
101
  let baseRef = options.codingBaseRef ?? agent.codingProfile.baseRef;
74
102
  let headRef = `wardby/run-${run.id}`;
@@ -57,11 +57,10 @@
57
57
  * later in the process, would replace this Agent with an h2-enabled one and
58
58
  * silently restore the corruption — the price of fixing this with a dispatcher
59
59
  * instead of owning the fetch stack. Nothing in the runtime image does that
60
- * today: the only other `setGlobalDispatcher` calls in the tree are undici
61
- * copies bundled inside `@prisma/client/runtime/binary.*` (guarded by the same
62
- * `=== undefined` check, and the binary engine is not the default) and
60
+ * today: the only other `setGlobalDispatcher` call in the tree is
63
61
  * `node-fetch-native` under the `prisma` CLI, which `deploy/Dockerfile:25`
64
- * asserts is absent from the runtime image.
62
+ * asserts is absent from the runtime image. (Prisma 7's client runtime and
63
+ * `@prisma/adapter-pg` contain none; Prisma 6's `runtime/binary.*` did.)
65
64
  *
66
65
  * Restoring Node's OWN dispatcher instead is not possible, though not for the
67
66
  * reason one might guess: undici defines the legacy symbol `configurable: false`
@@ -7,7 +7,7 @@
7
7
  * expired, or already ours, and `RETURNING` tells the caller which case it
8
8
  * was — zero rows means someone else holds an unexpired lease.
9
9
  */
10
- import type { PrismaClient } from "@prisma/client";
10
+ import type { PrismaClient } from "#prisma";
11
11
  export type LeaseDb = Pick<PrismaClient, "$queryRaw">;
12
12
  /** Attempts to acquire (or renew) the lease for `scope`. Returns whether `holder` now holds it. */
13
13
  export declare function tryAcquireLease(db: LeaseDb, scope: string, holder: string, ttlMs: number): Promise<boolean>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Creates `path` as a private directory, or verifies an existing one is safe to
3
+ * trust.
4
+ *
5
+ * `mkdir(..., { mode: 0o700 })` does nothing to a directory that already
6
+ * exists. The coding state roots default to fixed names under the OS temp
7
+ * directory, so on a shared host another user could create one first -- or
8
+ * point it somewhere else with a symlink -- and then read or plant the job
9
+ * records, workspaces and artifacts wardby keeps there. This refuses:
10
+ *
11
+ * - a symlink, or anything that is not a directory;
12
+ * - a directory owned by a different user (root excepted: an operator-mounted
13
+ * volume is commonly root-owned);
14
+ * - a directory any other user can write to.
15
+ *
16
+ * Group write is allowed, since a Kubernetes `fsGroup` volume is group-writable
17
+ * by design and its group is chosen by the operator. Ownership and mode are not
18
+ * checked on platforms without POSIX uids.
19
+ */
20
+ export declare function ensurePrivateDirectory(path: string): Promise<void>;
@@ -0,0 +1,36 @@
1
+ import { lstat, mkdir } from "node:fs/promises";
2
+ /**
3
+ * Creates `path` as a private directory, or verifies an existing one is safe to
4
+ * trust.
5
+ *
6
+ * `mkdir(..., { mode: 0o700 })` does nothing to a directory that already
7
+ * exists. The coding state roots default to fixed names under the OS temp
8
+ * directory, so on a shared host another user could create one first -- or
9
+ * point it somewhere else with a symlink -- and then read or plant the job
10
+ * records, workspaces and artifacts wardby keeps there. This refuses:
11
+ *
12
+ * - a symlink, or anything that is not a directory;
13
+ * - a directory owned by a different user (root excepted: an operator-mounted
14
+ * volume is commonly root-owned);
15
+ * - a directory any other user can write to.
16
+ *
17
+ * Group write is allowed, since a Kubernetes `fsGroup` volume is group-writable
18
+ * by design and its group is chosen by the operator. Ownership and mode are not
19
+ * checked on platforms without POSIX uids.
20
+ */
21
+ export async function ensurePrivateDirectory(path) {
22
+ await mkdir(path, { recursive: true, mode: 0o700 });
23
+ const metadata = await lstat(path);
24
+ if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
25
+ throw new Error(`${path} must be a real directory, not a symlink.`);
26
+ }
27
+ const uid = process.getuid?.();
28
+ if (uid === undefined)
29
+ return;
30
+ if (metadata.uid !== uid && metadata.uid !== 0) {
31
+ throw new Error(`${path} is owned by uid ${metadata.uid}, not this process (uid ${uid}). Remove it or choose another path.`);
32
+ }
33
+ if ((metadata.mode & 0o002) !== 0) {
34
+ throw new Error(`${path} is writable by other users. Run chmod o-w on it or choose another path.`);
35
+ }
36
+ }
@@ -28,7 +28,7 @@
28
28
  * second one's WHERE simply matches zero rows — double-reconcile is a
29
29
  * no-op, not a race.
30
30
  */
31
- import type { PrismaClient } from "@prisma/client";
31
+ import type { PrismaClient } from "#prisma";
32
32
  import type { Executor } from "../providers/executor/types.js";
33
33
  export type ReconcilerDb = Pick<PrismaClient, "run">;
34
34
  /** Runs one reconciliation pass. Returns the number of runs marked `lost`. */
@@ -16,7 +16,7 @@
16
16
  * down) lives inside the engine now — there is exactly one place that
17
17
  * reasons about cost, not one here plus one in the engine.
18
18
  */
19
- import type { PrismaClient, Run, RunTrigger } from "@prisma/client";
19
+ import type { PrismaClient, Run, RunTrigger } from "#prisma";
20
20
  import type { ProviderRegistry } from "../providers/index.js";
21
21
  import { type StepRunner } from "../providers/engine/types.js";
22
22
  import type { Executor } from "../providers/executor/types.js";
@@ -6,7 +6,7 @@
6
6
  * create — never by the lease alone (the lease only prevents concurrent
7
7
  * *ticking*, not a race within a single tick against a future one).
8
8
  */
9
- import type { Agent } from "@prisma/client";
9
+ import type { Agent } from "#prisma";
10
10
  import type { Executor } from "../providers/executor/types.js";
11
11
  import { type DispatchDb } from "./dispatch.js";
12
12
  export type SchedulerDb = DispatchDb;
@@ -6,7 +6,7 @@
6
6
  * always resolve a name within one owner's (or, at get-time, one agent's)
7
7
  * scope, never globally.
8
8
  */
9
- import type { PrismaClient, Secret } from "@prisma/client";
9
+ import type { PrismaClient, Secret } from "#prisma";
10
10
  import type { SecretCipher } from "../providers/secrets/types.js";
11
11
  export type SecretMetadata = Pick<Secret, "id" | "name" | "keyId" | "ownerId" | "createdAt" | "updatedAt">;
12
12
  export interface SecretsAccessor {
@@ -1,4 +1,4 @@
1
- import type { PrismaClient } from "@prisma/client";
1
+ import type { PrismaClient } from "#prisma";
2
2
  import type { LoadedTool } from "../providers/engine/types.js";
3
3
  import type { AgentMemoryStore } from "../providers/memory/types.js";
4
4
  export declare const SUBAGENT_MEMORY_TOOL_NAMES: ReadonlySet<string>;
@@ -1,4 +1,4 @@
1
- import type { PrismaClient, Webhook } from "@prisma/client";
1
+ import type { PrismaClient, Webhook } from "#prisma";
2
2
  import type { Executor } from "../providers/executor/types.js";
3
3
  export type WebhookMetadata = Pick<Webhook, "id" | "agentId" | "status" | "ownerId" | "createdAt" | "lastFiredAt">;
4
4
  /** Creates a webhook and returns the raw secret ONCE — only its hash is ever stored. */
@@ -0,0 +1,228 @@
1
+ import * as Prisma from './internal/prismaNamespaceBrowser.js';
2
+ export { Prisma };
3
+ export * as $Enums from './enums.js';
4
+ export * from './enums.js';
5
+ /**
6
+ * Model Agent
7
+ *
8
+ */
9
+ export type Agent = Prisma.AgentModel;
10
+ /**
11
+ * Model AgentSubAgent
12
+ * Un-phased: agent-composition edge, referenced by agent name at the
13
+ * import boundary (capabilities/subagents.json) but id-based here to
14
+ * match that Tier-1 convention. Cycle-checked in the MCP tool handler at
15
+ * creation time, not enforced by the database (Postgres has no native
16
+ * "no cycles" constraint).
17
+ */
18
+ export type AgentSubAgent = Prisma.AgentSubAgentModel;
19
+ /**
20
+ * Model BudgetGroup
21
+ * Phase 7: an optional recurring spend cap across a group of agents,
22
+ * layered on top of each agent's own per-run budgetUsd (which stays
23
+ * required and unchanged). All three period caps are independently
24
+ * optional -- unset means "no cap for that period." warnThresholdRatio
25
+ * is per-group so different groups can choose their own early-warning
26
+ * point; enforcement itself never lives here -- see
27
+ * src/core/budget-groups.ts and runner.ts's executeRun, which turn a
28
+ * group's remaining period budget into a tightened *effective* per-run
29
+ * budget the existing engine budget machinery enforces unchanged.
30
+ */
31
+ export type BudgetGroup = Prisma.BudgetGroupModel;
32
+ /**
33
+ * Model Tool
34
+ * Phase 3: a WASM-sandboxed, Zod-validated tool a model can call.
35
+ */
36
+ export type Tool = Prisma.ToolModel;
37
+ /**
38
+ * Model AgentTool
39
+ * Phase 3: explicit many-to-many join between Agent and Tool.
40
+ * Phase 6: per-attachment capability scoping (OWASP LLM08 fix — Excessive
41
+ * Agency). Empty array = no access to that resource class; a tool must be
42
+ * explicitly granted secrets/datastore-prefixes/hosts at attach time. A
43
+ * literal "*" element in allowedHosts lifts the fetch allowlist entirely
44
+ * (existing SSRF protection against private/link-local addresses still
45
+ * applies) — the back-compat escape hatch for pre-existing attachments and
46
+ * deliberate full-web-access tools. See src/sandbox/tool-capabilities.ts.
47
+ */
48
+ export type AgentTool = Prisma.AgentToolModel;
49
+ /**
50
+ * Model Datastore
51
+ * Named, owned resource shared across agents via AgentDatastore (Un-phased
52
+ * roadmap item "Named / shared datastores"). Null ownerId = public/unowned,
53
+ * matching Tool's convention.
54
+ */
55
+ export type Datastore = Prisma.DatastoreModel;
56
+ /**
57
+ * Model AgentDatastore
58
+ * Attaches a Datastore to an agent, addressed at sandbox point-of-use by
59
+ * `boundName` (sharedDatastore.get(boundName, key)) — same boundName
60
+ * convention as AgentSecret. Defaults to the datastore's own name.
61
+ */
62
+ export type AgentDatastore = Prisma.AgentDatastoreModel;
63
+ /**
64
+ * Model DatastoreEntry
65
+ * Phase 3: the datastore seam's Postgres-backed default. Scoped by agentId
66
+ * (private, per-agent) or datastoreId (shared, see Datastore above) — a row
67
+ * carries exactly one, enforced by a hand-written CHECK in the migration
68
+ * (Prisma has no declarative "exactly one of two columns" constraint).
69
+ * Phase 6: optional per-entry PII encryption (see `pii`/`keyId` below).
70
+ *
71
+ * `id` is a surrogate key required by Prisma's schema validator: with
72
+ * agentId and datastoreId both optional, neither `@@unique` below has an
73
+ * all-required-fields criterion, and Prisma rejects a model with no such
74
+ * criterion (P1012, "Each model must have at least one unique criteria
75
+ * that has only required fields") — `prisma generate`/`validate` refuse to
76
+ * run at all without it. Point lookups still go through the
77
+ * agentId_key/datastoreId_key compound uniques; `id` is not otherwise used.
78
+ */
79
+ export type DatastoreEntry = Prisma.DatastoreEntryModel;
80
+ /**
81
+ * Model AgentMemory
82
+ * Un-phased: agent-controlled persistent memory (key/content per agent),
83
+ * gated by Agent.memoryEnabled. Deliberately a separate table rather than a
84
+ * Datastore convention — memory has its own access surface (built-in
85
+ * memory_get/memory_set/memory_list/memory_search tools, not user-authored
86
+ * sandbox code) and its own full-text search index, which would be an odd
87
+ * fit bolted onto Datastore's opaque-JSON-value shape. No FK to Agent,
88
+ * matching DatastoreEntry: deleting an agent leaves orphaned rows today,
89
+ * same pre-existing gap, not a new one.
90
+ *
91
+ * `contentTsv` is maintained by application code (see
92
+ * PostgresAgentMemory.set), never a Postgres GENERATED column — a generated
93
+ * column's expression has no representation in `Unsupported()`, which risks
94
+ * the migration-vs-schema drift check (CLAUDE.md) never landing clean.
95
+ */
96
+ export type AgentMemory = Prisma.AgentMemoryModel;
97
+ /**
98
+ * Model Run
99
+ *
100
+ */
101
+ export type Run = Prisma.RunModel;
102
+ /**
103
+ * Model CodingAgentProfile
104
+ * Phase 5: owner-configured coding behavior. Runtime credentials and opaque
105
+ * launcher handles never live on the reusable profile.
106
+ */
107
+ export type CodingAgentProfile = Prisma.CodingAgentProfileModel;
108
+ /**
109
+ * Model CodingRun
110
+ * Phase 5: immutable dispatch inputs plus opaque execution/result state for
111
+ * one coding run. Policy is copied from the profile before work starts.
112
+ */
113
+ export type CodingRun = Prisma.CodingRunModel;
114
+ /**
115
+ * Model CodingProxySession
116
+ * Trusted-boundary state for one coding run. Only a capability digest and an
117
+ * upstream credential reference are persisted; neither secret value enters the DB.
118
+ */
119
+ export type CodingProxySession = Prisma.CodingProxySessionModel;
120
+ /**
121
+ * Model CodingProxyRequest
122
+ * Monotonic per-upstream-call ledger. Uncertain reservations remain held so a
123
+ * crash or truncated provider stream can never create new spendable budget.
124
+ */
125
+ export type CodingProxyRequest = Prisma.CodingProxyRequestModel;
126
+ /**
127
+ * Model SchedulerLease
128
+ * Phase 2: single-row-per-scope lease so exactly one scheduler process
129
+ * ticks at a time. `holder` is a process instance id (crypto.randomUUID()).
130
+ */
131
+ export type SchedulerLease = Prisma.SchedulerLeaseModel;
132
+ /**
133
+ * Model Principal
134
+ * Phase 4: an authenticated caller. `subject` is the IdP subject claim
135
+ * (delegating mode) or the configured LOCAL_PRINCIPAL (stdio, no token).
136
+ * Created on first sight (find-or-create by subject).
137
+ */
138
+ export type Principal = Prisma.PrincipalModel;
139
+ /**
140
+ * Model Task
141
+ *
142
+ */
143
+ export type Task = Prisma.TaskModel;
144
+ /**
145
+ * Model Secret
146
+ * Phase 4: a secret value, encrypted at rest via the SecretCipher seam.
147
+ * `ciphertext` is opaque to Prisma; only the cipher's decrypt() ever
148
+ * produces plaintext, and only at point-of-use inside the sandbox.
149
+ */
150
+ export type Secret = Prisma.SecretModel;
151
+ /**
152
+ * Model AgentSecret
153
+ * Phase 4: attaches a secret to an agent, addressed at sandbox point-of-use
154
+ * by `boundName` (secrets.get(boundName)). `boundName` defaults to the
155
+ * secret's canonical name; it differs only when the agent binds the secret
156
+ * under an alias, letting two agents resolve the same logical name to
157
+ * different underlying secrets.
158
+ */
159
+ export type AgentSecret = Prisma.AgentSecretModel;
160
+ /**
161
+ * Model SecretElicitationOutcome
162
+ * Cross-instance persistence for the out-of-band secret-entry flow
163
+ * (mcp/tools/secret-elicitation.ts) — was an in-process Map, which stranded
164
+ * a browser-form submission on the wrong instance under a multi-instance
165
+ * HTTP deployment. `outcome` holds the SecretElicitationOutcome JSON;
166
+ * `expiresAt` mirrors the old TTL sweep, now a `DELETE WHERE expiresAt <=
167
+ * now()` instead of a Map scan.
168
+ */
169
+ export type SecretElicitationOutcome = Prisma.SecretElicitationOutcomeModel;
170
+ /**
171
+ * Model Webhook
172
+ * Phase 4: inbound trigger for an agent. `secretHash` is an HMAC/hash of
173
+ * the validation secret shown to the caller once at creation; the raw
174
+ * secret itself is never stored.
175
+ */
176
+ export type Webhook = Prisma.WebhookModel;
177
+ /**
178
+ * Model OAuthClient
179
+ * Phase 4 (self-hosted AS only): a registered OAuth client. Created and
180
+ * used only under AUTH_PROVIDER=self-hosted; the delegating adapter never
181
+ * writes these tables even though the migration creates them unconditionally.
182
+ */
183
+ export type OAuthClient = Prisma.OAuthClientModel;
184
+ /**
185
+ * Model OAuthGrant
186
+ * Phase 4 (self-hosted AS only): an issued authorization grant / refresh token.
187
+ */
188
+ export type OAuthGrant = Prisma.OAuthGrantModel;
189
+ /**
190
+ * Model AuthUser
191
+ *
192
+ */
193
+ export type AuthUser = Prisma.AuthUserModel;
194
+ /**
195
+ * Model AuthLoginKey
196
+ *
197
+ */
198
+ export type AuthLoginKey = Prisma.AuthLoginKeyModel;
199
+ /**
200
+ * Model AuthSession
201
+ *
202
+ */
203
+ export type AuthSession = Prisma.AuthSessionModel;
204
+ /**
205
+ * Model AuthFormChallenge
206
+ *
207
+ */
208
+ export type AuthFormChallenge = Prisma.AuthFormChallengeModel;
209
+ /**
210
+ * Model OAuthAuthorizationRequest
211
+ *
212
+ */
213
+ export type OAuthAuthorizationRequest = Prisma.OAuthAuthorizationRequestModel;
214
+ /**
215
+ * Model OAuthAuthorizationCode
216
+ *
217
+ */
218
+ export type OAuthAuthorizationCode = Prisma.OAuthAuthorizationCodeModel;
219
+ /**
220
+ * Model OAuthFamily
221
+ *
222
+ */
223
+ export type OAuthFamily = Prisma.OAuthFamilyModel;
224
+ /**
225
+ * Model AuthRateLimit
226
+ *
227
+ */
228
+ export type AuthRateLimit = Prisma.AuthRateLimitModel;
@@ -0,0 +1,17 @@
1
+ /* !!! This is code generated by Prisma. Do not edit directly. !!! */
2
+ /* eslint-disable */
3
+ // biome-ignore-all lint: generated file
4
+ // @ts-nocheck
5
+ /*
6
+ * This file should be your main import to use Prisma-related types and utilities in a browser.
7
+ * Use it to get access to models, enums, and input types.
8
+ *
9
+ * This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only.
10
+ * See `client.ts` for the standard, server-side entry point.
11
+ *
12
+ * 🟢 You can import this file directly.
13
+ */
14
+ import * as Prisma from './internal/prismaNamespaceBrowser.js';
15
+ export { Prisma };
16
+ export * as $Enums from './enums.js';
17
+ export * from './enums.js';