diff --git a/packages/admin-cli/src/configure-providers.ts b/packages/admin-cli/src/configure-providers.ts index cec7092..9e5b3c0 100644 --- a/packages/admin-cli/src/configure-providers.ts +++ b/packages/admin-cli/src/configure-providers.ts @@ -5,11 +5,13 @@ import { validateProviderCredential } from "./provider-validation.js"; import { parseNumericMultiSelect, type Prompt } from "./prompt.js"; import { createTerminalPrompt } from "./prompt.js"; import { createWranglerClient, type WranglerClient } from "./wrangler.js"; +import { + createConsoleOutput, + safeErrorMessage, + type Output, +} from "./console-output.js"; -export interface Output { - log(message: string): void; - error(message: string): void; -} +export type { Output } from "./console-output.js"; export type ProviderValidator = ( provider: LLMProviderDefinition, @@ -71,7 +73,7 @@ async function promptForProviderSelection(prompt: Prompt, output: Output): Promi try { return parseNumericMultiSelect(response, LLM_PROVIDERS.length); } catch (error) { - output.error(getSafeErrorMessage(error)); + output.error(safeErrorMessage(error)); } } } @@ -134,18 +136,3 @@ async function validateSelection( } } } - -function createConsoleOutput(): Output { - return { - log(message) { - console.log(message); - }, - error(message) { - console.error(message); - }, - }; -} - -function getSafeErrorMessage(error: unknown): string { - return error instanceof Error ? error.message : "Unknown error."; -} diff --git a/packages/admin-cli/src/console-output.ts b/packages/admin-cli/src/console-output.ts new file mode 100644 index 0000000..9d2417c --- /dev/null +++ b/packages/admin-cli/src/console-output.ts @@ -0,0 +1,15 @@ +export interface Output { + log(message: string): void; + error(message: string): void; +} + +export function createConsoleOutput(): Output { + return { + log: (message) => console.log(message), + error: (message) => console.error(message), + }; +} + +export function safeErrorMessage(error: unknown): string { + return error instanceof Error ? error.message : "Unknown error."; +} diff --git a/packages/admin-cli/src/index.ts b/packages/admin-cli/src/index.ts index 0110eee..ada378b 100644 --- a/packages/admin-cli/src/index.ts +++ b/packages/admin-cli/src/index.ts @@ -1,4 +1,9 @@ -import { configureProviders, type Output } from "./configure-providers.js"; +import { configureProviders } from "./configure-providers.js"; +import { + createConsoleOutput, + safeErrorMessage, + type Output, +} from "./console-output.js"; import { createTerminalPrompt, PromptCancelledError, @@ -58,7 +63,7 @@ export async function runCli( return; } - output.error(getSafeErrorMessage(error)); + output.error(safeErrorMessage(error)); setExitCode(1); } } @@ -70,21 +75,6 @@ function printHelp(output: Output) { output.log(" --help, -h Show this help message"); } -function createConsoleOutput(): Output { - return { - log(message) { - console.log(message); - }, - error(message) { - console.error(message); - }, - }; -} - -function getSafeErrorMessage(error: unknown): string { - return error instanceof Error ? error.message : "Unknown error."; -} - if (isDirectExecution()) { await runCli(process.argv.slice(2)); } diff --git a/packages/cli/src/args.ts b/packages/cli/src/args.ts index 8bf4dbc..fe64194 100644 --- a/packages/cli/src/args.ts +++ b/packages/cli/src/args.ts @@ -182,19 +182,11 @@ function readOptionValue(argv: string[], index: number, option: string): string return value; } -function parsePositiveInteger(value: string, option: string): number { - const number = Number(value); - if (!Number.isInteger(number) || number <= 0) { - throw new Error(`${option} must be a positive integer`); - } - return number; -} - export function usage(): string { return [ "Usage:", " codevil init [--endpoint URL] [--api-key KEY] [--provider PROVIDER] [--plan-model MODEL] [--exec-model MODEL]", - " codevil run --repo REPO_URL [--provider PROVIDER] [--plan-model MODEL] [--exec-model MODEL] [--max-cost COST] [--max-time TIME] [--max-steps N] [--debug] ", + " codevil run --repo REPO_URL [--provider PROVIDER] [--plan-model MODEL] [--exec-model MODEL] [--max-time TIME] [--debug] ", " codevil models list [--provider PROVIDER]", " codevil models check /", ].join("\n"); diff --git a/packages/cli/src/config.ts b/packages/cli/src/config.ts index 3384111..c47c777 100644 --- a/packages/cli/src/config.ts +++ b/packages/cli/src/config.ts @@ -2,7 +2,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises"; import { homedir } from "node:os"; import { dirname, join } from "node:path"; -import { DEFAULT_CONFIG, type Config } from "@codevil/shared"; +import { DEFAULT_CONFIG, isRecord, type Config } from "@codevil/shared"; export interface ConfigPathOptions { home?: string; @@ -86,10 +86,6 @@ function validateConfig(value: unknown): Config { }; } -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null; -} - function isNodeError(error: unknown): error is NodeJS.ErrnoException { return error instanceof Error && "code" in error; } diff --git a/packages/cli/src/events.ts b/packages/cli/src/events.ts index 164cf6b..fc8b662 100644 --- a/packages/cli/src/events.ts +++ b/packages/cli/src/events.ts @@ -1,5 +1,6 @@ import type { DOToCLIEvent } from "@codevil/shared"; import { + isRecord, parseReplayEvent, ReplayBatchFrameSchema, SnapshotFrameSchema, @@ -147,7 +148,3 @@ function renderAgentEvent(event: unknown): string[] { } return ["Agent event received"]; } - -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null; -} diff --git a/packages/cli/src/models.ts b/packages/cli/src/models.ts index 1d45539..0531b88 100644 --- a/packages/cli/src/models.ts +++ b/packages/cli/src/models.ts @@ -30,15 +30,3 @@ export function checkAgentRunnableModel(providerId: string, modelId: string): bo return false; } } - -export function parseProviderModelRef(ref: string): { provider: string; modelId: string } { - const slash = ref.indexOf("/"); - if (slash <= 0 || slash === ref.length - 1) { - throw new Error(`Expected provider/model, got: ${ref}`); - } - - return { - provider: ref.slice(0, slash), - modelId: ref.slice(slash + 1), - }; -} diff --git a/packages/cli/src/session-client.ts b/packages/cli/src/session-client.ts index 9f500f7..9bd7a2e 100644 --- a/packages/cli/src/session-client.ts +++ b/packages/cli/src/session-client.ts @@ -1,4 +1,4 @@ -import type { Config } from "@codevil/shared"; +import { isRecord, type Config } from "@codevil/shared"; import type { RunCommand } from "./args.js"; @@ -82,7 +82,3 @@ export function buildWebSocketUrl(url: string, cursor: number): string { wsUrl.searchParams.set("cursor", cursor.toString()); return wsUrl.toString(); } - -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null; -} diff --git a/packages/cli/test/args.test.mjs b/packages/cli/test/args.test.mjs index 03b9c90..d6606f5 100644 --- a/packages/cli/test/args.test.mjs +++ b/packages/cli/test/args.test.mjs @@ -1,7 +1,7 @@ import assert from "node:assert/strict"; import test from "node:test"; -import { parseCommand } from "../dist/args.js"; +import { parseCommand, usage } from "../dist/args.js"; test("parses run command with repo, prompt, models, and time guard options", () => { const command = parseCommand([ @@ -71,3 +71,7 @@ test("rejects removed guard options", () => { /Unknown option: --max-cost/, ); }); + +test("usage omits removed guard options", () => { + assert.doesNotMatch(usage(), /--max-cost|--max-steps/); +}); diff --git a/packages/sandbox-image/src/dependency-cache.ts b/packages/sandbox-image/src/dependency-cache.ts index 0fcb166..6a7c506 100644 --- a/packages/sandbox-image/src/dependency-cache.ts +++ b/packages/sandbox-image/src/dependency-cache.ts @@ -267,18 +267,6 @@ function strategyFromMarker( }; } -function readPackageManager(packageJson: string): string | undefined { - try { - const parsed = JSON.parse(readFileSync(packageJson, "utf8")) as { - packageManager?: unknown; - }; - if (typeof parsed.packageManager !== "string") return undefined; - return parsed.packageManager.split("@", 1)[0]; - } catch { - return undefined; - } -} - function packageManifestHasInstallLifecycleScript(packageJson: string): boolean { try { const parsed = JSON.parse(readFileSync(packageJson, "utf8")) as { diff --git a/packages/sandbox-image/src/logging.ts b/packages/sandbox-image/src/logging.ts index ba5914a..030997e 100644 --- a/packages/sandbox-image/src/logging.ts +++ b/packages/sandbox-image/src/logging.ts @@ -14,11 +14,6 @@ export function setSandboxTraceFromSession(sessionId: string): void { bootstrapLogger.withSessionId(sessionId); } -export function setSandboxTraceId(traceId: string, sessionId?: string): void { - bootstrapLogger.withTraceId(traceId); - if (sessionId) bootstrapLogger.withSessionId(sessionId); -} - export function sandboxLogException( event: string, error: unknown, diff --git a/packages/sandbox-image/src/pi-cost.ts b/packages/sandbox-image/src/pi-cost.ts index a2b704b..a7a9e4e 100644 --- a/packages/sandbox-image/src/pi-cost.ts +++ b/packages/sandbox-image/src/pi-cost.ts @@ -33,8 +33,4 @@ export function costFromSessionStats(session: AgentSession): CostInfo { }; } -export function emptySessionCostSnapshot(): SessionCostSnapshot { - return { inputTokens: 0, outputTokens: 0, costUsd: 0 }; -} - export { zeroCost }; diff --git a/packages/sandbox-image/src/preview-manager.ts b/packages/sandbox-image/src/preview-manager.ts index b055ce4..dc634c5 100644 --- a/packages/sandbox-image/src/preview-manager.ts +++ b/packages/sandbox-image/src/preview-manager.ts @@ -1,7 +1,7 @@ -import { createServer, request as httpRequest } from "node:http"; +import { request as httpRequest } from "node:http"; import { spawn, type ChildProcess } from "node:child_process"; import { existsSync, readFileSync, readdirSync, statSync } from "node:fs"; -import { basename, dirname, join, relative, resolve } from "node:path"; +import { basename, join, relative, resolve } from "node:path"; import type { Readable } from "node:stream"; import type { PreviewApp, PreviewFramework } from "@codevil/shared"; @@ -265,17 +265,6 @@ export function detectPreviewApps(root: string): PreviewApp[] { return apps; } -/** - * Backward-compatible single-result wrapper kept for legacy callers and tests. - * Returns the first detected app's command (preferring root over subpackages). - */ -export function detectPreviewCommand(root: string): PreviewCommand | undefined { - const apps = detectPreviewApps(root); - if (apps.length === 0) return undefined; - const first = apps[0]; - return appToCommand(first, root); -} - export function appToCommand(app: PreviewApp, root: string): PreviewCommand { const relCwd = relativeCwd(root, app.cwd); const command: PreviewCommand = relCwd @@ -639,18 +628,3 @@ function withRecentLogs(message: string, recentLogs: string[]): string { function stripAnsi(text: string): string { return text.replace(/\[[0-9;?]*[ -/]*[@-~]/g, ""); } - -export function fakePreviewServer(port: number): Promise<{ close(): Promise }> { - const server = createServer((_req, res) => { - res.writeHead(200, { "content-type": "text/plain" }); - res.end("ok"); - }); - return new Promise((resolve, reject) => { - server.on("error", reject); - server.listen(port, "127.0.0.1", () => { - resolve({ - close: () => new Promise((closeResolve) => server.close(() => closeResolve())), - }); - }); - }); -} diff --git a/packages/sandbox-image/src/repo-setup.ts b/packages/sandbox-image/src/repo-setup.ts index 3af209c..77c4ac1 100644 --- a/packages/sandbox-image/src/repo-setup.ts +++ b/packages/sandbox-image/src/repo-setup.ts @@ -7,10 +7,8 @@ import { DEPENDENCY_ARTIFACT_FORMAT_VERSION, computeDependencyFingerprint, dependencyArtifactsPresent, - dependencyCleanExcludesForMarker, dependencyMarkerMatches, detectJavaScriptDependencyStrategy, - readDependencyArtifactMarker, removeDependencyArtifactMarker, removeJavaScriptDependencyArtifacts, repositoryHasInstallLifecycleScripts, diff --git a/packages/sandbox-image/src/runtime.ts b/packages/sandbox-image/src/runtime.ts index 3f19c75..b199100 100644 --- a/packages/sandbox-image/src/runtime.ts +++ b/packages/sandbox-image/src/runtime.ts @@ -23,7 +23,6 @@ import { import { readDependencyArtifactMarker, dependencyCleanExcludesForMarker, - type DependencyArtifactMarker, } from "./dependency-cache.js"; import { executePrompt, planPrompt, refinePrompt } from "./prompts.js"; import { parsePreviewSuggestion } from "./preview-parsers.js"; @@ -37,8 +36,6 @@ import { type Verifier, RepositoryVerifier, ShellCommandRunner, - detectSetupCommand, - detectVerificationCommand, runVerificationLoop, } from "./verification.js"; export { @@ -47,7 +44,7 @@ export { detectSetupCommand, detectVerificationCommand, } from "./verification.js"; -export { detectPreviewApps, detectPreviewCommand } from "./preview-manager.js"; +export { detectPreviewApps } from "./preview-manager.js"; export type { AgentStartOptions, diff --git a/packages/sandbox-image/test/runtime.test.mjs b/packages/sandbox-image/test/runtime.test.mjs index b52edb4..12f20a8 100644 --- a/packages/sandbox-image/test/runtime.test.mjs +++ b/packages/sandbox-image/test/runtime.test.mjs @@ -9,7 +9,6 @@ import { SandboxRuntime, ShellCommandRunner, detectPreviewApps, - detectPreviewCommand, detectSetupCommand, detectVerificationCommand, parsePreviewDiscovery, @@ -509,7 +508,7 @@ test("detectSetupCommand uses non-interactive npm install flags", async () => { } }); -test("detectPreviewCommand prefers Vite dev scripts and port 5173", async () => { +test("detectPreviewApps prefers Vite dev scripts and port 5173", async () => { const workspace = await mkdtemp(join(tmpdir(), "codevil-preview-vite-")); try { await writeFile(join(workspace, "package.json"), JSON.stringify({ @@ -518,7 +517,11 @@ test("detectPreviewCommand prefers Vite dev scripts and port 5173", async () => })); await writeFile(join(workspace, "pnpm-lock.yaml"), ""); - assert.deepEqual(detectPreviewCommand(workspace), { + assert.deepEqual(detectPreviewApps(workspace)[0], { + key: ".", + name: workspace.split("/").at(-1), + cwd: workspace, + framework: "vite", command: "pnpm dev -- --host 0.0.0.0 --port 5173", port: 5173, }); @@ -619,7 +622,7 @@ test("detectPreviewApps uses the root package manager for workspace apps", async } }); -test("detectPreviewCommand remaps Next.js away from port 3000", async () => { +test("detectPreviewApps remaps Next.js away from port 3000", async () => { const workspace = await mkdtemp(join(tmpdir(), "codevil-preview-next-")); try { await writeFile(join(workspace, "package.json"), JSON.stringify({ @@ -627,10 +630,13 @@ test("detectPreviewCommand remaps Next.js away from port 3000", async () => { dependencies: { next: "^15.0.0" }, })); - assert.deepEqual(detectPreviewCommand(workspace), { + assert.deepEqual(detectPreviewApps(workspace)[0], { + key: ".", + name: workspace.split("/").at(-1), + cwd: workspace, + framework: "next", command: "npm run dev -- --hostname 0.0.0.0 --port 3001", port: 3001, - readinessTimeoutMs: 120_000, }); } finally { await rm(workspace, { recursive: true, force: true }); diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 03b9dd0..a56db3b 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -384,7 +384,6 @@ export type { ActivityEntryStatus } from "./session-snapshot-schema.js"; export type { ProjectionContext, SessionSnapshot, - ProjectedSessionView, } from "./projections.js"; export { emptyPreviewState, @@ -401,8 +400,6 @@ export { reduceQuestions, mapEventToChat, mapEventToActivity, - projectEvent, - projectEvents, } from "./projections.js"; export { @@ -429,7 +426,6 @@ export type { ParseFailure } from "./wire-parsing.js"; export { parseReplayEvent, parseSessionSnapshot, - setParseFailureSink, } from "./wire-parsing.js"; export type { @@ -481,8 +477,6 @@ export type { SpanStatus, SpanOptions, Span, - EmittedSpan, - EmittedLog, TracerSink, Tracer, CreateTracerOptions, diff --git a/packages/shared/src/observability.ts b/packages/shared/src/observability.ts index 58f0b00..4ee414a 100644 --- a/packages/shared/src/observability.ts +++ b/packages/shared/src/observability.ts @@ -13,7 +13,6 @@ import { severityToOutcome, wideEventOutcomeFromStatus, type EmittedWideEvent, - type WideEventGroups, } from "./wide-event.js"; export type { @@ -61,12 +60,6 @@ export interface Span { end(): void; } -/** @deprecated Use EmittedWideEvent with record_type "span". */ -export type EmittedSpan = EmittedWideEvent; - -/** @deprecated Use EmittedWideEvent with record_type "point". */ -export type EmittedLog = EmittedWideEvent; - export type TracerSink = (line: EmittedWideEvent) => void; export interface CreateTracerOptions { @@ -129,7 +122,6 @@ class LiveSpan implements Span { private readonly _ctx: SpanContext; private readonly _name: string; private readonly _component: Component; - private readonly _kind: SpanKind; private readonly _parent?: SpanContext; private readonly _session_id?: string; private readonly _start: number; @@ -152,7 +144,6 @@ class LiveSpan implements Span { this._ctx = args.ctx; this._name = args.name; this._component = args.component; - this._kind = args.kind; this._parent = args.parent; this._session_id = args.session_id; this._sink = args.sink; diff --git a/packages/shared/src/projection-chat.ts b/packages/shared/src/projection-chat.ts index 8c0dd02..1b59b52 100644 --- a/packages/shared/src/projection-chat.ts +++ b/packages/shared/src/projection-chat.ts @@ -3,7 +3,6 @@ */ import type { DOToCLIEvent } from "./messages-cli.js"; -import { isRecord } from "./records.js"; import type { ChatMessage, ProjectionContext } from "./projection-types.js"; export function mapEventToChat(event: DOToCLIEvent, ctx: ProjectionContext): ChatMessage[] { @@ -234,7 +233,7 @@ export function mapEventToChat(event: DOToCLIEvent, ctx: ProjectionContext): Cha ]; case "agent_event": - return mapAgentEventToChat(event.event, ctx); + return []; case "plan_revision_frozen": return []; @@ -316,18 +315,6 @@ export function mapEventToChat(event: DOToCLIEvent, ctx: ProjectionContext): Cha } } -function mapAgentEventToChat(raw: unknown, ctx: ProjectionContext): ChatMessage[] { - if (!isRecord(raw) || typeof raw.type !== "string") return []; - - switch (raw.type) { - case "tool_execution_end": - case "message_update": - return []; - default: - return []; - } -} - export function appendProjectedChatMessages( messages: ChatMessage[], event: DOToCLIEvent, diff --git a/packages/shared/src/projections.ts b/packages/shared/src/projections.ts index 79d0998..9d6cfe4 100644 --- a/packages/shared/src/projections.ts +++ b/packages/shared/src/projections.ts @@ -7,14 +7,7 @@ */ import type { DOToCLIEvent } from "./messages-cli.js"; -import type { - ChatMessage, - ActivityEntry, - PreviewState, - PlanRevisionState, - QuestionViewModel, - ProjectionContext, -} from "./projection-types.js"; +import type { ProjectionContext } from "./projection-types.js"; import { emptyPreviewState, inferPhase, @@ -147,31 +140,3 @@ export function applyToChatActivity( activityLog: appendProjectedActivity(state.activityLog, event, ctx), }; } - -// --------------------------------------------------------------------------- -// Batch projection helpers (legacy event-mapper API) -// --------------------------------------------------------------------------- - -export interface ProjectedSessionView { - messages: ChatMessage[]; - activityLog: ActivityEntry[]; -} - -export function projectEvent( - state: ProjectedSessionView, - event: DOToCLIEvent, - ctx: ProjectionContext, -): ProjectedSessionView { - return { - messages: appendProjectedChatMessages(state.messages, event, ctx), - activityLog: appendProjectedActivity(state.activityLog, event, ctx), - }; -} - -export function projectEvents( - state: ProjectedSessionView, - events: DOToCLIEvent[], - ctx: ProjectionContext, -): ProjectedSessionView { - return events.reduce((s, e) => projectEvent(s, e, ctx), state); -} diff --git a/packages/shared/src/session-snapshot-schema.ts b/packages/shared/src/session-snapshot-schema.ts index 5e5d6bf..77c9f73 100644 --- a/packages/shared/src/session-snapshot-schema.ts +++ b/packages/shared/src/session-snapshot-schema.ts @@ -125,7 +125,6 @@ export const SessionSnapshotSchema = z.object({ }); export type ChatMessageRole = z.infer; -export type ChatMessageVariant = z.infer; export type ChatMessageMeta = z.infer; export type ChatMessage = z.infer; export type ActivityEntry = z.infer; diff --git a/packages/shared/src/wire-parsing.ts b/packages/shared/src/wire-parsing.ts index 3868bf1..24d89ef 100644 --- a/packages/shared/src/wire-parsing.ts +++ b/packages/shared/src/wire-parsing.ts @@ -18,7 +18,7 @@ export interface ParseFailure { type ParseFailureSink = (failure: ParseFailure) => void; -let failureSink: ParseFailureSink = (failure) => { +const failureSink: ParseFailureSink = (failure) => { emitLog({ severity: "ERROR", event: "parse_failure", @@ -30,10 +30,6 @@ let failureSink: ParseFailureSink = (failure) => { }); }; -export function setParseFailureSink(next: ParseFailureSink): void { - failureSink = next; -} - /** * Parse a persisted or replayed DO→CLI event. * Strict `DOToCLIEventSchema` first; lenient passthrough for legacy log rows. diff --git a/packages/shared/test/projections.test.mjs b/packages/shared/test/projections.test.mjs index f0e888f..40761b8 100644 --- a/packages/shared/test/projections.test.mjs +++ b/packages/shared/test/projections.test.mjs @@ -4,7 +4,6 @@ import test from "node:test"; import { mapEventToChat, mapEventToActivity, - projectEvent, applyToSessionSnapshot, applyToChatActivity, emptySessionSnapshot, @@ -187,17 +186,17 @@ test("mapEventToChat: maps verification_failed to a verification_failed message" }); // --------------------------------------------------------------------------- -// projectEvent +// applyToChatActivity // --------------------------------------------------------------------------- -test("projectEvent: coalesces streamed message updates into one thinking entry", () => { +test("applyToChatActivity: coalesces streamed message updates into one thinking entry", () => { const ctx = makeCtx(); - const first = projectEvent( + const first = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", event: { type: "message_update", content: "Analyzing " } }, ctx, ); - const second = projectEvent( + const second = applyToChatActivity( first, { type: "agent_event", event: { type: "message_update", content: "the repo." } }, ctx, @@ -208,14 +207,14 @@ test("projectEvent: coalesces streamed message updates into one thinking entry", assert.equal(second.activityLog[0].thinking?.text, "Analyzing the repo."); }); -test("projectEvent: updates a running tool entry when the matching tool ends", () => { +test("applyToChatActivity: updates a running tool entry when the matching tool ends", () => { const ctx = makeCtx(); - const started = projectEvent( + const started = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", event: { type: "tool_execution_start", tool: "bash", args: { command: "pnpm test" } } }, ctx, ); - const ended = projectEvent( + const ended = applyToChatActivity( started, { type: "agent_event", event: { type: "tool_execution_end", tool: "bash", args: { command: "pnpm test" }, result: "PASS", success: true } }, ctx, diff --git a/packages/web/src/lib/__tests__/event-mapper.test.ts b/packages/web/src/lib/__tests__/event-mapper.test.ts index a4112b2..3b7b2dd 100644 --- a/packages/web/src/lib/__tests__/event-mapper.test.ts +++ b/packages/web/src/lib/__tests__/event-mapper.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from "vitest"; -import { mapEventToChat, mapEventToActivity, projectEvent } from "@codevil/shared"; +import { applyToChatActivity, mapEventToChat, mapEventToActivity } from "@codevil/shared"; import type { ProjectionContext } from "@codevil/shared"; import type { DOToCLIEvent } from "@codevil/shared"; @@ -255,15 +255,15 @@ describe("mapEventToChat", () => { }); }); -describe("projectEvent", () => { +describe("applyToChatActivity", () => { it("coalesces streamed message updates into one thinking entry", () => { const ctx = makeCtx(); - const first = projectEvent( + const first = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", event: { type: "message_update", content: "Analyzing " } }, ctx, ); - const second = projectEvent( + const second = applyToChatActivity( first, { type: "agent_event", event: { type: "message_update", content: "the repo." } }, ctx, @@ -277,7 +277,7 @@ describe("projectEvent", () => { it("coalesces Pi assistant text deltas into one thinking entry", () => { const ctx = makeCtx(); - const first = projectEvent( + const first = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", @@ -288,7 +288,7 @@ describe("projectEvent", () => { }, ctx, ); - const second = projectEvent( + const second = applyToChatActivity( first, { type: "agent_event", @@ -305,7 +305,7 @@ describe("projectEvent", () => { }); it("keeps markdown heading deltas out of durable conversation messages", () => { - const projected = projectEvent( + const projected = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", @@ -326,7 +326,7 @@ describe("projectEvent", () => { }); it("keeps agent_end final assistant text in activity only", () => { - const projected = projectEvent( + const projected = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", @@ -345,7 +345,7 @@ describe("projectEvent", () => { }); it("does not promote agent_end text when a plan message exists", () => { - const projected = projectEvent( + const projected = applyToChatActivity( { messages: [ { @@ -375,12 +375,12 @@ describe("projectEvent", () => { it("updates a running tool entry when the matching tool ends", () => { const ctx = makeCtx(); - const started = projectEvent( + const started = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", event: { type: "tool_execution_start", tool: "bash", args: { command: "pnpm test" } } }, ctx, ); - const ended = projectEvent( + const ended = applyToChatActivity( started, { type: "agent_event", event: { type: "tool_execution_end", tool: "bash", args: { command: "pnpm test" }, result: "PASS", success: true } }, ctx, @@ -394,7 +394,7 @@ describe("projectEvent", () => { it("updates Pi tool events using toolCallId", () => { const ctx = makeCtx(); - const started = projectEvent( + const started = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", @@ -407,7 +407,7 @@ describe("projectEvent", () => { }, ctx, ); - const ended = projectEvent( + const ended = applyToChatActivity( started, { type: "agent_event", @@ -429,7 +429,7 @@ describe("projectEvent", () => { }); it("renders generic Pi lifecycle events in the activity pane", () => { - const projected = projectEvent( + const projected = applyToChatActivity( { messages: [], activityLog: [] }, { type: "agent_event", event: { type: "agent_start" } }, makeCtx(), diff --git a/packages/worker/src/http-handlers.ts b/packages/worker/src/http-handlers.ts index b96b4e9..79458a0 100644 --- a/packages/worker/src/http-handlers.ts +++ b/packages/worker/src/http-handlers.ts @@ -48,7 +48,7 @@ import { } from "./auth-redirect.js"; import { configuredWebOrigins, missingAuthConfigKeys } from "./auth-config.js"; import { createEmailProvider } from "./email.js"; -import { can, isRecord, type AuthAction, CreateInvitationRequestSchema, SetupClaimRequestSchema } from "@codevil/shared"; +import { can, type AuthAction, CreateInvitationRequestSchema, SetupClaimRequestSchema } from "@codevil/shared"; import { getCodevilSandbox, readSandboxDiagnostics, diff --git a/packages/worker/src/integrations/slack/actions.ts b/packages/worker/src/integrations/slack/actions.ts index 1c2f3c2..87c11a2 100644 --- a/packages/worker/src/integrations/slack/actions.ts +++ b/packages/worker/src/integrations/slack/actions.ts @@ -1,4 +1,5 @@ import { z } from "zod"; +import { isRecord } from "@codevil/shared"; import { workerLogForSession } from "../../logging.js"; import type { Env } from "../../worker-env.js"; import { @@ -240,7 +241,3 @@ function parseOrdinal(value: unknown): number | null { const parsed = Number(value); return Number.isSafeInteger(parsed) ? parsed : null; } - -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} diff --git a/packages/worker/src/integrations/store.ts b/packages/worker/src/integrations/store.ts index 46cbde3..912c412 100644 --- a/packages/worker/src/integrations/store.ts +++ b/packages/worker/src/integrations/store.ts @@ -1,4 +1,4 @@ -import type { SqlStatement } from "../session-directory.js"; +import type { SqlStatement } from "../sql.js"; import { externalParticipantId, diff --git a/packages/worker/src/invitations.ts b/packages/worker/src/invitations.ts index 0c2cea2..8648552 100644 --- a/packages/worker/src/invitations.ts +++ b/packages/worker/src/invitations.ts @@ -1,5 +1,6 @@ -import { AuthRoleSchema, can, type AuthRole } from "@codevil/shared"; -import { normalizeEmail, type InvitationRow, type SqlStatement } from "./memberships.js"; +import { can, type AuthRole } from "@codevil/shared"; +import { normalizeEmail, type InvitationRow } from "./memberships.js"; +import type { SqlStatement } from "./sql.js"; export const INVITATION_TTL_DAYS = 14; @@ -20,11 +21,6 @@ export function inviteExpiresAt(now: Date, ttlDays = INVITATION_TTL_DAYS): strin return new Date(now.getTime() + ttlDays * 24 * 60 * 60 * 1000).toISOString(); } -export function parseInviteRole(role: unknown): AuthRole | null { - const parsed = AuthRoleSchema.safeParse(role); - return parsed.success ? parsed.data : null; -} - export function canInviteRole(inviterRole: AuthRole, inviteRole: AuthRole): boolean { if (!can(inviterRole, "members:invite")) return false; return inviteRole !== "owner" || can(inviterRole, "members:invite-owner"); diff --git a/packages/worker/src/memberships.ts b/packages/worker/src/memberships.ts index 772f9c8..62d6c6d 100644 --- a/packages/worker/src/memberships.ts +++ b/packages/worker/src/memberships.ts @@ -1,9 +1,5 @@ import type { AuthRole } from "@codevil/shared"; - -export interface SqlStatement { - sql: string; - bindings: unknown[]; -} +import type { SqlStatement } from "./sql.js"; export interface MembershipRow { user_id: string; diff --git a/packages/worker/src/orchestrator.ts b/packages/worker/src/orchestrator.ts index 4164f4f..adc44e5 100644 --- a/packages/worker/src/orchestrator.ts +++ b/packages/worker/src/orchestrator.ts @@ -57,7 +57,6 @@ import { PHASE_SPAN_NAMES, SNAPSHOT_TERMINAL_EVENT_TYPES, } from "./orchestrator/types.js"; -import { traceSandboxProvisioning } from "./orchestrator/provisioning.js"; export { traceSandboxProvisioning } from "./orchestrator/provisioning.js"; import { proxyPreviewRequest } from "./orchestrator/preview.js"; import { diff --git a/packages/worker/src/orchestrator/preview.ts b/packages/worker/src/orchestrator/preview.ts index c69b09c..5a600ee 100644 --- a/packages/worker/src/orchestrator/preview.ts +++ b/packages/worker/src/orchestrator/preview.ts @@ -45,7 +45,7 @@ export function buildPreviewUrl(options: { return url.toString(); } -export function validatePreviewAccess(meta: SessionMeta, token: string): Response | null { +export function validatePreviewAccess(meta: SessionMeta): Response | null { if (!meta.preview_active || !meta.preview_port || !meta.preview_token_hash) { return new Response("Preview is not active.", { status: 404 }); } @@ -63,7 +63,7 @@ export async function proxyPreviewRequest( token: string, sandboxNamespace: DurableObjectNamespace, ): Promise { - const blocked = validatePreviewAccess(meta, token); + const blocked = validatePreviewAccess(meta); if (blocked) return blocked; const tokenHash = await hashPreviewToken(token); diff --git a/packages/worker/src/orchestrator/session-telemetry.ts b/packages/worker/src/orchestrator/session-telemetry.ts index e53830e..8145143 100644 --- a/packages/worker/src/orchestrator/session-telemetry.ts +++ b/packages/worker/src/orchestrator/session-telemetry.ts @@ -1,5 +1,4 @@ import type { SessionMeta } from "@codevil/shared"; -import type { WideEventGroups } from "@codevil/shared"; /** Session domain context for wide events — high-cardinality fields for debugging. */ export function sessionWideEventGroup(meta: SessionMeta): Record { @@ -20,7 +19,3 @@ export function sessionWideEventGroup(meta: SessionMeta): Record; - sessionId: string; - repo: string; -}): Promise { - const { getSandbox } = await import("@cloudflare/sandbox"); - const sandbox = getCodevilSandbox(getSandbox, input.binding, input.sessionId) as WorkspaceCacheSandbox; - return restoreLatestWorkspaceCache({ - db: input.db, - sandbox, - repo: input.repo, - }); -} - export async function createWorkspaceCacheSnapshotForSandbox(input: { db: D1Database; binding: DurableObjectNamespace; @@ -224,10 +204,6 @@ export async function createWorkspaceCacheSnapshotForSandbox(input: { }); } -export function workspaceBackupExcludes(): string[] { - return []; -} - function errorMessage(error: unknown): string { return error instanceof Error ? error.message : String(error); } diff --git a/packages/worker/test/workspace-cache.test.mjs b/packages/worker/test/workspace-cache.test.mjs index 35e783b..625dc3f 100644 --- a/packages/worker/test/workspace-cache.test.mjs +++ b/packages/worker/test/workspace-cache.test.mjs @@ -6,17 +6,12 @@ import { buildWorkspaceSnapshotInsert, latestWorkspaceSnapshotSelect, normalizeRepoCacheKey, - workspaceBackupExcludes, } from "../dist/workspace-cache.js"; test("workspace cache version changes when installed dependencies become snapshot artifacts", () => { assert.equal(WORKSPACE_CACHE_VERSION, "workspace-cache-v2"); }); -test("workspace backups include installed dependency artifacts", () => { - assert.deepEqual(workspaceBackupExcludes(), []); -}); - test("normalizeRepoCacheKey removes credentials and unstable URL suffixes", () => { assert.equal( normalizeRepoCacheKey("https://x-access-token:secret@github.com/Example/App.git/"),