Public: anyone can read this; the crew can change it.
The type check refuses unused imports and locals: `noUnusedLocals` is on in tsconfig.json and test/ is clean #4774
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/4741-the-type-check-refuses-unused-imports-an → main 2 commits fork
44 files
changed +28
−131
CLAUDE.md +1 −1
| @@ -60,7 +60,7 @@ canAdmin`), token scope (`readForm` floor + `minScope`), and branch | ||
| 60 | 60 | |
| 61 | 61 | sh |
| 62 | 62 | bun test # full suite — must stay green |
| 63 | bun x tsc --noEmit # zero type errors is the standard (strict, exact-optional) | |
| 63 | bun x tsc --noEmit # zero type errors is the standard (strict, exact-optional; an unused import or local fails it) | |
| 64 | 64 | bun run src/main.ts # boots on :3000, data in ./data |
| 65 | 65 | |
| 66 | 66 |
src/ssh/server.ts +1 −1
| @@ -75,7 +75,7 @@ class Connection { | ||
| 75 | 75 | constructor( |
| 76 | 76 | private readonly socket: Socket, |
| 77 | 77 | private readonly options: SshServerOptions, |
| 78 | private readonly hostKey: ReturnType<typeof loadOrCreateHostKey>, | |
| 78 | hostKey: ReturnType<typeof loadOrCreateHostKey>, | |
| 79 | 79 | private readonly onGone: (connection: Connection) => void, |
| 80 | 80 | ) { |
| 81 | 81 | const log = options.log; |
test/apps-adversarial-grants.test.ts +1 −1
| @@ -11,7 +11,7 @@ import { tmpdir } from "node:os"; | ||
| 11 | 11 | import { join } from "node:path"; |
| 12 | 12 | import { createApp, type App } from "../src/app.ts"; |
| 13 | 13 | import { AppsRuntime } from "../src/apps/runtime.ts"; |
| 14 | import { parseAppHost, signGrant, verifyGrant } from "../src/apps/proxy.ts"; | |
| 14 | import { signGrant, verifyGrant } from "../src/apps/proxy.ts"; | |
| 15 | 15 | import { newApp, updateAppSettings, type NewAppResult } from "../src/actions/apps.ts"; |
| 16 | 16 | import { listRuns, type Run } from "../src/core/runs.ts"; |
| 17 | 17 | import { createUser, type User } from "../src/core/users.ts"; |
test/apps-adversarial.test.ts −23
| @@ -60,33 +60,10 @@ import { | ||
| 60 | 60 | runLogListenerCount, |
| 61 | 61 | subscribeRunLog, |
| 62 | 62 | } from "../src/runs/log.ts"; |
| 63 | import { gitClientEnv } from "./helpers/git-client.ts"; | |
| 64 | 63 | import { portInsteadOfSocket } from "../src/git/hook-address.ts"; |
| 65 | 64 | |
| 66 | 65 | const testBySocket = portInsteadOfSocket() ? test.skip : test; |
| 67 | 66 | |
| 68 | const clientEnv = gitClientEnv({ | |
| 69 | GIT_AUTHOR_NAME: "Agent", | |
| 70 | GIT_AUTHOR_EMAIL: "[email protected]", | |
| 71 | GIT_COMMITTER_NAME: "Agent", | |
| 72 | GIT_COMMITTER_EMAIL: "[email protected]", | |
| 73 | }); | |
| 74 | ||
| 75 | async function sh(args: string[], cwd: string) { | |
| 76 | const proc = Bun.spawn(args, { | |
| 77 | cwd, | |
| 78 | env: clientEnv, | |
| 79 | stdout: "pipe", | |
| 80 | stderr: "pipe", | |
| 81 | }); | |
| 82 | const [out, err, code] = await Promise.all([ | |
| 83 | new Response(proc.stdout).text(), | |
| 84 | new Response(proc.stderr).text(), | |
| 85 | proc.exited, | |
| 86 | ]); | |
| 87 | return { code, out: out.trim(), err: err.trim() }; | |
| 88 | } | |
| 89 | ||
| 90 | 67 | // --------------------------------------------------------------------------- |
| 91 | 68 | // Pure units: no server, no filesystem beyond what the function itself does. |
| 92 | 69 | // --------------------------------------------------------------------------- |
test/apps-identity.test.ts +1 −1
| @@ -17,7 +17,7 @@ import { listEvents } from "../src/core/events.ts"; | ||
| 17 | 17 | import type { Repo } from "../src/core/repos.ts"; |
| 18 | 18 | import type { Run } from "../src/core/runs.ts"; |
| 19 | 19 | import type { User } from "../src/core/users.ts"; |
| 20 | import { serve, type Servers } from "../src/http/server.ts"; | |
| 20 | import type { Servers } from "../src/http/server.ts"; | |
| 21 | 21 | |
| 22 | 22 | import { identityKey } from "../src/apps/proxy.ts"; |
| 23 | 23 | /** The scaffold's suites that boot its real `serve`: a test that swaps in a toy server drops them. */ |
test/apps-open-host.test.ts +1 −8
| @@ -12,13 +12,10 @@ import { mkdtemp, rm } from "node:fs/promises"; | ||
| 12 | 12 | import { tmpdir } from "node:os"; |
| 13 | 13 | import { join } from "node:path"; |
| 14 | 14 | import { createApp, type App } from "../src/app.ts"; |
| 15 | import { newApp, updateAppSettings } from "../src/actions/apps.ts"; | |
| 15 | import { newApp } from "../src/actions/apps.ts"; | |
| 16 | 16 | import { AppsRuntime } from "../src/apps/runtime.ts"; |
| 17 | import { createToken } from "../src/core/tokens.ts"; | |
| 18 | 17 | import { createUser, type User } from "../src/core/users.ts"; |
| 19 | 18 | import { serve, type Servers } from "../src/http/server.ts"; |
| 20 | import type { Repo } from "../src/core/repos.ts"; | |
| 21 | import type { AppRecord } from "../src/core/apps.ts"; | |
| 22 | 19 | import { quietLogs } from "./helpers/globals.ts"; |
| 23 | 20 | |
| 24 | 21 | quietLogs(); |
| @@ -31,8 +28,6 @@ describe("/apps/open sends a grant only to a host that reads one way", () => { | ||
| 31 | 28 | let servers: Servers; |
| 32 | 29 | let runtime: AppsRuntime; |
| 33 | 30 | let alice: User; |
| 34 | let repo: Repo; | |
| 35 | let record: AppRecord; | |
| 36 | 31 | let aliceCookie = ""; |
| 37 | 32 | |
| 38 | 33 | const signIn = async (username: string): Promise<string> => { |
| @@ -72,8 +67,6 @@ describe("/apps/open sends a grant only to a host that reads one way", () => { | ||
| 72 | 67 | visibility: "public", |
| 73 | 68 | }); |
| 74 | 69 | if (!made.ok) throw new Error(String(made.error)); |
| 75 | repo = made.value.repo; | |
| 76 | record = made.value.app; | |
| 77 | 70 | }, 120_000); |
| 78 | 71 | |
| 79 | 72 | afterAll(async () => { |
test/apps-slow-test.test.ts −1
| @@ -7,7 +7,6 @@ | ||
| 7 | 7 | import { afterAll, beforeAll, describe, expect, test } from "bun:test"; |
| 8 | 8 | import type { App } from "../src/app.ts"; |
| 9 | 9 | import { AppsRuntime } from "../src/apps/runtime.ts"; |
| 10 | import { seconds } from "../src/apps/timing.ts"; | |
| 11 | 10 | import { mergePull, openPull } from "../src/actions/pulls.ts"; |
| 12 | 11 | import { commitToBranch } from "../src/actions/repos.ts"; |
| 13 | 12 | import type { AppRecord } from "../src/core/apps.ts"; |
test/apps.test.ts −1
| @@ -49,7 +49,6 @@ import { createUser, type User } from "../src/core/users.ts"; | ||
| 49 | 49 | import { serve, type Servers } from "../src/http/server.ts"; |
| 50 | 50 | import { readRunLog } from "../src/runs/log.ts"; |
| 51 | 51 | import { grantedCookie } from "./helpers/identity.ts"; |
| 52 | import { identityKey } from "../src/apps/proxy.ts"; | |
| 53 | 52 | import { |
| 54 | 53 | APPS_DOMAIN, |
| 55 | 54 | deploySettled, |
test/asks.test.ts −4
| @@ -18,15 +18,11 @@ import { createIssue } from "../src/core/issues.ts"; | ||
| 18 | 18 | import type { Repo } from "../src/core/repos.ts"; |
| 19 | 19 | import { claimRun, createRun, finishRun } from "../src/core/runs.ts"; |
| 20 | 20 | import { getUserByName } from "../src/core/users.ts"; |
| 21 | import { markVerified } from "../src/core/verify.ts"; | |
| 22 | 21 | import type { Ctx } from "../src/http/context.ts"; |
| 23 | 22 | import { serve, type Servers } from "../src/http/server.ts"; |
| 24 | 23 | import { setCapacity, storedCapacity } from "../src/core/capacity.ts"; |
| 25 | import { createOrigin } from "../src/core/origins.ts"; | |
| 26 | import { hunt } from "../src/crew/sentinel.ts"; | |
| 27 | 24 | import { decisionsFor } from "../src/web/studio/asks.ts"; |
| 28 | 25 | import { quietLogs } from "./helpers/globals.ts"; |
| 29 | import { promote } from "./helpers/members.ts"; | |
| 30 | 26 | import { adminCookie } from "./helpers/admin.ts"; |
| 31 | 27 | |
| 32 | 28 | quietLogs(); |
test/chain-timing.test.ts +1 −1
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | /** `/:owner/:name/following` names session, repo, chain, parent, upstream and render in Server-Timing (#3461). */ |
| 2 | import { afterAll, beforeAll, describe, expect, test } from "bun:test"; | |
| 2 | import { afterAll, beforeAll, expect, test } from "bun:test"; | |
| 3 | 3 | import { mkdtemp, rm } from "node:fs/promises"; |
| 4 | 4 | import { tmpdir } from "node:os"; |
| 5 | 5 | import { join } from "node:path"; |
test/crew-check-failed.test.ts +2 −8
| @@ -7,14 +7,12 @@ | ||
| 7 | 7 | import { afterAll, beforeAll, describe, expect, test } from "bun:test"; |
| 8 | 8 | import { readFileSync } from "node:fs"; |
| 9 | 9 | import type { App } from "../src/app.ts"; |
| 10 | import type { Repo } from "../src/core/repos.ts"; | |
| 11 | 10 | import type { User } from "../src/core/users.ts"; |
| 12 | 11 | import { addToCrew } from "../src/actions/crew.ts"; |
| 13 | 12 | import { assignIssue, openIssue } from "../src/actions/issues.ts"; |
| 14 | 13 | import { commitToBranch, createRepo } from "../src/actions/repos.ts"; |
| 15 | import { listRuns, type Run } from "../src/core/runs.ts"; | |
| 14 | import { listRuns } from "../src/core/runs.ts"; | |
| 16 | 15 | import { |
| 17 | agentRunSettled, | |
| 18 | 16 | startStandInCrew, |
| 19 | 17 | stopStandInCrew, |
| 20 | 18 | type StandInCrew, |
| @@ -25,15 +23,11 @@ describe("the crew, with a stand-in Claude Code: a failing check", () => { | ||
| 25 | 23 | let app: App; |
| 26 | 24 | let alice: User; |
| 27 | 25 | let bot: User; |
| 28 | let repo: Repo; | |
| 29 | 26 | let promptFile: string; |
| 30 | 27 | |
| 31 | const settled = (where: (run: Run) => boolean, timeoutMs?: number) => | |
| 32 | agentRunSettled(app, repo, where, timeoutMs); | |
| 33 | ||
| 34 | 28 | beforeAll(async () => { |
| 35 | 29 | standIn = await startStandInCrew({ tickMs: 50 }); |
| 36 | ({ app, alice, bot, repo, promptFile } = standIn); | |
| 30 | ({ app, alice, bot, promptFile } = standIn); | |
| 37 | 31 | }, 30_000); |
| 38 | 32 | |
| 39 | 33 | afterAll(() => stopStandInCrew(standIn)); |
test/crew-direction-autonomy.test.ts −1
| @@ -62,7 +62,6 @@ import { | ||
| 62 | 62 | import { struckOut } from "../src/crew/parks.ts"; |
| 63 | 63 | import { serve, type Servers } from "../src/http/server.ts"; |
| 64 | 64 | import { mapJson, marksFor } from "../src/web/pages/map.ts"; |
| 65 | import { listEvents } from "../src/core/events.ts"; | |
| 66 | 65 | import { quietLogs } from "./helpers/globals.ts"; |
| 67 | 66 | import { promote } from "./helpers/members.ts"; |
| 68 | 67 |
test/crew-direction-cap.test.ts −1
| @@ -28,7 +28,6 @@ describe("the direction is paced, not capped", () => { | ||
| 28 | 28 | let repo: Repo; |
| 29 | 29 | let direction: Issue; |
| 30 | 30 | const fresh = () => getRepoById(app.db, repo.id)!; |
| 31 | const hour = 60 * 60_000; | |
| 32 | 31 | |
| 33 | 32 | /** A finished planning pass, `ago` ms before now. */ |
| 34 | 33 | function pass(ago: number, state: "ok" | "failed" = "ok"): void { |
test/crew-early.test.ts +1 −3
| @@ -17,7 +17,6 @@ import { | ||
| 17 | 17 | setIssueState, |
| 18 | 18 | } from "../src/actions/issues.ts"; |
| 19 | 19 | import { pullOfBranch, watchForPull } from "../src/crew/early.ts"; |
| 20 | import type { CrewHandle } from "../src/crew/dispatch.ts"; | |
| 21 | 20 | import { resolveOid } from "../src/git/merge.ts"; |
| 22 | 21 | import { abortAgentRun } from "../src/crew/running.ts"; |
| 23 | 22 | import { getAgentByName } from "../src/core/agents.ts"; |
| @@ -39,7 +38,6 @@ describe("the crew, with a stand-in Claude Code: the early pull", () => { | ||
| 39 | 38 | let standIn: StandInCrew; |
| 40 | 39 | let dataDir: string; |
| 41 | 40 | let app: App; |
| 42 | let crew: CrewHandle; | |
| 43 | 41 | let alice: User; |
| 44 | 42 | let bot: User; |
| 45 | 43 | let repo: Repo; |
| @@ -49,7 +47,7 @@ describe("the crew, with a stand-in Claude Code: the early pull", () => { | ||
| 49 | 47 | |
| 50 | 48 | beforeAll(async () => { |
| 51 | 49 | standIn = await startStandInCrew(); |
| 52 | ({ dataDir, app, crew, alice, bot, repo } = standIn); | |
| 50 | ({ dataDir, app, alice, bot, repo } = standIn); | |
| 53 | 51 | }, 30_000); |
| 54 | 52 | |
| 55 | 53 | afterAll(() => stopStandInCrew(standIn)); |
test/decide.test.ts +1 −4
| @@ -11,13 +11,10 @@ import { join } from "node:path"; | ||
| 11 | 11 | import { createApp, type App } from "../src/app.ts"; |
| 12 | 12 | import { addToCrew, createAgent } from "../src/actions/crew.ts"; |
| 13 | 13 | import { openIssue } from "../src/actions/issues.ts"; |
| 14 | import { openPull } from "../src/actions/pulls.ts"; | |
| 15 | import { commitToBranch, createRepo } from "../src/actions/repos.ts"; | |
| 14 | import { createRepo } from "../src/actions/repos.ts"; | |
| 16 | 15 | import { listCrewRoles, setCrewRole } from "../src/core/agents.ts"; |
| 17 | 16 | import { getIssueById } from "../src/core/issues.ts"; |
| 18 | import type { Pull } from "../src/core/pulls.ts"; | |
| 19 | 17 | import type { Repo } from "../src/core/repos.ts"; |
| 20 | import { claimRun, createRun, finishRun } from "../src/core/runs.ts"; | |
| 21 | 18 | import { createUser, getUserByName, type User } from "../src/core/users.ts"; |
| 22 | 19 | import { |
| 23 | 20 | certain, |
test/edit-words.test.ts +1 −1
| @@ -23,7 +23,7 @@ import { commitToBranch, createRepo } from "../src/actions/repos.ts"; | ||
| 23 | 23 | import { createApp, type App } from "../src/app.ts"; |
| 24 | 24 | import { listEvents } from "../src/core/events.ts"; |
| 25 | 25 | import { getIssueById, type Issue } from "../src/core/issues.ts"; |
| 26 | import { getPull, openPullsClosing, type Pull } from "../src/core/pulls.ts"; | |
| 26 | import { openPullsClosing, type Pull } from "../src/core/pulls.ts"; | |
| 27 | 27 | import type { Repo } from "../src/core/repos.ts"; |
| 28 | 28 | import { submitReview } from "../src/core/reviews.ts"; |
| 29 | 29 | import { createToken } from "../src/core/tokens.ts"; |
test/file-modes.test.ts +1 −1
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | /** Host keys and database files are 0600; too-open ones are refused or named (#3025). */ |
| 2 | 2 | |
| 3 | import { afterAll, beforeAll, expect, test } from "bun:test"; | |
| 3 | import { afterAll, expect, test } from "bun:test"; | |
| 4 | 4 | import { chmodSync, mkdtempSync, rmSync, statSync, writeFileSync } from "node:fs"; |
| 5 | 5 | import { tmpdir } from "node:os"; |
| 6 | 6 | import { join } from "node:path"; |
test/finishing.test.ts +1 −2
| @@ -16,7 +16,7 @@ import { commitToBranch, createRepo } from "../src/actions/repos.ts"; | ||
| 16 | 16 | import { setCrewRole } from "../src/core/agents.ts"; |
| 17 | 17 | import { getIssueById, listComments, type Issue } from "../src/core/issues.ts"; |
| 18 | 18 | import type { Pull } from "../src/core/pulls.ts"; |
| 19 | import { getRepoById, type Repo } from "../src/core/repos.ts"; | |
| 19 | import type { Repo } from "../src/core/repos.ts"; | |
| 20 | 20 | import { submitReview } from "../src/core/reviews.ts"; |
| 21 | 21 | import { claimRun, finishRun, listRuns } from "../src/core/runs.ts"; |
| 22 | 22 | import { createUser, getUserByName, type User } from "../src/core/users.ts"; |
| @@ -33,7 +33,6 @@ let mason: User; | ||
| 33 | 33 | let repo: Repo; |
| 34 | 34 | let pull: Pull; |
| 35 | 35 | let ready: Issue; |
| 36 | const fresh = () => getRepoById(app.db, repo.id)!; | |
| 37 | 36 | const conflicts = () => |
| 38 | 37 | listRuns(app.db, repo.id, { kind: "agent" }).filter((r) => r.issueId === pull.id && r.reason === "conflict"); |
| 39 | 38 | const picked = () => listRuns(app.db, repo.id, { kind: "agent" }).filter((r) => r.issueId === ready.id); |
test/following.test.ts −1
| @@ -24,7 +24,6 @@ import { mergePull, openPull } from "../src/actions/pulls.ts"; | ||
| 24 | 24 | import { commitToBranch, createRepo, forkRepo } from "../src/actions/repos.ts"; |
| 25 | 25 | import { relationOf, takeUpdates } from "../src/actions/forks.ts"; |
| 26 | 26 | import { |
| 27 | convergeFork, | |
| 28 | 27 | convergeState, |
| 29 | 28 | convergeTitle, |
| 30 | 29 | followDivergence, |
test/front.test.ts +1 −1
| @@ -569,7 +569,7 @@ describe("the front page", () => { | ||
| 569 | 569 | }); |
| 570 | 570 | |
| 571 | 571 | test("never a letter tile: a pin without a stranger's picture, or one that is down, waits; the sweep wakes a pinned app asleep to picture it", async () => { |
| 572 | const bare = await make(admin, "pinned-bare", { picture: false }); | |
| 572 | await make(admin, "pinned-bare", { picture: false }); | |
| 573 | 573 | const down = await make(admin, "pinned-down"); |
| 574 | 574 | states.set(down.record.id, "failed"); |
| 575 | 575 | const sleepy = await make(admin, "pinned-sleepy", { picture: false }); |
test/hand-decider.test.ts +1 −1
| @@ -329,7 +329,7 @@ describe("let the decider answer a hand-over", () => { | ||
| 329 | 329 | test("the terminal's door: a parked row is on the On you card, D hands it over, U takes it back", async () => { |
| 330 | 330 | app.config.decider = standIn; |
| 331 | 331 | says = 0.9; |
| 332 | const issue = parked("tui card"); | |
| 332 | parked("tui card"); | |
| 333 | 333 | const terminal = headlessTerminal(140, 40); |
| 334 | 334 | const { app: ui } = createForgeApp( |
| 335 | 335 | app, |
test/looks.test.ts +3 −3
| @@ -22,13 +22,13 @@ import { commitToBranch, createRepo } from "../src/actions/repos.ts"; | ||
| 22 | 22 | import { envDataDir, previewEnv } from "../src/apps/data.ts"; |
| 23 | 23 | import { readGrant } from "../src/apps/proxy.ts"; |
| 24 | 24 | import { AppsRuntime } from "../src/apps/runtime.ts"; |
| 25 | import { getAppByRepo, type AppRecord } from "../src/core/apps.ts"; | |
| 25 | import type { AppRecord } from "../src/core/apps.ts"; | |
| 26 | 26 | import { listEvents } from "../src/core/events.ts"; |
| 27 | 27 | import { lookSlot, lookUrl, looksForEnv, recordLook, type Look } from "../src/core/looks.ts"; |
| 28 | 28 | import { decodePng, encodePng } from "../src/design/image/png.ts"; |
| 29 | 29 | import { setAppMembers } from "../src/core/app_members.ts"; |
| 30 | import { listPulls, type Pull } from "../src/core/pulls.ts"; | |
| 31 | import { getRepo, type Repo } from "../src/core/repos.ts"; | |
| 30 | import type { Pull } from "../src/core/pulls.ts"; | |
| 31 | import type { Repo } from "../src/core/repos.ts"; | |
| 32 | 32 | import { createRun, listRuns, type Run } from "../src/core/runs.ts"; |
| 33 | 33 | import { readLooks } from "../src/checks/looks.ts"; |
| 34 | 34 | import { vitalsRows } from "../src/checks/summary.ts"; |
test/mcp-upstream.test.ts −2
| @@ -73,8 +73,6 @@ describe("MCP proposes to the parent forge and lists proposals", () => { | ||
| 73 | 73 | return opened.value; |
| 74 | 74 | }; |
| 75 | 75 | |
| 76 | const forgeCount = (): number => | |
| 77 | child.db.query<{ n: number }, []>("SELECT COUNT(*) AS n FROM upstream_proposal").get()!.n; | |
| 78 | 76 | const parentPull = (number: number) => getPull(parent.db, lib.id, number)!; |
| 79 | 77 | |
| 80 | 78 | beforeAll(async () => { |
test/og-png.test.ts −2
| @@ -184,7 +184,6 @@ describe("og cards with a look", () => { | ||
| 184 | 184 | let servers: Servers; |
| 185 | 185 | let base: string; |
| 186 | 186 | let appId = ""; |
| 187 | let owner: { id: string }; | |
| 188 | 187 | |
| 189 | 188 | /** A 1280×800 page-like picture: bands and blocks, so it compresses as a screenshot does. */ |
| 190 | 189 | const screenshot = (hue: number): Uint8Array => { |
| @@ -224,7 +223,6 @@ describe("og cards with a look", () => { | ||
| 224 | 223 | adminIfFirst: true, |
| 225 | 224 | }); |
| 226 | 225 | if (!u.ok) throw new Error(u.error); |
| 227 | owner = u.value; | |
| 228 | 226 | const made = await createRepo(app, u.value, { name: "peek", visibility: "public" }); |
| 229 | 227 | if (!made.ok) throw new Error(String(made.error)); |
| 230 | 228 | const rec = createApp(app.db, { repoId: made.value.id, slug: "peek-app", access: "public" }); |
test/onboarding.test.ts +1 −2
| @@ -195,7 +195,6 @@ describe("a forge booted from a relative data dir still accepts pushes", () => { | ||
| 195 | 195 | let app: App; |
| 196 | 196 | let servers: Servers; |
| 197 | 197 | let port = 0; |
| 198 | let cookie = ""; | |
| 199 | 198 | |
| 200 | 199 | async function git(args: string[], cwd: string): Promise<number> { |
| 201 | 200 | const p = Bun.spawn(["git", ...args], { |
| @@ -218,7 +217,7 @@ describe("a forge booted from a relative data dir still accepts pushes", () => { | ||
| 218 | 217 | app = createApp({ dataDir, port: 0 }); |
| 219 | 218 | servers = await serve(app); |
| 220 | 219 | port = servers.port; |
| 221 | cookie = await adminCookie(app, { | |
| 220 | await adminCookie(app, { | |
| 222 | 221 | username: "rel", |
| 223 | 222 | email: "[email protected]", |
| 224 | 223 | password: "rel-secret", |
test/preview-spec.test.ts +1 −1
| @@ -6,7 +6,7 @@ import { tmpdir } from "node:os"; | ||
| 6 | 6 | import { join } from "node:path"; |
| 7 | 7 | import { createApp, type App } from "../src/app.ts"; |
| 8 | 8 | import { AppsRuntime } from "../src/apps/runtime.ts"; |
| 9 | import { checkPreview, previewSpec } from "../src/apps/preview_spec.ts"; | |
| 9 | import { previewSpec } from "../src/apps/preview_spec.ts"; | |
| 10 | 10 | import { newApp } from "../src/actions/apps.ts"; |
| 11 | 11 | import { openPull } from "../src/actions/pulls.ts"; |
| 12 | 12 | import { commitToBranch } from "../src/actions/repos.ts"; |
test/probes.test.ts +1 −1
| @@ -21,7 +21,7 @@ import { | ||
| 21 | 21 | untilNightly, |
| 22 | 22 | type ProbesHandle, |
| 23 | 23 | } from "../src/contract/probes.ts"; |
| 24 | import { getAppByRepo, type AppRecord } from "../src/core/apps.ts"; | |
| 24 | import type { AppRecord } from "../src/core/apps.ts"; | |
| 25 | 25 | import { listIssues } from "../src/core/issues.ts"; |
| 26 | 26 | import { getRepoById, type Repo } from "../src/core/repos.ts"; |
| 27 | 27 | import { listRuns } from "../src/core/runs.ts"; |
test/pull-variants.test.ts −24
| @@ -48,30 +48,6 @@ describe("a pull says its variant group and siblings", () => { | ||
| 48 | 48 | ...init, |
| 49 | 49 | headers: { ...auth, "content-type": "application/json" }, |
| 50 | 50 | })).json() as Promise<any>; |
| 51 | const mcp = async (name: string, args: unknown, as?: string) => { | |
| 52 | const res = await fetch(`${base}/mcp`, { | |
| 53 | method: "POST", | |
| 54 | headers: { | |
| 55 | "content-type": "application/json", | |
| 56 | accept: "application/json, text/event-stream", | |
| 57 | ...auth, | |
| 58 | ...(as ? { authorization: `Bearer ${as}` } : {}), | |
| 59 | }, | |
| 60 | body: JSON.stringify({ | |
| 61 | jsonrpc: "2.0", | |
| 62 | id: 1, | |
| 63 | method: "tools/call", | |
| 64 | params: { name, arguments: args }, | |
| 65 | }), | |
| 66 | }); | |
| 67 | const body = (await res.json()) as any; | |
| 68 | const text = body.result.content[0].text as string; | |
| 69 | try { | |
| 70 | return JSON.parse(text); | |
| 71 | } catch { | |
| 72 | return { error: text }; | |
| 73 | } | |
| 74 | }; | |
| 75 | 51 | const write = async (text: string, message: string) => { |
| 76 | 52 | await Bun.write(join(dir, "code.txt"), text); |
| 77 | 53 | await gitOk(["commit", "-am", message]); |
test/quotas-running.test.ts +2 −2
| @@ -7,7 +7,7 @@ | ||
| 7 | 7 | * for a named state or a flag file, never a guess at timing. |
| 8 | 8 | */ |
| 9 | 9 | |
| 10 | import { afterAll, beforeAll, describe, expect, test } from "bun:test"; | |
| 10 | import { describe, expect, test } from "bun:test"; | |
| 11 | 11 | import { chmodSync, existsSync, writeFileSync } from "node:fs"; |
| 12 | 12 | import { mkdtemp, rm } from "node:fs/promises"; |
| 13 | 13 | import { tmpdir } from "node:os"; |
| @@ -25,7 +25,7 @@ import { getRepo, type Repo } from "../src/core/repos.ts"; | ||
| 25 | 25 | import { createRun, listRuns, type Run } from "../src/core/runs.ts"; |
| 26 | 26 | import { createUser, type User } from "../src/core/users.ts"; |
| 27 | 27 | import { startCrew } from "../src/crew/dispatch.ts"; |
| 28 | import { serve, type Servers } from "../src/http/server.ts"; | |
| 28 | import { serve } from "../src/http/server.ts"; | |
| 29 | 29 | import { readRunLog } from "../src/runs/log.ts"; |
| 30 | 30 | import { QUOTA_KEYS, getQuota, runningLimitSentence, setQuota } from "../src/settings/quotas.ts"; |
| 31 | 31 | import { promote } from "./helpers/members.ts"; |
test/review-page.test.ts +1 −1
| @@ -9,7 +9,7 @@ import { addComment as addRawComment } from "../src/core/issues.ts"; | ||
| 9 | 9 | import { addCrew, createAgentRow, setCrewRole } from "../src/core/agents.ts"; |
| 10 | 10 | import { createRepo as createRepoRow } from "../src/core/repos.ts"; |
| 11 | 11 | import { submitReview } from "../src/core/reviews.ts"; |
| 12 | import { createUser, getUserByName } from "../src/core/users.ts"; | |
| 12 | import { createUser } from "../src/core/users.ts"; | |
| 13 | 13 | import { BREAKER_NOTE } from "../src/crew/breaker.ts"; |
| 14 | 14 | import { serve, type Servers } from "../src/http/server.ts"; |
| 15 | 15 | import { id } from "../src/kernel/id.ts"; |
test/sentinel.test.ts −3
| @@ -7,7 +7,6 @@ import { afterAll, beforeAll, describe, expect, test } from "bun:test"; | ||
| 7 | 7 | import { mkdtemp, rm } from "node:fs/promises"; |
| 8 | 8 | import { tmpdir } from "node:os"; |
| 9 | 9 | import { join } from "node:path"; |
| 10 | import keptIsAPersons from "../src/core/migrations/20261016120000-kept-is-a-person-s.ts"; | |
| 11 | 10 | import { quietLogs } from "./helpers/globals.ts"; |
| 12 | 11 | import { createApp, type App } from "../src/app.ts"; |
| 13 | 12 | import { createRepo } from "../src/actions/repos.ts"; |
| @@ -764,7 +763,6 @@ describe("a degraded incident whose issue closed as done", () => { | ||
| 764 | 763 | describe("a degraded finding whose cause has stayed closed", () => { |
| 765 | 764 | let hdir: string; |
| 766 | 765 | let happ: App; |
| 767 | let hrepo: Repo; | |
| 768 | 766 | let halice: User; |
| 769 | 767 | const T0 = Date.parse("2026-10-18T12:00:00.000Z"); |
| 770 | 768 | const plant = (cause: string, closedAt: number): void => { |
| @@ -782,7 +780,6 @@ describe("a degraded finding whose cause has stayed closed", () => { | ||
| 782 | 780 | halice = a.value; |
| 783 | 781 | const made = await createRepo(happ, halice, { name: "forge", visibility: "private" }); |
| 784 | 782 | if (!made.ok) throw new Error(String(made.error)); |
| 785 | hrepo = made.value; | |
| 786 | 783 | // Two incidents, both closed at T0; one will get a person's comment. |
| 787 | 784 | plant("drill", T0); |
| 788 | 785 | plant("disk", T0); |
test/signin-password-doors.test.ts −3
| @@ -19,20 +19,17 @@ const PASSWORD = "a-long-family-passphrase"; | ||
| 19 | 19 | const TRIES = 3; |
| 20 | 20 | |
| 21 | 21 | let dir = ""; |
| 22 | let app: App | undefined; | |
| 23 | 22 | let servers: Servers | undefined; |
| 24 | 23 | |
| 25 | 24 | afterEach(async () => { |
| 26 | 25 | servers?.stop(); |
| 27 | 26 | servers = undefined; |
| 28 | app = undefined; | |
| 29 | 27 | await rm(dir, { recursive: true, force: true }); |
| 30 | 28 | }); |
| 31 | 29 | |
| 32 | 30 | async function forge(): Promise<{ app: App; url: string }> { |
| 33 | 31 | dir = await mkdtemp(join(tmpdir(), "signin-doors-")); |
| 34 | 32 | const made = createApp({ dataDir: dir, port: 0 }); |
| 35 | app = made; | |
| 36 | 33 | servers = await serve(made); |
| 37 | 34 | const pat = await seedAdmin(made, { username: "pat", email: "[email protected]", password: PASSWORD }); |
| 38 | 35 | if (!pat.ok) throw new Error("setup"); |
test/signins.test.ts +1 −1
| @@ -273,7 +273,7 @@ describe("sign-ins: tokens and browsers, seen and ended", () => { | ||
| 273 | 273 | // `DELETE /api/v1/users/:username/tokens/:id`; this pull adds the browsers. |
| 274 | 274 | test("the owner does the same over the API, with an admin token", async () => { |
| 275 | 275 | const ownerToken = createToken(app.db, owner.id, "o", "admin").token; |
| 276 | const token = createToken(app.db, bo.id, "phone", "ro"); | |
| 276 | createToken(app.db, bo.id, "phone", "ro"); | |
| 277 | 277 | const browser = cookieFor(bo); |
| 278 | 278 | const seen = (await (await api("/api/v1/users/bo/signins", ownerToken)).json()) as { |
| 279 | 279 | tokens: { id: string; name: string }[]; |
test/studio-changes.test.ts −7
| @@ -49,13 +49,6 @@ describe("the studio, continued", () => { | ||
| 49 | 49 | headers: { cookie: `${cookie}; forge_mode=studio`, ...extra }, |
| 50 | 50 | redirect: "manual", |
| 51 | 51 | }); |
| 52 | const post = (path: string, body: Record<string, string>, extra = "") => | |
| 53 | fetch(`${base}${path}`, { | |
| 54 | method: "POST", | |
| 55 | headers: { cookie: `${cookie}${extra}`, origin: base }, | |
| 56 | body: new URLSearchParams(body), | |
| 57 | redirect: "manual", | |
| 58 | }); | |
| 59 | 52 | |
| 60 | 53 | beforeAll(async () => { |
| 61 | 54 | dataDir = await mkdtemp(join(tmpdir(), "forge-studio-")); |
test/studio-runs.test.ts −1
| @@ -57,7 +57,6 @@ import { | ||
| 57 | 57 | } from "../src/web/studio/words.ts"; |
| 58 | 58 | import { repoDir } from "../src/git/repos.ts"; |
| 59 | 59 | import { appendRunLog } from "../src/runs/log.ts"; |
| 60 | import { serving } from "./helpers/studio.ts"; | |
| 61 | 60 | |
| 62 | 61 | describe("the studio's slot count", () => { |
| 63 | 62 | let dataDir: string; |
test/studio-search.test.ts −1
| @@ -37,7 +37,6 @@ import { | ||
| 37 | 37 | } from "../src/core/runs.ts"; |
| 38 | 38 | import { createUser, getUserByName, type User } from "../src/core/users.ts"; |
| 39 | 39 | import { serve, type Servers } from "../src/http/server.ts"; |
| 40 | import { serving } from "./helpers/studio.ts"; | |
| 41 | 40 | import { promote } from "./helpers/members.ts"; |
| 42 | 41 | |
| 43 | 42 | describe("finding things in the studio: /search", () => { |
test/studio-shipping.test.ts −3
| @@ -29,7 +29,6 @@ import { | ||
| 29 | 29 | updateRepoSettings, |
| 30 | 30 | } from "../src/actions/repos.ts"; |
| 31 | 31 | import { recordDecision } from "../src/core/decisions.ts"; |
| 32 | import type { Issue } from "../src/core/issues.ts"; | |
| 33 | 32 | import { getPull, mergedPullCount, type Pull } from "../src/core/pulls.ts"; |
| 34 | 33 | import { getRepo, type Repo } from "../src/core/repos.ts"; |
| 35 | 34 | import { |
| @@ -37,7 +36,6 @@ import { | ||
| 37 | 36 | claimRun, |
| 38 | 37 | createRun, |
| 39 | 38 | finishRun, |
| 40 | listRuns, | |
| 41 | 39 | markServing, |
| 42 | 40 | previewLatency, |
| 43 | 41 | STOPPED_SUMMARY, |
| @@ -47,7 +45,6 @@ import { createUser, getUserByName, type User } from "../src/core/users.ts"; | ||
| 47 | 45 | import { serve, type Servers } from "../src/http/server.ts"; |
| 48 | 46 | import { NOBODY_ON_CREW } from "../src/web/studio/words.ts"; |
| 49 | 47 | import { servedPhrase } from "../src/web/ui.ts"; |
| 50 | import { serving } from "./helpers/studio.ts"; | |
| 51 | 48 | |
| 52 | 49 | describe("a stranger sees the app, not the owner's books", () => { |
| 53 | 50 | let dataDir: string; |
test/studio.test.ts −1
| @@ -34,7 +34,6 @@ import { | ||
| 34 | 34 | createRun, |
| 35 | 35 | finishRun, |
| 36 | 36 | noteRunProgress, |
| 37 | type Run, | |
| 38 | 37 | } from "../src/core/runs.ts"; |
| 39 | 38 | import { createUser, getUserByName, type User } from "../src/core/users.ts"; |
| 40 | 39 | import { CHECK_FAILED_LIMIT } from "../src/crew/dispatch.ts"; |
test/surfaces-adversarial.test.ts −2
| @@ -41,7 +41,6 @@ import { adminCookie } from "./helpers/admin.ts"; | ||
| 41 | 41 | |
| 42 | 42 | quietLogs(); |
| 43 | 43 | |
| 44 | const words = (html: string): string => html.replace(/\s+/g, " "); | |
| 45 | 44 | |
| 46 | 45 | // ============================================================================ |
| 47 | 46 | // Web |
| @@ -54,7 +53,6 @@ describe("surfaces adversarial: web", () => { | ||
| 54 | 53 | let base = ""; |
| 55 | 54 | let alice = ""; |
| 56 | 55 | let alicePassword = "alice-adversarial-pass"; |
| 57 | let hello: { id: string; ownerName: string; name: string }; | |
| 58 | 56 | |
| 59 | 57 | const web = ( |
| 60 | 58 | cookie: string, |
test/system-telemetry.test.ts +1 −1
| @@ -382,7 +382,7 @@ describe("telemetry:read: the owner grants it, an agent reads with it, nobody el | ||
| 382 | 382 | app.db.query("UPDATE user SET is_admin = 1 WHERE id = ?1").run(made.value.user.id); |
| 383 | 383 | const adminbot = getUserByName(app.db, "zadminbot")!; |
| 384 | 384 | expect(adminbot.isAdmin).toBe(true); |
| 385 | const token = createToken(app.db, adminbot.id, "t", "admin").token; | |
| 385 | createToken(app.db, adminbot.id, "t", "admin"); | |
| 386 | 386 | const flowCommand = () => { |
| 387 | 387 | const ctx = { push: () => {}, pop: () => {}, toast: () => {} } as unknown as Ctx; |
| 388 | 388 | const session = new Session(app, { sshUsername: "zadminbot", remoteAddress: "127.0.0.1", fingerprint: "SHA256:t", user: adminbot }); |
test/tui-widgets.test.ts +1 −1
| @@ -4,7 +4,7 @@ import { chord, binding, matches } from "../src/tui/app/keys.ts"; | ||
| 4 | 4 | import { rank, score } from "../src/tui/app/palette.ts"; |
| 5 | 5 | import type { KeyEvent } from "../src/tui/term/input.ts"; |
| 6 | 6 | import { Screen } from "../src/tui/term/screen.ts"; |
| 7 | import { PLAIN, style, UNDERLINE } from "../src/tui/term/style.ts"; | |
| 7 | import { style, UNDERLINE } from "../src/tui/term/style.ts"; | |
| 8 | 8 | import { renderDiff, renderFileDiff } from "../src/tui/ui/diff.ts"; |
| 9 | 9 | import { |
| 10 | 10 | center, |
test/view-source.test.ts −1
| @@ -15,7 +15,6 @@ import { | ||
| 15 | 15 | } from "../src/view/cache.ts"; |
| 16 | 16 | import { sourceFor, type RepoSource } from "../src/view/source.ts"; |
| 17 | 17 | import { |
| 18 | mirrorAndWait, | |
| 19 | 18 | newFakeState, |
| 20 | 19 | serveFakeForge, |
| 21 | 20 | type FakeForge, |
tsconfig.json +1
| @@ -12,6 +12,7 @@ | ||
| 12 | 12 | "exactOptionalPropertyTypes": true, |
| 13 | 13 | "noFallthroughCasesInSwitch": true, |
| 14 | 14 | "noImplicitOverride": true, |
| 15 | "noUnusedLocals": true, | |
| 15 | 16 | "verbatimModuleSyntax": true, |
| 16 | 17 | "skipLibCheck": true, |
| 17 | 18 | "noEmit": true |
new above
offline