@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.
- package/README.md +142 -67
- package/dist/claude-coding-worker/driver.d.ts +1 -0
- package/dist/claude-coding-worker/driver.js +4 -1
- package/dist/claude-coding-worker/main.js +3 -2
- package/dist/coding/protocol.d.ts +28 -3
- package/dist/coding/protocol.js +53 -2
- package/dist/coding-worker/artifact.d.ts +12 -0
- package/dist/coding-worker/artifact.js +48 -6
- package/dist/coding-worker/driver.d.ts +1 -0
- package/dist/coding-worker/driver.js +4 -1
- package/dist/coding-worker/errors.d.ts +7 -0
- package/dist/coding-worker/errors.js +18 -0
- package/dist/coding-worker/main.js +3 -2
- package/dist/core/budget-groups.d.ts +1 -1
- package/dist/core/coding-queue.d.ts +1 -1
- package/dist/core/datastores.d.ts +1 -1
- package/dist/core/db.d.ts +36 -2
- package/dist/core/db.js +69 -2
- package/dist/core/dispatch.d.ts +16 -1
- package/dist/core/dispatch.js +33 -5
- package/dist/core/http-runtime.js +3 -4
- package/dist/core/lease.d.ts +1 -1
- package/dist/core/private-directory.d.ts +20 -0
- package/dist/core/private-directory.js +36 -0
- package/dist/core/reconciler.d.ts +1 -1
- package/dist/core/runner.d.ts +1 -1
- package/dist/core/scheduler.d.ts +1 -1
- package/dist/core/secrets.d.ts +1 -1
- package/dist/core/subagent-memory-tools.d.ts +1 -1
- package/dist/core/webhooks.d.ts +1 -1
- package/dist/generated/prisma/browser.d.ts +228 -0
- package/dist/generated/prisma/browser.js +17 -0
- package/dist/generated/prisma/client.d.ts +247 -0
- package/dist/generated/prisma/client.js +34 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +809 -0
- package/dist/generated/prisma/commonInputTypes.js +10 -0
- package/dist/generated/prisma/enums.d.ts +53 -0
- package/dist/generated/prisma/enums.js +54 -0
- package/dist/generated/prisma/internal/class.d.ts +462 -0
- package/dist/generated/prisma/internal/class.js +49 -0
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +3325 -0
- package/dist/generated/prisma/internal/prismaNamespace.js +455 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +449 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +426 -0
- package/dist/generated/prisma/models/Agent.d.ts +3267 -0
- package/dist/generated/prisma/models/Agent.js +1 -0
- package/dist/generated/prisma/models/AgentDatastore.d.ts +1210 -0
- package/dist/generated/prisma/models/AgentDatastore.js +1 -0
- package/dist/generated/prisma/models/AgentMemory.d.ts +986 -0
- package/dist/generated/prisma/models/AgentMemory.js +1 -0
- package/dist/generated/prisma/models/AgentSecret.d.ts +1212 -0
- package/dist/generated/prisma/models/AgentSecret.js +1 -0
- package/dist/generated/prisma/models/AgentSubAgent.d.ts +1217 -0
- package/dist/generated/prisma/models/AgentSubAgent.js +1 -0
- package/dist/generated/prisma/models/AgentTool.d.ts +1309 -0
- package/dist/generated/prisma/models/AgentTool.js +1 -0
- package/dist/generated/prisma/models/AuthFormChallenge.d.ts +1298 -0
- package/dist/generated/prisma/models/AuthFormChallenge.js +1 -0
- package/dist/generated/prisma/models/AuthLoginKey.d.ts +1245 -0
- package/dist/generated/prisma/models/AuthLoginKey.js +1 -0
- package/dist/generated/prisma/models/AuthRateLimit.d.ts +979 -0
- package/dist/generated/prisma/models/AuthRateLimit.js +1 -0
- package/dist/generated/prisma/models/AuthSession.d.ts +1376 -0
- package/dist/generated/prisma/models/AuthSession.js +1 -0
- package/dist/generated/prisma/models/AuthUser.d.ts +1645 -0
- package/dist/generated/prisma/models/AuthUser.js +1 -0
- package/dist/generated/prisma/models/BudgetGroup.d.ts +1548 -0
- package/dist/generated/prisma/models/BudgetGroup.js +1 -0
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +1430 -0
- package/dist/generated/prisma/models/CodingAgentProfile.js +1 -0
- package/dist/generated/prisma/models/CodingProxyRequest.d.ts +1749 -0
- package/dist/generated/prisma/models/CodingProxyRequest.js +1 -0
- package/dist/generated/prisma/models/CodingProxySession.d.ts +1505 -0
- package/dist/generated/prisma/models/CodingProxySession.js +1 -0
- package/dist/generated/prisma/models/CodingRun.d.ts +2402 -0
- package/dist/generated/prisma/models/CodingRun.js +1 -0
- package/dist/generated/prisma/models/Datastore.d.ts +1434 -0
- package/dist/generated/prisma/models/Datastore.js +1 -0
- package/dist/generated/prisma/models/DatastoreEntry.d.ts +1314 -0
- package/dist/generated/prisma/models/DatastoreEntry.js +1 -0
- package/dist/generated/prisma/models/OAuthAuthorizationCode.d.ts +1526 -0
- package/dist/generated/prisma/models/OAuthAuthorizationCode.js +1 -0
- package/dist/generated/prisma/models/OAuthAuthorizationRequest.d.ts +1350 -0
- package/dist/generated/prisma/models/OAuthAuthorizationRequest.js +1 -0
- package/dist/generated/prisma/models/OAuthClient.d.ts +1289 -0
- package/dist/generated/prisma/models/OAuthClient.js +1 -0
- package/dist/generated/prisma/models/OAuthFamily.d.ts +1540 -0
- package/dist/generated/prisma/models/OAuthFamily.js +1 -0
- package/dist/generated/prisma/models/OAuthGrant.d.ts +1280 -0
- package/dist/generated/prisma/models/OAuthGrant.js +1 -0
- package/dist/generated/prisma/models/Principal.d.ts +1790 -0
- package/dist/generated/prisma/models/Principal.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +2281 -0
- package/dist/generated/prisma/models/Run.js +1 -0
- package/dist/generated/prisma/models/SchedulerLease.d.ts +970 -0
- package/dist/generated/prisma/models/SchedulerLease.js +1 -0
- package/dist/generated/prisma/models/Secret.d.ts +1399 -0
- package/dist/generated/prisma/models/Secret.js +1 -0
- package/dist/generated/prisma/models/SecretElicitationOutcome.d.ts +973 -0
- package/dist/generated/prisma/models/SecretElicitationOutcome.js +1 -0
- package/dist/generated/prisma/models/Task.d.ts +1176 -0
- package/dist/generated/prisma/models/Task.js +1 -0
- package/dist/generated/prisma/models/Tool.d.ts +1478 -0
- package/dist/generated/prisma/models/Tool.js +1 -0
- package/dist/generated/prisma/models/Webhook.d.ts +1386 -0
- package/dist/generated/prisma/models/Webhook.js +1 -0
- package/dist/generated/prisma/models.d.ts +32 -0
- package/dist/generated/prisma/models.js +1 -0
- package/dist/import/create.d.ts +1 -1
- package/dist/import/create.js +1 -1
- package/dist/import/index.d.ts +1 -1
- package/dist/mcp/auth/ownership.d.ts +19 -19
- package/dist/mcp/auth/principal.d.ts +1 -1
- package/dist/mcp/auth/resource-server.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/browser.js +20 -6
- package/dist/mcp/auth/self-hosted/cli.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/credentials.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/rate-limit.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/session.d.ts +1 -1
- package/dist/mcp/context.d.ts +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/shared/page-style.d.ts +16 -0
- package/dist/mcp/shared/page-style.js +129 -0
- package/dist/mcp/tasks/manager.d.ts +1 -1
- package/dist/mcp/tools/agents.js +1 -1
- package/dist/mcp/tools/datastore.js +1 -1
- package/dist/mcp/tools/scheduling.js +1 -1
- package/dist/mcp/tools/secret-elicitation-form.d.ts +1 -1
- package/dist/mcp/tools/secret-elicitation-form.js +10 -28
- package/dist/mcp/tools/secret-elicitation.d.ts +1 -1
- package/dist/mcp/tools/subagents.js +1 -1
- package/dist/mcp/tools/tools.js +1 -1
- package/dist/mcp/transport/streamable-http.d.ts +1 -1
- package/dist/mcp/unattended-schedules.d.ts +1 -1
- package/dist/mcp/webhooks/ingress.d.ts +1 -1
- package/dist/providers/auth/index.d.ts +1 -1
- package/dist/providers/auth/self-hosted.d.ts +2 -2
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +1 -1
- package/dist/providers/coding-proxy/runtime.d.ts +1 -1
- package/dist/providers/datastore/postgres.d.ts +1 -1
- package/dist/providers/executor/build.d.ts +1 -1
- package/dist/providers/executor/composition.d.ts +1 -1
- package/dist/providers/executor/container.d.ts +1 -1
- package/dist/providers/executor/container.js +10 -3
- package/dist/providers/executor/dbos.d.ts +1 -1
- package/dist/providers/jobs/docker.d.ts +11 -0
- package/dist/providers/jobs/docker.js +34 -18
- package/dist/providers/jobs/kubernetes.js +5 -10
- package/dist/providers/jobs/types.d.ts +2 -0
- package/dist/providers/memory/postgres.d.ts +1 -1
- package/dist/providers/vcs/git.js +2 -1
- package/dist/quickstart/index.js +22 -31
- package/dist/quickstart/migrate.d.ts +23 -0
- package/dist/quickstart/migrate.js +125 -0
- package/package.json +20 -10
- package/prisma/migrate.config.mjs +20 -0
- package/prisma/schema.prisma +10 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PrismaClient } from "
|
|
1
|
+
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import type { AuthProfile, AuthProvider, AuthTokens, VerifiedToken } from "./types.js";
|
|
3
3
|
import { Credentials } from "../../mcp/auth/self-hosted/credentials.js";
|
|
4
4
|
import { Sessions } from "../../mcp/auth/self-hosted/session.js";
|
|
@@ -34,7 +34,7 @@ export declare class SelfHostedAuthProvider implements AuthProvider {
|
|
|
34
34
|
consentPage(sessionToken: string, interactionId: string): Promise<{
|
|
35
35
|
interaction: {
|
|
36
36
|
client: {
|
|
37
|
-
metadata: import("@prisma/client/runtime/
|
|
37
|
+
metadata: import("@prisma/client/runtime/client").JsonValue;
|
|
38
38
|
createdAt: Date;
|
|
39
39
|
clientId: string;
|
|
40
40
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PrismaClient } from "
|
|
1
|
+
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import type { CreateProxySessionInput, ProxyLedger, ProxyRequest, ProxySession, ProxyUsage, ReserveProxyRequestInput, ReserveProxyRequestResult } from "./types.js";
|
|
3
3
|
export type PrismaProxyLedgerDb = Pick<PrismaClient, "$transaction" | "$queryRaw" | "$executeRaw">;
|
|
4
4
|
export declare class PrismaProxyLedger implements ProxyLedger {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PrismaClient } from "
|
|
1
|
+
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import { startDenyPortListener } from "./deny-port.js";
|
|
3
3
|
import { startCodingProxyServer, type CodingProxyServerHandle } from "./server.js";
|
|
4
4
|
import type { ProxyAuditSink } from "./types.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Postgres-backed default Datastore adapter, via the `DatastoreEntry` table.
|
|
3
3
|
*/
|
|
4
|
-
import type { PrismaClient } from "
|
|
4
|
+
import type { PrismaClient } from "#prisma";
|
|
5
5
|
import type { Datastore, DatastoreSetOptions, DatastoreValue } from "./types.js";
|
|
6
6
|
import type { SecretCipher } from "../secrets/types.js";
|
|
7
7
|
export type DatastoreDb = Pick<PrismaClient, "datastoreEntry" | "datastore" | "$queryRaw">;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PrismaClient } from "
|
|
1
|
+
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import { type ProviderConfig } from "../../config/providers.js";
|
|
3
3
|
import type { KubernetesApi } from "../jobs/kubernetes-api.js";
|
|
4
4
|
import type { Executor } from "./types.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PrismaClient } from "
|
|
1
|
+
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import { type CodingRunObserver } from "../../coding/observability.js";
|
|
3
3
|
import { type CodingRunResult } from "../../coding/protocol.js";
|
|
4
4
|
import type { ProxyProtocol } from "../coding-proxy/types.js";
|
|
@@ -3,6 +3,7 @@ import { mkdir, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import { join, resolve, sep } from "node:path";
|
|
4
4
|
import { CodingProfileSchema } from "../../coding/profile.js";
|
|
5
5
|
import { logger } from "../../core/logger.js";
|
|
6
|
+
import { ensurePrivateDirectory } from "../../core/private-directory.js";
|
|
6
7
|
import { codingRunObserver } from "../../coding/observability.js";
|
|
7
8
|
import { CODING_PROTOCOL_VERSION, CodingRunResultSchema, CodingTaskInputSchema, parseCodingAgentOutputJson, redactAndTruncate, } from "../../coding/protocol.js";
|
|
8
9
|
import { getModelPricing } from "../llm/pricing.js";
|
|
@@ -597,7 +598,7 @@ export class ContainerExecutor {
|
|
|
597
598
|
const reason = collected?.diagnostic ?? collected?.reason ?? jobState;
|
|
598
599
|
this.emit({ stage: "collected", runId: run.runId, jobId: handle.id });
|
|
599
600
|
const status = jobState === "lost" ? "lost" : "failed";
|
|
600
|
-
const failure = this.failure(`job_${reason}
|
|
601
|
+
const failure = this.failure(`job_${reason}`, { issues: collected?.diagnosticIssues });
|
|
601
602
|
await this.options.store.terminate(run.runId, status, failure.error, failure.audit);
|
|
602
603
|
this.terminal(run, status, failure.audit);
|
|
603
604
|
return;
|
|
@@ -755,7 +756,7 @@ export class ContainerExecutor {
|
|
|
755
756
|
throw new Error("coding_provider_not_configured:claude-code");
|
|
756
757
|
}
|
|
757
758
|
async writeInput(run, deadlineAt) {
|
|
758
|
-
await
|
|
759
|
+
await ensurePrivateDirectory(this.artifactRoot);
|
|
759
760
|
const rootReal = await realpath(this.artifactRoot);
|
|
760
761
|
const directory = resolve(rootReal, run.runId);
|
|
761
762
|
if (!directory.startsWith(`${rootReal}${sep}`))
|
|
@@ -881,7 +882,13 @@ export class ContainerExecutor {
|
|
|
881
882
|
// keyed by the same diagnostic id. Token-shaped values are redacted, and a
|
|
882
883
|
// cause chain is kept because the outer message is often just a wrapper.
|
|
883
884
|
// A user asking to stop is not a failure, so it gets the same id at info.
|
|
884
|
-
|
|
885
|
+
// `issues` names only which output-schema fields failed (see SAFE_CODING_OUTPUT_ISSUE).
|
|
886
|
+
const line = {
|
|
887
|
+
diagnosticId,
|
|
888
|
+
category,
|
|
889
|
+
reason: describeFailure(error),
|
|
890
|
+
...(options.issues ? { issues: options.issues } : {}),
|
|
891
|
+
};
|
|
885
892
|
if (options.cancelled === true)
|
|
886
893
|
containerLog.info(line, "coding run cancelled; the persisted error is its id only");
|
|
887
894
|
else
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* stale-heartbeat detection is unchanged; the reconciler consults
|
|
13
13
|
* `recover()` (Task 6) before declaring a DBOS run lost.
|
|
14
14
|
*/
|
|
15
|
-
import type { PrismaClient } from "
|
|
15
|
+
import type { PrismaClient } from "#prisma";
|
|
16
16
|
import type { ProviderRegistry } from "../index.js";
|
|
17
17
|
import type { DbosConfig } from "../../config/providers.js";
|
|
18
18
|
import { type RunnerDb } from "../../core/runner.js";
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { JobHandle, JobResult, JobSpec, JobStatus, WorkspaceJobLauncher } from "./types.js";
|
|
2
2
|
export declare const SAFE_WORKER_DIAGNOSTIC: RegExp;
|
|
3
|
+
export interface WorkerDiagnostic {
|
|
4
|
+
diagnostic: string;
|
|
5
|
+
diagnosticIssues?: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Worker output is untrusted: recognizes only the fixed `{"error": code}` line,
|
|
9
|
+
* plus an optional `issues` list whose every entry must pass the shared pattern.
|
|
10
|
+
* A list with any entry that does not is dropped whole rather than filtered, so
|
|
11
|
+
* a malformed worker cannot smuggle a partial value through.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseWorkerDiagnosticLine(line: string): WorkerDiagnostic | undefined;
|
|
3
14
|
export interface DockerCommandOptions {
|
|
4
15
|
env?: Record<string, string>;
|
|
5
16
|
maxOutputBytes?: number;
|
|
@@ -3,7 +3,9 @@ import { spawn } from "node:child_process";
|
|
|
3
3
|
import { lstat, mkdir, mkdtemp, open, opendir, readdir, readFile, readlink, realpath, rename, rm, unlink, } from "node:fs/promises";
|
|
4
4
|
import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
5
5
|
import { logger } from "../../core/logger.js";
|
|
6
|
-
import {
|
|
6
|
+
import { ensurePrivateDirectory } from "../../core/private-directory.js";
|
|
7
|
+
import { readBoundedRegularFile } from "../../coding-worker/artifact.js";
|
|
8
|
+
import { parseCodingAgentOutputJson, redactAndTruncate, MAX_CODING_ARTIFACT_BYTES, MAX_CODING_OUTPUT_ISSUES, SAFE_CODING_OUTPUT_ISSUE, } from "../../coding/protocol.js";
|
|
7
9
|
import { assertDockerHostSupportsIsolation, assertClaudeAgentContainerInspection, assertClaudeToolRunnerContainerInspection, assertIsolationNetworkInspection, assertKeeperContainerInspection, assertProxyContainerInspection, assertStorageVolumeInspection, assertWorkerContainerInspection, buildDockerIsolationPlan, } from "./docker-isolation.js";
|
|
8
10
|
import { replaceDirectoryFromStaging } from "./workspace-swap.js";
|
|
9
11
|
const BACKEND = "docker";
|
|
@@ -13,6 +15,31 @@ const MAX_DOCKER_SEED_DIAGNOSTIC_BYTES = 4 * 1024;
|
|
|
13
15
|
const MAX_WORKSPACE_ENTRIES = 100_000;
|
|
14
16
|
const TERMINAL_PHASES = new Set(["succeeded", "failed", "stopped", "lost", "removed"]);
|
|
15
17
|
export const SAFE_WORKER_DIAGNOSTIC = /^(?:worker_[a-z_]+|coding_[a-z_]+|wardby_[a-z_]+)$/;
|
|
18
|
+
/**
|
|
19
|
+
* Worker output is untrusted: recognizes only the fixed `{"error": code}` line,
|
|
20
|
+
* plus an optional `issues` list whose every entry must pass the shared pattern.
|
|
21
|
+
* A list with any entry that does not is dropped whole rather than filtered, so
|
|
22
|
+
* a malformed worker cannot smuggle a partial value through.
|
|
23
|
+
*/
|
|
24
|
+
export function parseWorkerDiagnosticLine(line) {
|
|
25
|
+
let value;
|
|
26
|
+
try {
|
|
27
|
+
value = JSON.parse(line);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
if (typeof value?.error !== "string" || !SAFE_WORKER_DIAGNOSTIC.test(value.error))
|
|
33
|
+
return undefined;
|
|
34
|
+
const issues = value.issues;
|
|
35
|
+
const safeIssues = Array.isArray(issues) &&
|
|
36
|
+
issues.length > 0 &&
|
|
37
|
+
issues.length <= MAX_CODING_OUTPUT_ISSUES &&
|
|
38
|
+
issues.every((issue) => typeof issue === "string" && SAFE_CODING_OUTPUT_ISSUE.test(issue))
|
|
39
|
+
? issues
|
|
40
|
+
: undefined;
|
|
41
|
+
return { diagnostic: value.error, ...(safeIssues ? { diagnosticIssues: safeIssues } : {}) };
|
|
42
|
+
}
|
|
16
43
|
const dockerLog = logger.child({ module: "docker-jobs" });
|
|
17
44
|
/**
|
|
18
45
|
* Docker failures never include daemon output in their public message -- that
|
|
@@ -440,7 +467,7 @@ export class DockerJobLauncher {
|
|
|
440
467
|
if (current.phase === "failed" && !current.result.diagnostic) {
|
|
441
468
|
const diagnostic = await this.readWorkerFailureDiagnostic(current);
|
|
442
469
|
if (diagnostic) {
|
|
443
|
-
current.result = { ...current.result, diagnostic };
|
|
470
|
+
current.result = { ...current.result, ...diagnostic };
|
|
444
471
|
await this.writeRecord(current);
|
|
445
472
|
}
|
|
446
473
|
}
|
|
@@ -500,7 +527,7 @@ export class DockerJobLauncher {
|
|
|
500
527
|
});
|
|
501
528
|
}
|
|
502
529
|
async initialize() {
|
|
503
|
-
await
|
|
530
|
+
await ensurePrivateDirectory(this.stateRoot);
|
|
504
531
|
await mkdir(join(this.stateRoot, ".home"), { recursive: true, mode: 0o700 });
|
|
505
532
|
await realpath(this.stateRoot);
|
|
506
533
|
const records = await this.allRecords();
|
|
@@ -792,13 +819,7 @@ export class DockerJobLauncher {
|
|
|
792
819
|
const target = join(staging, "result.json");
|
|
793
820
|
try {
|
|
794
821
|
await this.run(["container", "cp", `${this.keeperName(record)}:/run/wardby/storage/output/result.json`, target]);
|
|
795
|
-
const
|
|
796
|
-
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > MAX_CODING_ARTIFACT_BYTES) {
|
|
797
|
-
throw new Error("docker_result_artifact_invalid");
|
|
798
|
-
}
|
|
799
|
-
const raw = await readFile(target, "utf8");
|
|
800
|
-
if (Buffer.byteLength(raw, "utf8") > MAX_CODING_ARTIFACT_BYTES)
|
|
801
|
-
throw new Error("docker_result_artifact_invalid");
|
|
822
|
+
const raw = await readBoundedRegularFile(target, MAX_CODING_ARTIFACT_BYTES, "docker_result_artifact_invalid");
|
|
802
823
|
const output = parseCodingAgentOutputJson(raw);
|
|
803
824
|
if (output.runId !== record.runId)
|
|
804
825
|
throw new Error("docker_result_run_mismatch");
|
|
@@ -818,14 +839,9 @@ export class DockerJobLauncher {
|
|
|
818
839
|
const logs = await this.run(["container", "logs", "--tail", "8", record.handle.id]);
|
|
819
840
|
const raw = `${logs.stdout}\n${logs.stderr}`;
|
|
820
841
|
for (const line of raw.split("\n").reverse()) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
return value.error;
|
|
825
|
-
}
|
|
826
|
-
catch {
|
|
827
|
-
// Worker output is untrusted; only parse one fixed JSON shape.
|
|
828
|
-
}
|
|
842
|
+
const diagnostic = parseWorkerDiagnosticLine(line);
|
|
843
|
+
if (diagnostic)
|
|
844
|
+
return diagnostic;
|
|
829
845
|
}
|
|
830
846
|
}
|
|
831
847
|
catch {
|
|
@@ -31,7 +31,7 @@ import { isIP } from "node:net";
|
|
|
31
31
|
import { logger } from "../../core/logger.js";
|
|
32
32
|
import { MAX_CODING_ARTIFACT_BYTES, parseCodingAgentOutputJson } from "../../coding/protocol.js";
|
|
33
33
|
import { CODING_PROXY_DENY_PORT, CODING_PROXY_PORT } from "./docker-isolation.js";
|
|
34
|
-
import {
|
|
34
|
+
import { parseWorkerDiagnosticLine } from "./docker.js";
|
|
35
35
|
import { KubernetesAlreadyExistsError, KubernetesConflictError } from "./kubernetes-api.js";
|
|
36
36
|
import { ENFORCEMENT_PROBE_DENY_REACHABLE, ENFORCEMENT_PROBE_PROVEN, ENFORCEMENT_PROBE_DENY_REFUSED, ENFORCEMENT_PROBE_PROXY_UNREACHABLE, KEEPER_CONTAINER, KEEPER_SEEDED_MARKER, KUBERNETES_ISOLATION_ERROR, STORAGE_ROOT, WORKER_CONTAINER, assertRunNetworkPolicyMatches, assertRunPodMatches, buildCapabilitySecret, buildRunNetworkPolicy, buildRunPod, enforcementProbeScript, kubernetesRunNames, kubernetesRunNamesForToken, runLabels, validateKubernetesSpec, } from "./kubernetes-isolation.js";
|
|
37
37
|
import { readProxyWitness } from "./kubernetes-witness.js";
|
|
@@ -428,7 +428,7 @@ export class KubernetesJobLauncher {
|
|
|
428
428
|
if (phase === "failed" && !result.diagnostic) {
|
|
429
429
|
const diagnostic = await this.readWorkerDiagnostic(names);
|
|
430
430
|
if (diagnostic)
|
|
431
|
-
result = { ...result, diagnostic };
|
|
431
|
+
result = { ...result, ...diagnostic };
|
|
432
432
|
}
|
|
433
433
|
if (phase === "succeeded" && !result.resultArtifact) {
|
|
434
434
|
result = { ...result, resultArtifact: await this.readResultArtifact(names, record.runId) };
|
|
@@ -715,14 +715,9 @@ export class KubernetesJobLauncher {
|
|
|
715
715
|
return undefined;
|
|
716
716
|
}
|
|
717
717
|
for (const line of raw.split("\n").reverse()) {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
return value.error;
|
|
722
|
-
}
|
|
723
|
-
catch {
|
|
724
|
-
// Worker output is untrusted; only one fixed JSON shape is recognized.
|
|
725
|
-
}
|
|
718
|
+
const diagnostic = parseWorkerDiagnosticLine(line);
|
|
719
|
+
if (diagnostic)
|
|
720
|
+
return diagnostic;
|
|
726
721
|
}
|
|
727
722
|
return undefined;
|
|
728
723
|
}
|
|
@@ -45,6 +45,8 @@ export interface JobResult {
|
|
|
45
45
|
resultArtifact?: string;
|
|
46
46
|
/** Fixed worker-owned failure code; never raw container output. */
|
|
47
47
|
diagnostic?: string;
|
|
48
|
+
/** Output-schema failure locations (`path:code`) that passed SAFE_CODING_OUTPUT_ISSUE; never values. */
|
|
49
|
+
diagnosticIssues?: string[];
|
|
48
50
|
}
|
|
49
51
|
/**
|
|
50
52
|
* Lifecycle invariants implemented by every launcher:
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* schema.prisma). Every other operation goes through the normal Prisma
|
|
7
7
|
* Client since it never touches `contentTsv`.
|
|
8
8
|
*/
|
|
9
|
-
import type { PrismaClient } from "
|
|
9
|
+
import type { PrismaClient } from "#prisma";
|
|
10
10
|
import type { AgentMemorySearchHit, AgentMemoryStore } from "./types.js";
|
|
11
11
|
export type AgentMemoryDb = Pick<PrismaClient, "agentMemory" | "$executeRaw" | "$queryRaw">;
|
|
12
12
|
export declare class PostgresAgentMemory implements AgentMemoryStore {
|
|
@@ -2,6 +2,7 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { lstat, mkdir, opendir, readFile, readlink, realpath, rm } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, resolve, sep } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { ensurePrivateDirectory } from "../../core/private-directory.js";
|
|
5
6
|
import { MAX_REDACTED_SPAN, redactTokenShapedValues, normalizeGitHubRepository, normalizeGitRef, } from "../../coding/protocol.js";
|
|
6
7
|
import { isSafeGitHubInstallationToken } from "./github.js";
|
|
7
8
|
export const DEFAULT_MAX_CHANGED_FILES = 1_000;
|
|
@@ -220,7 +221,7 @@ export class GitVcsProvider {
|
|
|
220
221
|
}
|
|
221
222
|
async prepareWorkspace(input) {
|
|
222
223
|
const normalized = this.validateInput(input);
|
|
223
|
-
await
|
|
224
|
+
await ensurePrivateDirectory(this.rootDir);
|
|
224
225
|
await mkdir(resolve(this.rootDir, ".home"), { recursive: true, mode: 0o700 });
|
|
225
226
|
const runRoot = resolve(this.rootDir, normalized.runId);
|
|
226
227
|
if (!directChild(this.rootDir, runRoot))
|
package/dist/quickstart/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
2
|
import { createServer } from "node:net";
|
|
4
3
|
import { readFileSync, statSync } from "node:fs";
|
|
5
4
|
import { join } from "node:path";
|
|
@@ -7,12 +6,11 @@ import { fileURLToPath } from "node:url";
|
|
|
7
6
|
import { parseArgs } from "node:util";
|
|
8
7
|
import { createInterface } from "node:readline/promises";
|
|
9
8
|
import { composeProjectName, defaultModel, ensureWardbyIgnored, generatedSecret, providerKeyName, quickstartPaths, readQuickstartEnv, readQuickstartState, resolveProjectDir, writeQuickstartEnv, writeQuickstartState, } from "./config.js";
|
|
9
|
+
import { FETCH_NOTICE, migrateFailureReason, prismaMigrateInvocation, REGISTRY_FAILURE_MESSAGE, runPrismaMigrateInvocation, } from "./migrate.js";
|
|
10
10
|
const packageRoot = fileURLToPath(new URL("../../", import.meta.url));
|
|
11
11
|
const composeFile = join(packageRoot, "deploy/local/docker-compose.yml");
|
|
12
|
-
const schemaFile = join(packageRoot, "prisma/schema.prisma");
|
|
13
12
|
const wardbyBin = join(packageRoot, "bin/wardby.js");
|
|
14
13
|
const packageJson = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
15
|
-
const require = createRequire(import.meta.url);
|
|
16
14
|
const DEMO_AGENT = "hello-wardby";
|
|
17
15
|
const DEMO_PROMPT = "You are the Wardby quickstart agent. Reply with a short greeting, then explain in one sentence that Wardby admitted this run against an explicit maximum budget. Do not call tools.";
|
|
18
16
|
function runCommand(command, args, options = {}) {
|
|
@@ -200,22 +198,21 @@ async function chooseProvider(requested, previous, existing, nonInteractive) {
|
|
|
200
198
|
return "anthropic";
|
|
201
199
|
throw new Error(`Unknown provider selection "${answer}".`);
|
|
202
200
|
}
|
|
203
|
-
function prismaCliPath() {
|
|
204
|
-
return require.resolve("prisma/build/index.js");
|
|
205
|
-
}
|
|
206
201
|
function applyMigrations(paths) {
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
202
|
+
const invocation = prismaMigrateInvocation("deploy", runtimeEnv(paths));
|
|
203
|
+
if (!invocation.local)
|
|
204
|
+
console.log(FETCH_NOTICE);
|
|
205
|
+
const result = runPrismaMigrateInvocation(invocation, paths.projectDir);
|
|
206
|
+
if (result.registryFailure) {
|
|
207
|
+
const detail = /^npm (?:error|ERR!) code .*$/m.exec(result.stderr)?.[0] ?? result.stderr.trim().split("\n")[0];
|
|
208
|
+
throw new Error(`${REGISTRY_FAILURE_MESSAGE}${detail ? ` (${detail})` : ""}`);
|
|
209
|
+
}
|
|
211
210
|
if (result.status !== 0)
|
|
212
211
|
commandFailure("Database migration", result);
|
|
213
212
|
}
|
|
214
213
|
async function seedDemo(paths, state, budget) {
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
const { PrismaClient } = await import("@prisma/client");
|
|
218
|
-
const db = new PrismaClient();
|
|
214
|
+
const { createPrismaClient } = await import("../core/db.js");
|
|
215
|
+
const db = createPrismaClient(readQuickstartEnv(paths).DATABASE_URL);
|
|
219
216
|
try {
|
|
220
217
|
const existing = await db.agent.findUnique({ where: { name: DEMO_AGENT } });
|
|
221
218
|
if (existing && existing.systemPrompt !== DEMO_PROMPT) {
|
|
@@ -241,10 +238,6 @@ async function seedDemo(paths, state, budget) {
|
|
|
241
238
|
}
|
|
242
239
|
finally {
|
|
243
240
|
await db.$disconnect();
|
|
244
|
-
if (previousDatabaseUrl === undefined)
|
|
245
|
-
delete process.env.DATABASE_URL;
|
|
246
|
-
else
|
|
247
|
-
process.env.DATABASE_URL = previousDatabaseUrl;
|
|
248
241
|
}
|
|
249
242
|
}
|
|
250
243
|
function runDemo(paths) {
|
|
@@ -419,10 +412,8 @@ async function databaseHealthy(paths) {
|
|
|
419
412
|
const env = readQuickstartEnv(paths);
|
|
420
413
|
if (!env.DATABASE_URL)
|
|
421
414
|
return false;
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
const { PrismaClient } = await import("@prisma/client");
|
|
425
|
-
const db = new PrismaClient();
|
|
415
|
+
const { createPrismaClient } = await import("../core/db.js");
|
|
416
|
+
const db = createPrismaClient(env.DATABASE_URL);
|
|
426
417
|
try {
|
|
427
418
|
await db.$queryRawUnsafe("SELECT 1");
|
|
428
419
|
return true;
|
|
@@ -432,10 +423,6 @@ async function databaseHealthy(paths) {
|
|
|
432
423
|
}
|
|
433
424
|
finally {
|
|
434
425
|
await db.$disconnect();
|
|
435
|
-
if (previous === undefined)
|
|
436
|
-
delete process.env.DATABASE_URL;
|
|
437
|
-
else
|
|
438
|
-
process.env.DATABASE_URL = previous;
|
|
439
426
|
}
|
|
440
427
|
}
|
|
441
428
|
export async function doctorCommand(args) {
|
|
@@ -468,11 +455,15 @@ export async function doctorCommand(args) {
|
|
|
468
455
|
const ps = runCompose(paths, state, ["ps", "--status", "running", "--quiet"]);
|
|
469
456
|
checks.push(["PostgreSQL container", ps.status === 0 && ps.stdout.trim().length > 0]);
|
|
470
457
|
checks.push(["Database connection", await databaseHealthy(paths)]);
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
checks.push([
|
|
458
|
+
const invocation = prismaMigrateInvocation("status", runtimeEnv(paths));
|
|
459
|
+
if (!invocation.local)
|
|
460
|
+
console.log(FETCH_NOTICE);
|
|
461
|
+
const migrations = runPrismaMigrateInvocation(invocation, paths.projectDir);
|
|
462
|
+
checks.push([
|
|
463
|
+
"Database migrations",
|
|
464
|
+
migrations.status === 0,
|
|
465
|
+
migrations.status === 0 ? undefined : migrateFailureReason(migrations),
|
|
466
|
+
]);
|
|
476
467
|
}
|
|
477
468
|
let failed = false;
|
|
478
469
|
for (const [name, ok, detail] of checks) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const PRISMA_CLI_VERSION = "7.10.0";
|
|
2
|
+
export declare const FETCH_NOTICE = "Fetching the Prisma CLI (prisma@7.10.0)\u2026";
|
|
3
|
+
export declare const REGISTRY_FAILURE_MESSAGE: string;
|
|
4
|
+
export declare const migrateConfigFile: string;
|
|
5
|
+
export interface MigrateResult {
|
|
6
|
+
status: number;
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr: string;
|
|
9
|
+
registryFailure?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface MigrateInvocation {
|
|
12
|
+
command: string;
|
|
13
|
+
args: string[];
|
|
14
|
+
env: NodeJS.ProcessEnv;
|
|
15
|
+
local: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function parseLocalPrismaVersion(stdout: string): string | undefined;
|
|
18
|
+
export declare function probeLocalPrismaVersion(env: NodeJS.ProcessEnv): string | undefined;
|
|
19
|
+
export declare function prismaMigrateInvocation(subcommand: "deploy" | "status", env: NodeJS.ProcessEnv, probe?: (env: NodeJS.ProcessEnv) => string | undefined): MigrateInvocation;
|
|
20
|
+
export declare function classifyMigrateResult(result: MigrateResult, spawnError?: Error, local?: boolean): MigrateResult;
|
|
21
|
+
export declare function migrateFailureReason(result: MigrateResult): string;
|
|
22
|
+
export declare function runPrismaMigrateInvocation(invocation: MigrateInvocation, cwd: string): MigrateResult;
|
|
23
|
+
export declare function runPrismaMigrate(subcommand: "deploy" | "status", env: NodeJS.ProcessEnv, cwd: string, probe?: (env: NodeJS.ProcessEnv) => string | undefined): MigrateResult;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
// The installed npm package does not carry the Prisma CLI (a devDependency:
|
|
4
|
+
// its tree pulled advisories into every consumer install), so quickstart and
|
|
5
|
+
// doctor first look for a `prisma` executable on PATH and use it only if it
|
|
6
|
+
// reports exactly this version; anything else -- wrong version, not on PATH,
|
|
7
|
+
// a spawn error, a non-zero exit, or a timeout -- falls back to running the
|
|
8
|
+
// pinned version through npx, with a config file shipped in the package.
|
|
9
|
+
// Keep this equal to package.json's devDependencies.prisma (migrate.test.ts
|
|
10
|
+
// enforces it).
|
|
11
|
+
//
|
|
12
|
+
// Not supported on Windows: npx is `npx.cmd` there (and a local install would
|
|
13
|
+
// be `prisma.cmd`), which spawnSync can only run through a shell, and
|
|
14
|
+
// quickstart has no win32 handling anywhere else (Docker Compose paths,
|
|
15
|
+
// POSIX file modes) either.
|
|
16
|
+
export const PRISMA_CLI_VERSION = "7.10.0";
|
|
17
|
+
export const FETCH_NOTICE = `Fetching the Prisma CLI (prisma@${PRISMA_CLI_VERSION})…`;
|
|
18
|
+
export const REGISTRY_FAILURE_MESSAGE = `Could not download the Prisma CLI (prisma@${PRISMA_CLI_VERSION}) from the npm registry. ` +
|
|
19
|
+
"quickstart and doctor fetch it on demand. Check your internet connection or npm registry settings " +
|
|
20
|
+
"(.npmrc, proxy), then retry. You can also install it yourself " +
|
|
21
|
+
`(\`npm i -g prisma@${PRISMA_CLI_VERSION}\`) and rerun quickstart -- doctor benefits too.`;
|
|
22
|
+
export const migrateConfigFile = fileURLToPath(new URL("../../prisma/migrate.config.mjs", import.meta.url));
|
|
23
|
+
// A short timeout so a wedged or misbehaving local binary can't stall
|
|
24
|
+
// quickstart/doctor -- any hang past this falls back to npx.
|
|
25
|
+
const LOCAL_PRISMA_PROBE_TIMEOUT_MS = 5000;
|
|
26
|
+
// `prisma --version` prints a fixed-label, padded-column report, e.g.:
|
|
27
|
+
// prisma : 7.10.0
|
|
28
|
+
// @prisma/client : 7.10.0
|
|
29
|
+
// Operating System : darwin
|
|
30
|
+
// ...
|
|
31
|
+
// Several other lines carry their own version-shaped numbers (Node.js,
|
|
32
|
+
// TypeScript, the schema engine hash), so key off the "prisma" label
|
|
33
|
+
// specifically -- not the first x.y.z token anywhere in the output.
|
|
34
|
+
const LOCAL_VERSION_LINE = /^prisma\s*:\s*(\S+)$/m;
|
|
35
|
+
export function parseLocalPrismaVersion(stdout) {
|
|
36
|
+
return LOCAL_VERSION_LINE.exec(stdout)?.[1];
|
|
37
|
+
}
|
|
38
|
+
// Runs a local `prisma --version` under the given env's PATH and returns the
|
|
39
|
+
// version it reports, or undefined for anything that isn't a clean match:
|
|
40
|
+
// not on PATH, a spawn error, a non-zero exit, a timeout, or unparseable
|
|
41
|
+
// output. Never throws.
|
|
42
|
+
export function probeLocalPrismaVersion(env) {
|
|
43
|
+
const result = spawnSync("prisma", ["--version"], {
|
|
44
|
+
env,
|
|
45
|
+
encoding: "utf8",
|
|
46
|
+
stdio: "pipe",
|
|
47
|
+
timeout: LOCAL_PRISMA_PROBE_TIMEOUT_MS,
|
|
48
|
+
});
|
|
49
|
+
if (result.error || result.status !== 0)
|
|
50
|
+
return undefined;
|
|
51
|
+
return parseLocalPrismaVersion(result.stdout ?? "");
|
|
52
|
+
}
|
|
53
|
+
// DATABASE_URL travels in the child's environment only -- never argv, where
|
|
54
|
+
// any local user could read it from the process table. `probe` is injectable
|
|
55
|
+
// so tests never depend on the developer's real PATH.
|
|
56
|
+
export function prismaMigrateInvocation(subcommand, env, probe = probeLocalPrismaVersion) {
|
|
57
|
+
const childEnv = {
|
|
58
|
+
...env,
|
|
59
|
+
PRISMA_HIDE_UPDATE_MESSAGE: "1",
|
|
60
|
+
npm_config_update_notifier: "false",
|
|
61
|
+
npm_config_fund: "false",
|
|
62
|
+
};
|
|
63
|
+
if (probe(childEnv) === PRISMA_CLI_VERSION) {
|
|
64
|
+
return {
|
|
65
|
+
command: "prisma",
|
|
66
|
+
args: ["migrate", subcommand, "--config", migrateConfigFile],
|
|
67
|
+
env: childEnv,
|
|
68
|
+
local: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
command: "npx",
|
|
73
|
+
args: ["--yes", `prisma@${PRISMA_CLI_VERSION}`, "migrate", subcommand, "--config", migrateConfigFile],
|
|
74
|
+
env: childEnv,
|
|
75
|
+
local: false,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// npm's own error lines when it cannot fetch a package (npm 7+ prints
|
|
79
|
+
// "npm error", older "npm ERR!"): network failures and registry HTTP / version
|
|
80
|
+
// errors. A failed migration is printed by Prisma itself and never carries
|
|
81
|
+
// these -- in particular a database ECONNREFUSED is Prisma's P1001, not an
|
|
82
|
+
// "npm error code" line.
|
|
83
|
+
const REGISTRY_ERROR = /^npm (?:error|ERR!) (?:code|errno) (?:ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ETARGET|E[45]\d\d)\b|^npm (?:error|ERR!) network /m;
|
|
84
|
+
// `local` marks that `result`/`spawnError` came from the locally installed
|
|
85
|
+
// binary rather than npx: nothing was fetched, so neither an npm-shaped
|
|
86
|
+
// error line nor a spawn error is a registry failure there -- a spawn error
|
|
87
|
+
// still gets a clear message (below), just not that one.
|
|
88
|
+
export function classifyMigrateResult(result, spawnError, local = false) {
|
|
89
|
+
if (spawnError) {
|
|
90
|
+
if (local)
|
|
91
|
+
return { ...result, status: 1, stderr: spawnError.message };
|
|
92
|
+
return { ...result, status: 1, stderr: spawnError.message, registryFailure: true };
|
|
93
|
+
}
|
|
94
|
+
if (!local && result.status !== 0 && REGISTRY_ERROR.test(result.stderr))
|
|
95
|
+
return { ...result, registryFailure: true };
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
// The one-line reason for a failed run: the registry message, or Prisma's own
|
|
99
|
+
// first error line (URLs masked, though Prisma prints host and database only).
|
|
100
|
+
export function migrateFailureReason(result) {
|
|
101
|
+
if (result.registryFailure)
|
|
102
|
+
return REGISTRY_FAILURE_MESSAGE;
|
|
103
|
+
const lines = `${result.stderr}\n${result.stdout}`
|
|
104
|
+
.split("\n")
|
|
105
|
+
.map((line) => line.trim())
|
|
106
|
+
.filter(Boolean);
|
|
107
|
+
// A line that starts with "Error", or that carries a Prisma error code anywhere.
|
|
108
|
+
const line = lines.find((candidate) => candidate.startsWith("Error") || /\bP\d{4}\b/.test(candidate)) ?? lines[0] ?? "no output";
|
|
109
|
+
return line.replace(/postgres(ql)?:\/\/[^\s`'"]+/gi, "<database url>");
|
|
110
|
+
}
|
|
111
|
+
// Runs an already-resolved invocation (from `prismaMigrateInvocation`). Split
|
|
112
|
+
// out so callers can decide whether to print `FETCH_NOTICE` -- which only
|
|
113
|
+
// applies to the npx path -- before running it.
|
|
114
|
+
export function runPrismaMigrateInvocation(invocation, cwd) {
|
|
115
|
+
const result = spawnSync(invocation.command, invocation.args, {
|
|
116
|
+
cwd,
|
|
117
|
+
env: invocation.env,
|
|
118
|
+
encoding: "utf8",
|
|
119
|
+
stdio: "pipe",
|
|
120
|
+
});
|
|
121
|
+
return classifyMigrateResult({ status: result.status ?? 1, stdout: result.stdout ?? "", stderr: result.stderr ?? "" }, result.error, invocation.local);
|
|
122
|
+
}
|
|
123
|
+
export function runPrismaMigrate(subcommand, env, cwd, probe) {
|
|
124
|
+
return runPrismaMigrateInvocation(prismaMigrateInvocation(subcommand, env, probe), cwd);
|
|
125
|
+
}
|