@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
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ export type * from './models/Agent.js';
2
+ export type * from './models/AgentSubAgent.js';
3
+ export type * from './models/BudgetGroup.js';
4
+ export type * from './models/Tool.js';
5
+ export type * from './models/AgentTool.js';
6
+ export type * from './models/Datastore.js';
7
+ export type * from './models/AgentDatastore.js';
8
+ export type * from './models/DatastoreEntry.js';
9
+ export type * from './models/AgentMemory.js';
10
+ export type * from './models/Run.js';
11
+ export type * from './models/CodingAgentProfile.js';
12
+ export type * from './models/CodingRun.js';
13
+ export type * from './models/CodingProxySession.js';
14
+ export type * from './models/CodingProxyRequest.js';
15
+ export type * from './models/SchedulerLease.js';
16
+ export type * from './models/Principal.js';
17
+ export type * from './models/Task.js';
18
+ export type * from './models/Secret.js';
19
+ export type * from './models/AgentSecret.js';
20
+ export type * from './models/SecretElicitationOutcome.js';
21
+ export type * from './models/Webhook.js';
22
+ export type * from './models/OAuthClient.js';
23
+ export type * from './models/OAuthGrant.js';
24
+ export type * from './models/AuthUser.js';
25
+ export type * from './models/AuthLoginKey.js';
26
+ export type * from './models/AuthSession.js';
27
+ export type * from './models/AuthFormChallenge.js';
28
+ export type * from './models/OAuthAuthorizationRequest.js';
29
+ export type * from './models/OAuthAuthorizationCode.js';
30
+ export type * from './models/OAuthFamily.js';
31
+ export type * from './models/AuthRateLimit.js';
32
+ export type * from './commonInputTypes.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -3,7 +3,7 @@
3
3
  * attachments, secrets, datastores, webhooks, budget groups) to the database
4
4
  * from a validated bundle + reconciliation.
5
5
  */
6
- import type { PrismaClient } from "@prisma/client";
6
+ import type { PrismaClient } from "#prisma";
7
7
  import type { KeyObject } from "node:crypto";
8
8
  import type { Bundle } from "./bundle.js";
9
9
  import type { Reconciliation } from "./preflight.js";
@@ -3,7 +3,7 @@
3
3
  * attachments, secrets, datastores, webhooks, budget groups) to the database
4
4
  * from a validated bundle + reconciliation.
5
5
  */
6
- import { Prisma } from "@prisma/client";
6
+ import { Prisma } from "#prisma";
7
7
  import { createSecret, attachSecret } from "../core/secrets.js";
8
8
  import { createDatastore, attachDatastore } from "../core/datastores.js";
9
9
  import { createWebhook } from "../core/webhooks.js";
@@ -2,7 +2,7 @@
2
2
  * Top-level orchestrator: opens a bundle, runs preflight reconciliation,
3
3
  * renders the report, and (unless dry-run or fatal collision) creates entities.
4
4
  */
5
- import type { PrismaClient } from "@prisma/client";
5
+ import type { PrismaClient } from "#prisma";
6
6
  import type { ConflictPolicy } from "./preflight.js";
7
7
  import { type ImportResult } from "./create.js";
8
8
  export interface ImportOptions {
@@ -10,7 +10,7 @@
10
10
  * this module instead of re-deriving the null-handling itself, so changing
11
11
  * the policy again later is a change here, not an N-file sweep.
12
12
  */
13
- import type { PrismaClient, Tool } from "@prisma/client";
13
+ import type { PrismaClient, Tool } from "#prisma";
14
14
  export declare function canRead(ownerId: string | null, principalId: string): boolean;
15
15
  export declare function isOwner(ownerId: string | null, principalId: string): boolean;
16
16
  /** Same rule as canRead: a null owner is a mutation target for anyone, same as it's a read target for anyone. */
@@ -27,12 +27,12 @@ export declare function visibleToPrincipal(principalId: string): {
27
27
  export declare function requireOwnedAgent(db: PrismaClient, id: string, principalId: string): Promise<{
28
28
  name: string;
29
29
  model: string;
30
- budgetUsd: import("@prisma/client/runtime/library").Decimal;
30
+ budgetUsd: import("@prisma/client-runtime-utils").Decimal;
31
31
  id: string;
32
32
  systemPrompt: string;
33
33
  createdAt: Date;
34
34
  updatedAt: Date;
35
- kind: import("@prisma/client").$Enums.AgentKind;
35
+ kind: import("#prisma").AgentKind;
36
36
  schedule: string | null;
37
37
  timezone: string;
38
38
  scheduleEnabled: boolean;
@@ -45,12 +45,12 @@ export declare function requireOwnedAgent(db: PrismaClient, id: string, principa
45
45
  export declare function requireReadableAgent(db: PrismaClient, id: string, principalId: string): Promise<{
46
46
  name: string;
47
47
  model: string;
48
- budgetUsd: import("@prisma/client/runtime/library").Decimal;
48
+ budgetUsd: import("@prisma/client-runtime-utils").Decimal;
49
49
  id: string;
50
50
  systemPrompt: string;
51
51
  createdAt: Date;
52
52
  updatedAt: Date;
53
- kind: import("@prisma/client").$Enums.AgentKind;
53
+ kind: import("#prisma").AgentKind;
54
54
  schedule: string | null;
55
55
  timezone: string;
56
56
  scheduleEnabled: boolean;
@@ -66,10 +66,10 @@ export declare function requireOwnedBudgetGroup(db: PrismaClient, id: string, pr
66
66
  createdAt: Date;
67
67
  updatedAt: Date;
68
68
  ownerId: string | null;
69
- dailyBudgetUsd: import("@prisma/client/runtime/library").Decimal | null;
70
- weeklyBudgetUsd: import("@prisma/client/runtime/library").Decimal | null;
71
- monthlyBudgetUsd: import("@prisma/client/runtime/library").Decimal | null;
72
- warnThresholdRatio: import("@prisma/client/runtime/library").Decimal;
69
+ dailyBudgetUsd: import("@prisma/client-runtime-utils").Decimal | null;
70
+ weeklyBudgetUsd: import("@prisma/client-runtime-utils").Decimal | null;
71
+ monthlyBudgetUsd: import("@prisma/client-runtime-utils").Decimal | null;
72
+ warnThresholdRatio: import("@prisma/client-runtime-utils").Decimal;
73
73
  }>;
74
74
  export declare function requireReadableBudgetGroup(db: PrismaClient, id: string, principalId: string): Promise<{
75
75
  name: string;
@@ -77,10 +77,10 @@ export declare function requireReadableBudgetGroup(db: PrismaClient, id: string,
77
77
  createdAt: Date;
78
78
  updatedAt: Date;
79
79
  ownerId: string | null;
80
- dailyBudgetUsd: import("@prisma/client/runtime/library").Decimal | null;
81
- weeklyBudgetUsd: import("@prisma/client/runtime/library").Decimal | null;
82
- monthlyBudgetUsd: import("@prisma/client/runtime/library").Decimal | null;
83
- warnThresholdRatio: import("@prisma/client/runtime/library").Decimal;
80
+ dailyBudgetUsd: import("@prisma/client-runtime-utils").Decimal | null;
81
+ weeklyBudgetUsd: import("@prisma/client-runtime-utils").Decimal | null;
82
+ monthlyBudgetUsd: import("@prisma/client-runtime-utils").Decimal | null;
83
+ warnThresholdRatio: import("@prisma/client-runtime-utils").Decimal;
84
84
  }>;
85
85
  export declare function requireOwnedSecret(db: PrismaClient, id: string, principalId: string): Promise<void>;
86
86
  export declare function requireOwnedWebhook(db: PrismaClient, id: string, principalId: string): Promise<void>;
@@ -98,16 +98,16 @@ export declare function requireOwnedTool(db: Pick<PrismaClient, "tool">, id: str
98
98
  * triggered them. No canRead/null=public path exists here on purpose.
99
99
  */
100
100
  export declare function requireOwnedTask(db: PrismaClient, taskId: string, principalId: string): Promise<{
101
- status: import("@prisma/client").$Enums.TaskStatus;
101
+ status: import("#prisma").TaskStatus;
102
102
  runId: string | null;
103
- error: import("@prisma/client/runtime/library").JsonValue | null;
104
- result: import("@prisma/client/runtime/library").JsonValue | null;
103
+ error: import("@prisma/client/runtime/client").JsonValue | null;
104
+ result: import("@prisma/client/runtime/client").JsonValue | null;
105
105
  id: string;
106
106
  createdAt: Date;
107
107
  updatedAt: Date;
108
- kind: import("@prisma/client").$Enums.TaskKind;
108
+ kind: import("#prisma").TaskKind;
109
109
  principalId: string | null;
110
- inputRequests: import("@prisma/client/runtime/library").JsonValue | null;
111
- inputResponses: import("@prisma/client/runtime/library").JsonValue | null;
110
+ inputRequests: import("@prisma/client/runtime/client").JsonValue | null;
111
+ inputResponses: import("@prisma/client/runtime/client").JsonValue | null;
112
112
  ttlAt: Date;
113
113
  }>;
@@ -5,5 +5,5 @@
5
5
  * always carries an owner, so a deployment that later moves from stdio to
6
6
  * HTTP+OAuth doesn't orphan locally-authored agents.
7
7
  */
8
- import type { PrismaClient, Principal } from "@prisma/client";
8
+ import type { PrismaClient, Principal } from "#prisma";
9
9
  export declare function resolvePrincipal(subject: string, db: PrismaClient): Promise<Principal>;
@@ -4,7 +4,7 @@
4
4
  * AuthProvider (delegating | self-hosted) is active — both implement
5
5
  * verifyBearer, so this file never branches on auth mode.
6
6
  */
7
- import type { PrismaClient } from "@prisma/client";
7
+ import type { PrismaClient } from "#prisma";
8
8
  import type { AuthProvider } from "../../providers/auth/types.js";
9
9
  import { McpError } from "../errors.js";
10
10
  import type { McpRequestContext, McpProviders } from "../context.js";
@@ -1,6 +1,7 @@
1
1
  import { randomUUID, randomBytes } from "node:crypto";
2
2
  import { PostgresRateLimiter, RateLimitError } from "./rate-limit.js";
3
3
  import { logger } from "../../../core/logger.js";
4
+ import { PAGE_STYLE } from "../../shared/page-style.js";
4
5
  const authLog = logger.child({ module: "self-hosted-oauth" });
5
6
  const paths = new Set([
6
7
  "/login",
@@ -29,12 +30,21 @@ const FORM_SCRIPT = `document.addEventListener('submit', async (event) => {
29
30
  });`;
30
31
  function html(res, content) {
31
32
  const nonce = randomBytes(18).toString("base64");
32
- res.setHeader("content-security-policy", `default-src 'none'; script-src 'nonce-${nonce}'; connect-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'`);
33
+ res.setHeader("content-security-policy",
34
+ // style-src reuses the same per-request nonce as script-src rather than
35
+ // 'unsafe-inline', so the one inline <style> stays as tightly scoped as
36
+ // the inline <script>.
37
+ `default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; connect-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'`);
33
38
  res
34
39
  .writeHead(200, { "content-type": "text/html; charset=utf-8" })
35
- .end('<!doctype html><html lang="en"><meta charset="utf-8"><title>wardby authorization</title><body>' +
40
+ .end('<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">' +
41
+ '<title>wardby authorization</title><style nonce="' +
42
+ nonce +
43
+ '">' +
44
+ PAGE_STYLE +
45
+ '</style><body><div class="card"><div class="kicker">wardby</div>' +
36
46
  content +
37
- '<p id="auth-error" role="alert"></p><noscript>JavaScript is required for secure form submission.</noscript><script nonce="' +
47
+ '<p id="auth-error" role="alert"></p></div><noscript>JavaScript is required for secure form submission.</noscript><script nonce="' +
38
48
  nonce +
39
49
  '">' +
40
50
  FORM_SCRIPT +
@@ -155,7 +165,7 @@ export function browserHandler(provider) {
155
165
  html(res, '<h1>Sign in to wardby</h1><form method="post" action="/login">' +
156
166
  hidden("interaction", interaction) +
157
167
  hidden("csrf", challenge) +
158
- '<label>Login key <input type="password" name="login_key" required autocomplete="off"></label><button>Sign in</button></form>');
168
+ '<label>Login key<input type="password" name="login_key" required autocomplete="off"></label><button>Sign in</button></form>');
159
169
  return true;
160
170
  }
161
171
  if (req.method === "POST" &&
@@ -198,7 +208,8 @@ export function browserHandler(provider) {
198
208
  '</p><form action="/consent" method="post">' +
199
209
  hidden("interaction", id) +
200
210
  hidden("csrf", challenge) +
201
- '<button name="decision" value="approve">Approve</button><button name="decision" value="deny">Deny</button></form>');
211
+ '<div class="actions"><button name="decision" value="approve">Approve</button>' +
212
+ '<button name="decision" value="deny">Deny</button></div></form>');
202
213
  return true;
203
214
  }
204
215
  if (req.method === "POST" && url.pathname === "/consent") {
@@ -210,7 +221,10 @@ export function browserHandler(provider) {
210
221
  if (req.method === "GET" && url.pathname === "/logout") {
211
222
  const session = await provider.sessions.get(cookies.get(sessionName) ?? "");
212
223
  const challenge = await provider.sessions.challenge("logout", session.sessionId, "logout");
213
- html(res, '<form action="/logout" method="post">' + hidden("csrf", challenge) + "<button>Sign out</button></form>");
224
+ html(res, "<h1>Sign out</h1>" +
225
+ '<form action="/logout" method="post">' +
226
+ hidden("csrf", challenge) +
227
+ "<button>Sign out</button></form>");
214
228
  return true;
215
229
  }
216
230
  if (req.method === "POST" && url.pathname === "/logout") {
@@ -1,2 +1,2 @@
1
- import type { PrismaClient } from "@prisma/client";
1
+ import type { PrismaClient } from "#prisma";
2
2
  export declare function authCommand(args: string[], db: PrismaClient, hashKey: string, output?: (value: string) => void): Promise<void>;
@@ -1,4 +1,4 @@
1
- import type { Prisma, PrismaClient } from "@prisma/client";
1
+ import type { Prisma, PrismaClient } from "#prisma";
2
2
  export type AuthDb = Prisma.TransactionClient;
3
3
  export declare const DAY = 86400000;
4
4
  export declare function decodeKey(value: string, name: string): Buffer;
@@ -1,4 +1,4 @@
1
- import type { PrismaClient } from "@prisma/client";
1
+ import type { PrismaClient } from "#prisma";
2
2
  import type { Credentials } from "./credentials.js";
3
3
  export interface RateLimiter {
4
4
  check(bucket: string, identity: string, limit: number): Promise<void>;
@@ -1,4 +1,4 @@
1
- import type { PrismaClient } from "@prisma/client";
1
+ import type { PrismaClient } from "#prisma";
2
2
  import type { Credentials } from "./credentials.js";
3
3
  import { type AuthDb } from "./credentials.js";
4
4
  export declare class Sessions {
@@ -7,7 +7,7 @@
7
7
  * registry also carries jobs/email/auth/storage seams no Phase 4 tool
8
8
  * needs and this plan never builds real adapters for.
9
9
  */
10
- import type { Principal, PrismaClient } from "@prisma/client";
10
+ import type { Principal, PrismaClient } from "#prisma";
11
11
  import type { RequestStateAccessor } from "@modelcontextprotocol/server";
12
12
  import type { ProviderRegistry } from "../providers/index.js";
13
13
  export type McpProviders = Pick<ProviderRegistry, "llm" | "engine" | "datastore" | "secrets" | "executor" | "memory">;
@@ -23,7 +23,7 @@
23
23
  * whole connection.
24
24
  */
25
25
  import { type McpServerFactory, type InputRequiredResult } from "@modelcontextprotocol/server";
26
- import type { PrismaClient } from "@prisma/client";
26
+ import type { PrismaClient } from "#prisma";
27
27
  import type { McpRequestContext, McpProviders } from "./context.js";
28
28
  export interface ToolSpec<Args = Record<string, unknown>> {
29
29
  name: string;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Shared CSS for wardby's server-rendered pages: the self-hosted OAuth
3
+ * browser flow (auth/self-hosted/browser.ts) and the secret-entry form
4
+ * (tools/secret-elicitation-form.ts). Both are publicly reachable,
5
+ * dependency-free surfaces — no CDN fonts, no external stylesheets, no
6
+ * external images — so this module is the one inline stylesheet each page
7
+ * embeds in its own `<style>` tag rather than a `<link>`.
8
+ *
9
+ * Tokens follow the naming used by wardby's marketing/dashboard page so this
10
+ * corner of the product reads as the same system: --cream --gold --ink
11
+ * --line --mint --mint-deep --muted --paper --red --shadow --sky --white.
12
+ * Dark mode redefines the same token names under `prefers-color-scheme` —
13
+ * the source page itself has no dark mode, but these pages already did
14
+ * (the secret form's previous inline styles supported it), so it's kept.
15
+ */
16
+ export declare const PAGE_STYLE = "\n:root {\n color-scheme: light dark;\n --cream: #fffaf0;\n --paper: #f7f4ec;\n --white: #ffffff;\n --ink: #12243c;\n --muted: #657287;\n --line: #dce3e8;\n --mint: #43e6b1;\n --mint-deep: #15b982;\n --gold: #c9aa70;\n --red: #e33d37;\n --sky: #75d4ff;\n --shadow: 0 24px 70px rgba(6, 23, 47, 0.12);\n}\n@media (prefers-color-scheme: dark) {\n :root {\n --paper: #0b1524;\n --white: #142238;\n --ink: #f2f6fa;\n --muted: #9fb0c2;\n --line: #263a52;\n --shadow: 0 24px 70px rgba(0, 0, 0, 0.5);\n }\n}\n* { box-sizing: border-box; }\nbody {\n margin: 0;\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n color: var(--ink);\n background:\n radial-gradient(circle at 12% 0%, rgba(67, 230, 177, 0.14), transparent 26rem),\n radial-gradient(circle at 100% 20%, rgba(117, 212, 255, 0.12), transparent 30rem),\n var(--paper);\n font-family: \"Avenir Next\", Avenir, \"Trebuchet MS\", sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n.card {\n width: 100%;\n max-width: 420px;\n padding: 38px 34px;\n border: 1px solid var(--line);\n border-radius: 20px;\n background: var(--white);\n box-shadow: var(--shadow);\n}\n.kicker {\n margin: 0 0 12px;\n color: var(--mint-deep);\n font-size: 11px;\n font-weight: 800;\n letter-spacing: 0.15em;\n text-transform: uppercase;\n}\nh1 {\n margin: 0 0 10px;\n font-family: Futura, \"Avenir Next\", Avenir, sans-serif;\n font-size: 23px;\n line-height: 1.2;\n letter-spacing: -0.02em;\n}\np { margin: 0 0 22px; color: var(--muted); font-size: 14px; line-height: 1.55; }\np:last-child { margin-bottom: 0; }\np strong { color: var(--ink); }\nlabel { display: block; margin-bottom: 18px; font-size: 13px; font-weight: 700; color: var(--muted); }\ninput[type=\"password\"] {\n display: block;\n width: 100%;\n margin-top: 8px;\n padding: 14px 16px;\n font-size: 16px;\n letter-spacing: 0.02em;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n color: var(--ink);\n background: var(--paper);\n border: 1px solid var(--line);\n border-radius: 10px;\n}\ninput[type=\"password\"]:focus {\n outline: none;\n border-color: var(--mint-deep);\n box-shadow: 0 0 0 3px rgba(21, 185, 130, 0.18);\n}\nbutton {\n width: 100%;\n margin-top: 4px;\n padding: 15px;\n font: inherit;\n font-size: 15px;\n font-weight: 700;\n color: var(--cream);\n background: var(--ink);\n border: none;\n border-radius: 10px;\n cursor: pointer;\n transition: background 140ms ease;\n}\nbutton:hover { background: var(--mint-deep); }\nbutton:focus-visible { outline: 3px solid var(--mint-deep); outline-offset: 2px; }\n.actions { display: flex; gap: 10px; margin-top: 4px; }\n.actions button { margin-top: 0; }\n.actions button[value=\"deny\"] {\n color: var(--ink);\n background: var(--paper);\n border: 1px solid var(--line);\n}\n.actions button[value=\"deny\"]:hover { background: var(--line); }\n#auth-error { margin: 16px 0 0; color: var(--red); font-size: 13px; min-height: 1em; }\n";
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Shared CSS for wardby's server-rendered pages: the self-hosted OAuth
3
+ * browser flow (auth/self-hosted/browser.ts) and the secret-entry form
4
+ * (tools/secret-elicitation-form.ts). Both are publicly reachable,
5
+ * dependency-free surfaces — no CDN fonts, no external stylesheets, no
6
+ * external images — so this module is the one inline stylesheet each page
7
+ * embeds in its own `<style>` tag rather than a `<link>`.
8
+ *
9
+ * Tokens follow the naming used by wardby's marketing/dashboard page so this
10
+ * corner of the product reads as the same system: --cream --gold --ink
11
+ * --line --mint --mint-deep --muted --paper --red --shadow --sky --white.
12
+ * Dark mode redefines the same token names under `prefers-color-scheme` —
13
+ * the source page itself has no dark mode, but these pages already did
14
+ * (the secret form's previous inline styles supported it), so it's kept.
15
+ */
16
+ export const PAGE_STYLE = `
17
+ :root {
18
+ color-scheme: light dark;
19
+ --cream: #fffaf0;
20
+ --paper: #f7f4ec;
21
+ --white: #ffffff;
22
+ --ink: #12243c;
23
+ --muted: #657287;
24
+ --line: #dce3e8;
25
+ --mint: #43e6b1;
26
+ --mint-deep: #15b982;
27
+ --gold: #c9aa70;
28
+ --red: #e33d37;
29
+ --sky: #75d4ff;
30
+ --shadow: 0 24px 70px rgba(6, 23, 47, 0.12);
31
+ }
32
+ @media (prefers-color-scheme: dark) {
33
+ :root {
34
+ --paper: #0b1524;
35
+ --white: #142238;
36
+ --ink: #f2f6fa;
37
+ --muted: #9fb0c2;
38
+ --line: #263a52;
39
+ --shadow: 0 24px 70px rgba(0, 0, 0, 0.5);
40
+ }
41
+ }
42
+ * { box-sizing: border-box; }
43
+ body {
44
+ margin: 0;
45
+ min-height: 100vh;
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ padding: 24px;
50
+ color: var(--ink);
51
+ background:
52
+ radial-gradient(circle at 12% 0%, rgba(67, 230, 177, 0.14), transparent 26rem),
53
+ radial-gradient(circle at 100% 20%, rgba(117, 212, 255, 0.12), transparent 30rem),
54
+ var(--paper);
55
+ font-family: "Avenir Next", Avenir, "Trebuchet MS", sans-serif;
56
+ -webkit-font-smoothing: antialiased;
57
+ }
58
+ .card {
59
+ width: 100%;
60
+ max-width: 420px;
61
+ padding: 38px 34px;
62
+ border: 1px solid var(--line);
63
+ border-radius: 20px;
64
+ background: var(--white);
65
+ box-shadow: var(--shadow);
66
+ }
67
+ .kicker {
68
+ margin: 0 0 12px;
69
+ color: var(--mint-deep);
70
+ font-size: 11px;
71
+ font-weight: 800;
72
+ letter-spacing: 0.15em;
73
+ text-transform: uppercase;
74
+ }
75
+ h1 {
76
+ margin: 0 0 10px;
77
+ font-family: Futura, "Avenir Next", Avenir, sans-serif;
78
+ font-size: 23px;
79
+ line-height: 1.2;
80
+ letter-spacing: -0.02em;
81
+ }
82
+ p { margin: 0 0 22px; color: var(--muted); font-size: 14px; line-height: 1.55; }
83
+ p:last-child { margin-bottom: 0; }
84
+ p strong { color: var(--ink); }
85
+ label { display: block; margin-bottom: 18px; font-size: 13px; font-weight: 700; color: var(--muted); }
86
+ input[type="password"] {
87
+ display: block;
88
+ width: 100%;
89
+ margin-top: 8px;
90
+ padding: 14px 16px;
91
+ font-size: 16px;
92
+ letter-spacing: 0.02em;
93
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
94
+ color: var(--ink);
95
+ background: var(--paper);
96
+ border: 1px solid var(--line);
97
+ border-radius: 10px;
98
+ }
99
+ input[type="password"]:focus {
100
+ outline: none;
101
+ border-color: var(--mint-deep);
102
+ box-shadow: 0 0 0 3px rgba(21, 185, 130, 0.18);
103
+ }
104
+ button {
105
+ width: 100%;
106
+ margin-top: 4px;
107
+ padding: 15px;
108
+ font: inherit;
109
+ font-size: 15px;
110
+ font-weight: 700;
111
+ color: var(--cream);
112
+ background: var(--ink);
113
+ border: none;
114
+ border-radius: 10px;
115
+ cursor: pointer;
116
+ transition: background 140ms ease;
117
+ }
118
+ button:hover { background: var(--mint-deep); }
119
+ button:focus-visible { outline: 3px solid var(--mint-deep); outline-offset: 2px; }
120
+ .actions { display: flex; gap: 10px; margin-top: 4px; }
121
+ .actions button { margin-top: 0; }
122
+ .actions button[value="deny"] {
123
+ color: var(--ink);
124
+ background: var(--paper);
125
+ border: 1px solid var(--line);
126
+ }
127
+ .actions button[value="deny"]:hover { background: var(--line); }
128
+ #auth-error { margin: 16px 0 0; color: var(--red); font-size: 13px; min-height: 1em; }
129
+ `;
@@ -10,7 +10,7 @@
10
10
  * cancellation is cooperative and eventually consistent, per the
11
11
  * extension's own spec language).
12
12
  */
13
- import type { PrismaClient, Task } from "@prisma/client";
13
+ import type { PrismaClient, Task } from "#prisma";
14
14
  export type TaskStatus = "working" | "input_required" | "completed" | "failed" | "cancelled";
15
15
  export interface JsonRpcErrorObject {
16
16
  code: number;
@@ -1,5 +1,5 @@
1
1
  /** Agent CRUD with scope checks in server.ts and ownership checks here. */
2
- import { Prisma } from "@prisma/client";
2
+ import { Prisma } from "#prisma";
3
3
  import { z } from "zod";
4
4
  import { CodingProfilePatchSchema, CodingProfileSchema } from "../../coding/profile.js";
5
5
  import { codingProviderSupportsModel } from "../../coding/provider.js";
@@ -1,4 +1,4 @@
1
- import { Prisma } from "@prisma/client";
1
+ import { Prisma } from "#prisma";
2
2
  import { requireOwnedAgent, requireReadableAgent, requireOwnedDatastore, canRead, assertCanMutate, } from "../auth/ownership.js";
3
3
  import { createDatastore, listDatastores, deleteDatastore, attachDatastore, detachDatastore, buildSharedDatastoreAccessor, } from "../../core/datastores.js";
4
4
  import { McpError } from "../errors.js";
@@ -1,4 +1,4 @@
1
- import { Prisma } from "@prisma/client";
1
+ import { Prisma } from "#prisma";
2
2
  import { validateCronExpression } from "../../core/cron.js";
3
3
  import { McpError } from "../errors.js";
4
4
  import { assertCanMutate, requireOwnedAgent } from "../auth/ownership.js";
@@ -6,7 +6,7 @@
6
6
  * CSP can forbid scripts outright rather than needing a nonce.
7
7
  */
8
8
  import type { IncomingMessage, ServerResponse } from "node:http";
9
- import type { PrismaClient } from "@prisma/client";
9
+ import type { PrismaClient } from "#prisma";
10
10
  import type { SecretCipher } from "../../providers/secrets/types.js";
11
11
  import { type SecretElicitationPayload } from "./secret-elicitation.js";
12
12
  /** The HTTP-transport route path this form is mounted at (see streamable-http.ts). */
@@ -1,43 +1,24 @@
1
1
  import { fulfillSecretElicitation } from "./secret-elicitation.js";
2
+ import { PAGE_STYLE } from "../shared/page-style.js";
2
3
  /** The HTTP-transport route path this form is mounted at (see streamable-http.ts). */
3
4
  export const SECRET_ELICITATION_PATH = "/elicit/secret";
4
5
  function escape(value) {
5
6
  return value.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
6
7
  }
7
- const STYLE = `
8
- :root { color-scheme: light dark; }
9
- * { box-sizing: border-box; }
10
- body { margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px;
11
- background: #f5f5f7; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
12
- .card { background: #fff; border-radius: 14px; box-shadow: 0 1px 3px rgba(0,0,0,.1), 0 8px 24px rgba(0,0,0,.08);
13
- padding: 36px; max-width: 480px; width: 100%; }
14
- h1 { margin: 0 0 10px; font-size: 21px; }
15
- p { margin: 0 0 24px; color: #555; font-size: 14px; line-height: 1.5; }
16
- p strong { color: #111; }
17
- input[type=password] { display: block; width: 100%; padding: 16px 18px; font-size: 17px; letter-spacing: .02em;
18
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; border: 1px solid #d1d1d6; border-radius: 10px;
19
- margin-bottom: 18px; }
20
- input[type=password]:focus { outline: none; border-color: #0071e3; box-shadow: 0 0 0 3px rgba(0,113,227,.15); }
21
- button { width: 100%; padding: 15px; font-size: 15px; font-weight: 600; color: #fff; background: #0071e3;
22
- border: none; border-radius: 10px; cursor: pointer; }
23
- button:hover { background: #0077ed; }
24
- @media (prefers-color-scheme: dark) {
25
- body { background: #1c1c1e; }
26
- .card { background: #2c2c2e; box-shadow: none; }
27
- h1 { color: #f5f5f7; }
28
- p { color: #a1a1a6; }
29
- p strong { color: #f5f5f7; }
30
- input[type=password] { background: #1c1c1e; border-color: #48484a; color: #f5f5f7; }
31
- }`;
32
8
  function html(res, status, body) {
33
9
  res.setHeader("content-security-policy", "default-src 'none'; script-src 'none'; style-src 'unsafe-inline'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'");
34
10
  res.setHeader("cache-control", "no-store");
35
11
  res.setHeader("x-content-type-options", "nosniff");
36
- res.setHeader("referrer-policy", "no-referrer");
12
+ // Not no-referrer: under it a browser sends `Origin: null` on this page's native
13
+ // form POST, even to the same origin, and the HTTP transport rejects that as
14
+ // invalid_origin. same-origin keeps the Origin and still sends nothing,
15
+ // token-bearing URL included, to any other site. (The login page solves the
16
+ // same problem with a fetch() instead; this page runs no script at all.)
17
+ res.setHeader("referrer-policy", "same-origin");
37
18
  res
38
19
  .writeHead(status, { "content-type": "text/html; charset=utf-8" })
39
20
  .end(`<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">` +
40
- `<title>wardby secret entry</title><style>${STYLE}</style><body><div class="card">${body}</div></body></html>`);
21
+ `<title>wardby secret entry</title><style>${PAGE_STYLE}</style><body><div class="card"><div class="kicker">wardby</div>${body}</div></body></html>`);
41
22
  }
42
23
  /** Handles one GET (render) or POST (submit) for the secret-entry form at the given token. */
43
24
  export async function handleSecretElicitationForm(method, token, readFormBody, res, deps) {
@@ -53,7 +34,8 @@ export async function handleSecretElicitationForm(method, token, readFormBody, r
53
34
  }
54
35
  if (method === "GET") {
55
36
  html(res, 200, `<h1>Enter secret value</h1><p>Name: <strong>${escape(payload.secretName)}</strong></p>` +
56
- `<form method="post"><input type="password" name="value" autocomplete="off" required autofocus placeholder="Paste the value here">` +
37
+ `<form method="post"><label>Secret value` +
38
+ `<input type="password" name="value" autocomplete="off" required autofocus placeholder="Paste the value here"></label>` +
57
39
  `<button type="submit">Save</button></form>`);
58
40
  return;
59
41
  }
@@ -15,7 +15,7 @@
15
15
  * Expiry is swept lazily on every read and write via a `deleteMany` rather
16
16
  * than a timer, so an idle process holds no interval.
17
17
  */
18
- import type { PrismaClient } from "@prisma/client";
18
+ import type { PrismaClient } from "#prisma";
19
19
  import { type SecretMetadata } from "../../core/secrets.js";
20
20
  import type { SecretCipher } from "../../providers/secrets/types.js";
21
21
  export interface SecretElicitationPayload {
@@ -6,7 +6,7 @@
6
6
  * graph (§7 of the design doc) — cycles are not something Postgres can
7
7
  * enforce natively.
8
8
  */
9
- import { Prisma } from "@prisma/client";
9
+ import { Prisma } from "#prisma";
10
10
  import { requireOwnedAgent } from "../auth/ownership.js";
11
11
  import { McpError } from "../errors.js";
12
12
  import { textResult } from "./text-result.js";
@@ -9,7 +9,7 @@
9
9
  * (attach/detach on an agent or tool you don't own) DO throw, same
10
10
  * convention as every other tool in this codebase.
11
11
  */
12
- import { Prisma } from "@prisma/client";
12
+ import { Prisma } from "#prisma";
13
13
  import { deriveJsonSchema, validateParams } from "../../sandbox/zod-params.js";
14
14
  import { runInSandbox } from "../../sandbox/run-in-sandbox.js";
15
15
  import { ToolCapabilitiesPatchSchema } from "../../sandbox/tool-capabilities.js";
@@ -1,6 +1,6 @@
1
1
  import { type ServerResponse } from "node:http";
2
2
  import { type PerRequestResponseMode } from "@modelcontextprotocol/server";
3
- import type { PrismaClient } from "@prisma/client";
3
+ import type { PrismaClient } from "#prisma";
4
4
  import type { AuthProvider } from "../../providers/auth/types.js";
5
5
  import type { SelfHostedAuthProvider } from "../../providers/auth/self-hosted.js";
6
6
  import type { WardbyMcpServer } from "../server.js";
@@ -1,4 +1,4 @@
1
- import type { PrismaClient } from "@prisma/client";
1
+ import type { PrismaClient } from "#prisma";
2
2
  /**
3
3
  * `wardby mcp` serves the MCP surface and launches the executor, but the
4
4
  * scheduler and reconciler live in `wardby scheduler` (or in `wardby serve`,
@@ -4,7 +4,7 @@
4
4
  * route in streamable-http.ts, matching the design's "route is
5
5
  * unauthenticated by OAuth" invariant.
6
6
  */
7
- import type { PrismaClient } from "@prisma/client";
7
+ import type { PrismaClient } from "#prisma";
8
8
  import type { Executor } from "../../providers/executor/types.js";
9
9
  export interface WebhookIngressRequest {
10
10
  headers: Record<string, string | undefined>;
@@ -3,7 +3,7 @@
3
3
  * kind. Both adapters implement the same AuthProvider (incl. verifyBearer),
4
4
  * so the resource-server middleware and tool handlers never branch on mode.
5
5
  */
6
- import type { PrismaClient } from "@prisma/client";
6
+ import type { PrismaClient } from "#prisma";
7
7
  import type { AuthProviderKind, AuthConfig } from "../../config/providers.js";
8
8
  import type { AuthProvider } from "./types.js";
9
9
  export { DelegatingAuthProvider } from "./delegating.js";