From 4f74dd885c1a592bf87b189aba9c499ea203c8fe Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 02:54:05 +0000 Subject: [PATCH 1/8] chore(deps-rules): delete dead review address module and freeze core interiors Phase 0 of giving src/core an interior. Deletes core/review/address.ts (a speculative primitive whose only importer was its own test) and adds three boundary rules: no-dead-modules (any src/ module unreachable from a production entry point fails the check, with a shrink-only test-only allowlist), core-leaves-never-reimport-types (freezes the cycle fix so the extracted leaves can never import core/types.ts back), and the first per-module interior rule making core/review/reducer.ts importable only from within the review model. Also fixes core/watch/signature.ts to import CliInput from its leaf home, caught by the new freeze rule. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XcuayyxJrwQd9EHpuxNef1 --- .dependency-cruiser.cjs | 58 ++++++++++++ docs/browser-review-seam-audit.md | 4 + docs/module-boundaries.md | 39 ++++++-- src/core/review/address.test.ts | 99 --------------------- src/core/review/address.ts | 142 ------------------------------ src/core/watch/signature.ts | 2 +- 6 files changed, 95 insertions(+), 249 deletions(-) delete mode 100644 src/core/review/address.test.ts delete mode 100644 src/core/review/address.ts diff --git a/.dependency-cruiser.cjs b/.dependency-cruiser.cjs index 4500df97e..7e4ccf0ee 100644 --- a/.dependency-cruiser.cjs +++ b/.dependency-cruiser.cjs @@ -20,6 +20,31 @@ const UI_SESSION_ADAPTERS = [ "^src/ui/lib/reviewState\\.ts$", ]; +// Every way the shipped product is entered: the CLI, the highlight worker thread, the two +// published facades, and the skill generator. A module under src/ that no entry reaches, +// directly or transitively, is not in the product. +const PRODUCTION_ENTRY_POINTS = [ + "^src/main\\.tsx$", + "^src/highlightWorkerEntry\\.ts$", + "^src/opentui/index\\.ts$", + "^src/extension-api/index\\.ts$", + "^src/hunk-review/skillDocument\\.ts$", +]; + +// Modules kept alive by tests alone. The cruise excludes tests, so these look unreachable +// from the entry points while real coverage still depends on them. Shrink-only: an entry +// leaves when production reaches the module or the module goes; nothing is ever added +// without the coverage to justify it. +const TEST_ONLY_MODULES = [ + // Note-height measurement exercised by the review-conformance corpus. + "^src/core/review/noteSize\\.ts$", + // The floating agent-note popover and its measurement helper. Nothing renders them since + // notes moved into the diff flow as STML cards; their unit tests are the only consumers + // left, so they are quarantined here until that call is made rather than deleted blind. + "^src/ui/components/panes/AgentCard\\.tsx$", + "^src/ui/lib/agentPopover\\.ts$", +]; + module.exports = { forbidden: [ { @@ -94,6 +119,39 @@ module.exports = { from: { path: "^src/ui/", pathNot: UI_SESSION_ADAPTERS }, to: { path: "^src/(app|session)/" }, }, + { + name: "no-dead-modules", + comment: + "Every module under src/ earns its place by being reachable from an entry point. Dead files are worse than clutter: they still import, so they hold boundaries hostage and answer questions nobody asks. `orphan` only catches fully disconnected files, which misses dead code that still has dependencies — reachability catches both. A flagged module is either deleted or, if tests are its only real consumer, listed in TEST_ONLY_MODULES with a reason.", + severity: "error", + from: { path: PRODUCTION_ENTRY_POINTS }, + to: { + path: "^src/", + pathNot: [...PRODUCTION_ENTRY_POINTS, ...TEST_ONLY_MODULES], + reachable: false, + }, + }, + { + name: "core-leaves-never-reimport-types", + comment: + "Freezes the 2026-08 cycle fix. core/types.ts handed its changeset, command-input, sidecar, and file models to these leaves and now re-exports them for existing import sites; a leaf importing core/types.ts back would recreate the cycle that made the grab-bag and its members one module.", + severity: "error", + from: { + path: [ + "^src/core/(changeset|commandInputs|diffFile|sidecar)\\.ts$", + "^src/core/(vcs|watch|patch)/", + ], + }, + to: { path: "^src/core/types\\.ts$" }, + }, + { + name: "review-reducer-is-module-internal", + comment: + "The review reducer applies actions; callers state intent instead, so surfaces cannot reach past planReviewIntent into the transition table. First of the per-module interior rules — this establishes the mechanism later phases extend to the rest of src/core (identity.ts and the other named model modules stay public by design).", + severity: "error", + from: { path: "^src/", pathNot: "^src/core/review/" }, + to: { path: "^src/core/review/reducer\\.ts$" }, + }, { name: "packages-stay-standalone", comment: diff --git a/docs/browser-review-seam-audit.md b/docs/browser-review-seam-audit.md index daaefdb2b..8feccf15a 100644 --- a/docs/browser-review-seam-audit.md +++ b/docs/browser-review-seam-audit.md @@ -619,6 +619,10 @@ implementation does. carrying separators, percent signs, and non-ASCII characters, and strict rejection of anything outside the grammar. No consumers yet, by design — browser deep links are Phase 5 and opener fragments Phase 6, which is when this finding closes. + _Reopened (2026-08-17, module-boundaries phase 0)_: `core/review/address.ts` is deleted. A + primitive with no consumers cannot be checked against what its consumers need, and the + `no-dead-modules` rule now flags exactly that shape. The grammar above still stands as the + design; write it again beside the first consumer that addresses a review across a boundary. - **G4. User-facing error catalog.** The repo already solves this once for agents: `src/session/agent/errors.ts` single-sources every message the generated skill quotes, with contract tests. The browser has no equivalent — action rejections (`invalid-action`, diff --git a/docs/module-boundaries.md b/docs/module-boundaries.md index 54e4a58a4..1961c4950 100644 --- a/docs/module-boundaries.md +++ b/docs/module-boundaries.md @@ -44,9 +44,34 @@ Intentional exceptions, allowed by the rules: surface by design. - Tests are excluded: they are colocated and free to reach across boundaries. +## Module interiors + +Tier rules say which trees may reach each other; interior rules say which _files_ in a tree +outsiders may name. A module's interior is enforced the same way as a tier — one rule per +protected file, `from` everything outside the module's directory, `to` the file — so an +accidental reach-in fails `bun run deps:check` instead of quietly becoming API. + +Two supporting rules keep the interiors honest: + +- **`no-dead-modules`** flags any module under `src/` that no entry point reaches + (`main.tsx`, `highlightWorkerEntry.ts`, the `opentui` and `extension-api` facades, and the + skill generator). It uses `reachable: false` rather than `orphan`, which only catches fully + disconnected files and so misses dead code that still imports. A hit is deleted, or — when + tests are its only genuine consumer — listed in the rule's `TEST_ONLY_MODULES` allowlist + with the reason. That allowlist is **shrink-only**, like the baseline. +- **`core-leaves-never-reimport-types`** freezes the cycle fix below: the leaves extracted out + of `core/types.ts` may never import it back, even though it re-exports them. + +Phase 0 (2026-08-17) established the mechanism: it deleted `core/review/address.ts` (a +speculative primitive with no consumers), added the two rules above, and froze the first +interior — `core/review/reducer.ts` is importable only from within `core/review/`, because +callers state intent and `planReviewIntent` owns the transition. Later phases extend the same +pattern across `src/core` as its subdirectories take shape; the review model's named modules +(`document`, `identity`, `geometry`, `state`, …) stay public by design. + ## Snapshot (2026-08-17, v0.19.0) -332 production modules, 1283 internal edges, **zero boundary violations and zero import +331 production modules, 1282 internal edges, **zero boundary violations and zero import cycles** — the baseline is empty. The initial audit (2026-08-16) found 28 violations in five clusters and 5 file-level cycles; all were repaid in the same change series that introduced the rules: @@ -81,12 +106,12 @@ rules: The tier rules now hold with no exceptions. Two follow-ups are worth doing next: -1. **Give `src/core` an interior.** The subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, - `patch/`) are already coherent modules; the ~40 loose files at `core/*` root are the - grab-bag. Group them by audience (changeset model, config/CLI, process/runtime concerns) and - then add per-module rules restricting which files other tiers may import — the review seam's - named modules (`document`, `geometry`, `state`, …) stay public; their helpers become - internal. +1. **Give `src/core` an interior.** _Started (phase 0, see Module interiors)._ The + subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, `patch/`) are already coherent + modules; the ~40 loose files at `core/*` root are the grab-bag. Group them by audience + (changeset model, config/CLI, process/runtime concerns) and then add per-module rules + restricting which files other tiers may import — the review seam's named modules + (`document`, `geometry`, `state`, …) stay public; their helpers become internal. 2. **Tighten the adapter allowlist.** `ui-couples-to-session-via-adapters` currently allowlists six files. As session coupling consolidates into `useTerminalReview` / `useHunkSessionBridge`, shrink the list. diff --git a/src/core/review/address.test.ts b/src/core/review/address.test.ts deleted file mode 100644 index 62f3a7e35..000000000 --- a/src/core/review/address.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { describe, expect, test } from "bun:test"; -import { formatReviewAddress, parseReviewAddress, type ReviewAddress } from "./address"; - -/** Identifiers that have broken naive string formats: separators, percents, unicode. */ -const AWKWARD_IDENTIFIERS = [ - "sha256:abc123", - "user:1717171717-4", - "src/nested/path.ts#2", - "key with spaces", - "100% coverage", - "ünïcøde-ключ", - "a/b/c/d", - "?query=1&other=2", -]; - -describe("review address grammar", () => { - // Intent: the canonical form is stable, so a link a client wrote stays readable. - test("serializes each address kind to its documented form", () => { - expect(formatReviewAddress({ kind: "file", fileKey: "abc" })).toBe("file/abc"); - expect(formatReviewAddress({ kind: "hunk", fileKey: "abc", hunkIndex: 2 })).toBe( - "file/abc/hunk/2", - ); - expect(formatReviewAddress({ kind: "line", fileKey: "abc", side: "old", line: 41 })).toBe( - "file/abc/line/old/41", - ); - expect(formatReviewAddress({ kind: "note", fileKey: "abc", noteId: "user:1" })).toBe( - "file/abc/note/user%3A1", - ); - }); - - // Intent: identifiers are opaque, so no key or note id can break out of the grammar. - test("round-trips every address kind through awkward identifiers", () => { - for (const identifier of AWKWARD_IDENTIFIERS) { - const addresses: ReviewAddress[] = [ - { kind: "file", fileKey: identifier }, - { kind: "hunk", fileKey: identifier, hunkIndex: 0 }, - { kind: "hunk", fileKey: identifier, hunkIndex: 17 }, - { kind: "line", fileKey: identifier, side: "old", line: 1 }, - { kind: "line", fileKey: identifier, side: "new", line: 9001 }, - { kind: "note", fileKey: identifier, noteId: identifier }, - ]; - - for (const address of addresses) { - expect(parseReviewAddress(formatReviewAddress(address))).toEqual(address); - } - } - }); - - // Intent: canonical serialization must never produce text the strict parser rejects. - test("refuses values the address grammar cannot represent", () => { - const invalid: ReviewAddress[] = [ - { kind: "file", fileKey: "" }, - { kind: "hunk", fileKey: "abc", hunkIndex: -1 }, - { kind: "hunk", fileKey: "abc", hunkIndex: 1.5 }, - { kind: "hunk", fileKey: "abc", hunkIndex: Number.POSITIVE_INFINITY }, - { kind: "line", fileKey: "abc", side: "new", line: 0 }, - { kind: "line", fileKey: "abc", side: "new", line: -1 }, - { kind: "line", fileKey: "abc", side: "new", line: 1.5 }, - { kind: "line", fileKey: "abc", side: "left" as never, line: 1 }, - { kind: "note", fileKey: "abc", noteId: "" }, - ]; - - for (const address of invalid) { - expect(() => formatReviewAddress(address)).toThrow(); - } - expect(() => formatReviewAddress({ kind: "file", fileKey: "\ud800" })).toThrow( - "must be valid Unicode", - ); - }); - - // Intent: an address is untrusted input; a half-understood one must not navigate. - test("rejects anything that is not exactly the grammar", () => { - const rejected = [ - "", - "abc", - "file", - "file/", - "files/abc", - "file/abc/", - "file/abc/hunk", - "file/abc/hunk/", - "file/abc/hunk/-1", - "file/abc/hunk/1.5", - "file/abc/hunk/1/2", - "file/abc/line/new", - "file/abc/line/left/3", - "file/abc/line/new/0", - "file/abc/line/new/x", - "file/abc/note", - "file/abc/note/", - "file/abc/row/4", - "file/%zz/hunk/0", - ]; - - for (const text of rejected) { - expect(parseReviewAddress(text)).toBeUndefined(); - } - }); -}); diff --git a/src/core/review/address.ts b/src/core/review/address.ts deleted file mode 100644 index 9df0ebd95..000000000 --- a/src/core/review/address.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Semantic addresses: one grammar for pointing at a place in a review. - * - * Three consumers need to name a location across a boundary — a browser deep link and its - * history entries, a terminal "copy link" command, and agent surfaces that already address - * targets by file and hunk (`docs/browser-review-seam-audit.md`, G3). Without one grammar - * each would invent its own string format and they would stop understanding each other. - * - * Addresses are built from semantic keys only: a file key, a hunk index, a side and line, - * a note id. Never an index into rendered rows — those depend on layout, expansion state, - * and window width, so an address built from them means something different in the next - * client, or in the same client one keypress later. - * - * The serialized form is a slash-separated path with percent-encoded identifier segments, - * which makes it safe inside a URL fragment without further escaping. - */ -import type { ReviewSide } from "./types"; - -/** - * One addressable thing in a review, at the granularity the caller means. - * - * `file` and `hunk` name structure; `line` names a position in the content by side, which - * exists whether or not anything is anchored there; `note` names one anchored note by its - * id, which outlives the line it currently hangs from. - */ -export type ReviewAddress = - | { kind: "file"; fileKey: string } - | { kind: "hunk"; fileKey: string; hunkIndex: number } - | { kind: "line"; fileKey: string; side: ReviewSide; line: number } - | { kind: "note"; fileKey: string; noteId: string }; - -/** Encode one required identifier, rejecting values the address grammar cannot represent. */ -function encodeIdentifier(value: string, label: "file key" | "note id") { - if (value.length === 0) { - throw new TypeError(`Review address ${label} must not be empty.`); - } - - try { - return encodeURIComponent(value); - } catch { - // A lone surrogate cannot be percent-encoded into a URL-safe identifier. - throw new TypeError(`Review address ${label} must be valid Unicode.`); - } -} - -/** Format one integer segment the parser will accept. */ -function formatIndex(value: number, label: "hunk index" | "line", minimum: number) { - if (!Number.isSafeInteger(value) || value < minimum) { - throw new RangeError(`Review address ${label} must be an integer at least ${minimum}.`); - } - return String(value); -} - -/** Validate the line side that remains a runtime value at this public boundary. */ -function formatSide(side: ReviewSide) { - if (side !== "old" && side !== "new") { - throw new TypeError("Review address line side must be old or new."); - } - return side; -} - -/** Serialize one valid address into its canonical string form. */ -export function formatReviewAddress(address: ReviewAddress): string { - const file = `file/${encodeIdentifier(address.fileKey, "file key")}`; - switch (address.kind) { - case "file": - return file; - case "hunk": - return `${file}/hunk/${formatIndex(address.hunkIndex, "hunk index", 0)}`; - case "line": - return `${file}/line/${formatSide(address.side)}/${formatIndex(address.line, "line", 1)}`; - case "note": - return `${file}/note/${encodeIdentifier(address.noteId, "note id")}`; - } -} - -/** Decode one identifier segment, rejecting an empty or malformed one. */ -function decodeSegment(segment: string | undefined) { - if (!segment) { - return undefined; - } - try { - const decoded = decodeURIComponent(segment); - return decoded.length > 0 ? decoded : undefined; - } catch { - // A stray percent sign is a malformed address, not a key containing one. - return undefined; - } -} - -/** Parse one non-negative integer segment, rejecting anything else. */ -function parseIndex(segment: string | undefined, minimum: number) { - if (segment === undefined || !/^\d+$/.test(segment)) { - return undefined; - } - const value = Number(segment); - return Number.isSafeInteger(value) && value >= minimum ? value : undefined; -} - -/** - * Parse one address, or report that the text is not one. - * - * Deliberately strict: an address that arrived from a link, a fragment, or an agent - * command is untrusted input, and a half-understood one would silently navigate somewhere - * other than where it points. Anything that is not exactly this grammar is rejected. - */ -export function parseReviewAddress(text: string): ReviewAddress | undefined { - const segments = text.split("/"); - if (segments[0] !== "file") { - return undefined; - } - - const fileKey = decodeSegment(segments[1]); - if (fileKey === undefined) { - return undefined; - } - - if (segments.length === 2) { - return { kind: "file", fileKey }; - } - - switch (segments[2]) { - case "hunk": { - const hunkIndex = segments.length === 4 ? parseIndex(segments[3], 0) : undefined; - return hunkIndex === undefined ? undefined : { kind: "hunk", fileKey, hunkIndex }; - } - case "line": { - const side = segments[3]; - // Lines are 1-based everywhere in the model, so line 0 is not an address. - const line = segments.length === 5 ? parseIndex(segments[4], 1) : undefined; - return line === undefined || (side !== "old" && side !== "new") - ? undefined - : { kind: "line", fileKey, side, line }; - } - case "note": { - const noteId = segments.length === 4 ? decodeSegment(segments[3]) : undefined; - return noteId === undefined ? undefined : { kind: "note", fileKey, noteId }; - } - default: - return undefined; - } -} diff --git a/src/core/watch/signature.ts b/src/core/watch/signature.ts index 682645cbb..7e198a405 100644 --- a/src/core/watch/signature.ts +++ b/src/core/watch/signature.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import { resolve } from "node:path"; import { createVcsWatchSignature, getConfiguredVcsAdapter, operationFromInput } from "../vcs"; -import type { CliInput } from "../types"; +import type { CliInput } from "../commandInputs"; import type { VcsCatalog } from "../vcs/types"; /** Format one file stat into a stable signature fragment, or mark the path missing. */ From 612ac25e7a52335ecd88ebc6f003f4062209a01f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 03:07:28 +0000 Subject: [PATCH 2/8] refactor(core): group the changeset model and loaders into core/changeset/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 of giving src/core an interior. Twelve root files — the model, its patch-text builder, the loaders, and the file-level helpers — become one module with a declared surface: model, loaders, diffFile, fileSource, fileLanguage, binary, diffPaths, hunkHeader, and hunkSummary stay public, while fromPatch, sidecar, and fileLanguageLookup are enforced module-internal. Pure move: no exported symbol renamed, and core/types.ts keeps re-exporting the model for existing import sites. Also repoints the leaf-freeze rule at the moved paths so it keeps protecting the cycle fix. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XcuayyxJrwQd9EHpuxNef1 --- .dependency-cruiser.cjs | 13 ++++++- benchmarks/bootstrap-load.ts | 2 +- benchmarks/changeset-parse.ts | 2 +- benchmarks/working-tree-load.ts | 2 +- docs/browser-review-seam-audit.md | 2 +- docs/extension-system-exploration.md | 2 +- docs/module-boundaries.md | 38 ++++++++++++++----- docs/source-architecture.md | 6 ++- scripts/test-large-untracked-render.tsx | 2 +- src/app/review/producer.test.ts | 2 +- src/app/review/resourceStore.ts | 2 +- src/app/session/registration.ts | 2 +- src/app/sessionBootstrap.ts | 2 +- src/app/startup.ts | 4 +- src/core/{ => changeset}/binary.test.ts | 0 src/core/{ => changeset}/binary.ts | 0 src/core/{ => changeset}/diffFile.test.ts | 0 src/core/{ => changeset}/diffFile.ts | 2 +- src/core/{ => changeset}/diffPaths.ts | 0 src/core/{ => changeset}/fileLanguage.test.ts | 0 src/core/{ => changeset}/fileLanguage.ts | 0 .../{ => changeset}/fileLanguageLookup.ts | 0 src/core/{ => changeset}/fileSource.test.ts | 0 src/core/{ => changeset}/fileSource.ts | 4 +- .../fromPatch.ts} | 8 ++-- src/core/{ => changeset}/hunkHeader.test.ts | 0 src/core/{ => changeset}/hunkHeader.ts | 2 +- src/core/{ => changeset}/hunkSummary.test.ts | 10 ++--- src/core/{ => changeset}/hunkSummary.ts | 4 +- .../loaders.ordering.test.ts} | 6 +-- .../loaders.test.ts} | 19 ++++------ .../loaders.ts} | 14 +++---- src/core/{changeset.ts => changeset/model.ts} | 2 +- src/core/{ => changeset}/sidecar.test.ts | 0 src/core/{ => changeset}/sidecar.ts | 4 +- src/core/config.test.ts | 2 +- src/core/patch/chunks.ts | 2 +- src/core/patch/sanitize.ts | 2 +- src/core/review/selectors.ts | 2 +- src/core/types.ts | 4 +- src/core/vcs/types.ts | 4 +- src/core/vcs/untracked.ts | 6 +-- src/extensions/apply.test.ts | 2 +- src/extensions/apply.ts | 5 ++- src/extensions/events.ts | 2 +- src/extensions/vcsPatchResult.test.ts | 2 +- src/extensions/vcsPatchResult.ts | 4 +- src/opentui/model.ts | 6 +-- src/ui/AppHost.extension-dialogs.test.tsx | 2 +- src/ui/AppHost.extension-navigation.test.tsx | 2 +- src/ui/AppHost.extension-sidebar.test.tsx | 2 +- src/ui/AppHost.extensions.test.tsx | 2 +- src/ui/AppHost.file-view-modes.test.tsx | 2 +- src/ui/AppHost.interactions.test.tsx | 2 +- src/ui/AppHost.keybindings.test.tsx | 2 +- src/ui/AppHost.reload.test.tsx | 2 +- src/ui/AppHost.watch.test.tsx | 2 +- src/ui/AppHost.workspace.test.tsx | 2 +- src/ui/diff/diffRows.ts | 2 +- src/ui/hooks/useTerminalReview.test.tsx | 2 +- src/ui/hooks/useTerminalReview.ts | 2 +- src/ui/lib/extensionWorkspace.ts | 4 +- src/ui/lib/files.ts | 2 +- src/ui/staticDiffPager.ts | 2 +- test/helpers/diff-helpers.ts | 2 +- 65 files changed, 134 insertions(+), 101 deletions(-) rename src/core/{ => changeset}/binary.test.ts (100%) rename src/core/{ => changeset}/binary.ts (100%) rename src/core/{ => changeset}/diffFile.test.ts (100%) rename src/core/{ => changeset}/diffFile.ts (99%) rename src/core/{ => changeset}/diffPaths.ts (100%) rename src/core/{ => changeset}/fileLanguage.test.ts (100%) rename src/core/{ => changeset}/fileLanguage.ts (100%) rename src/core/{ => changeset}/fileLanguageLookup.ts (100%) rename src/core/{ => changeset}/fileSource.test.ts (100%) rename src/core/{ => changeset}/fileSource.ts (96%) rename src/core/{changesetFromPatch.ts => changeset/fromPatch.ts} (95%) rename src/core/{ => changeset}/hunkHeader.test.ts (100%) rename src/core/{ => changeset}/hunkHeader.ts (94%) rename src/core/{ => changeset}/hunkSummary.test.ts (91%) rename src/core/{ => changeset}/hunkSummary.ts (92%) rename src/core/{changesetLoaders.ordering.test.ts => changeset/loaders.ordering.test.ts} (92%) rename src/core/{changesetLoaders.test.ts => changeset/loaders.test.ts} (99%) rename src/core/{changesetLoaders.ts => changeset/loaders.ts} (97%) rename src/core/{changeset.ts => changeset/model.ts} (95%) rename src/core/{ => changeset}/sidecar.test.ts (100%) rename src/core/{ => changeset}/sidecar.ts (97%) diff --git a/.dependency-cruiser.cjs b/.dependency-cruiser.cjs index 7e4ccf0ee..f1f6da389 100644 --- a/.dependency-cruiser.cjs +++ b/.dependency-cruiser.cjs @@ -138,7 +138,8 @@ module.exports = { severity: "error", from: { path: [ - "^src/core/(changeset|commandInputs|diffFile|sidecar)\\.ts$", + "^src/core/changeset/(model|diffFile|sidecar)\\.ts$", + "^src/core/commandInputs\\.ts$", "^src/core/(vcs|watch|patch)/", ], }, @@ -152,6 +153,16 @@ module.exports = { from: { path: "^src/", pathNot: "^src/core/review/" }, to: { path: "^src/core/review/reducer\\.ts$" }, }, + { + name: "changeset-internals-stay-in-module", + comment: + "core/changeset owns the changeset model and the pipeline that acquires one. Outsiders name the model, the loaders, and the per-file helpers they build on (model, loaders, diffFile, fileSource, fileLanguage, binary, diffPaths, hunkHeader, hunkSummary); the patch-to-model parse, the Pierre extension-table lookup, and the sidecar reader are steps inside that pipeline, reached through the loaders instead.", + severity: "error", + from: { path: "^src/", pathNot: "^src/core/changeset/" }, + to: { + path: "^src/core/changeset/(fromPatch|fileLanguageLookup|sidecar)\\.ts$", + }, + }, { name: "packages-stay-standalone", comment: diff --git a/benchmarks/bootstrap-load.ts b/benchmarks/bootstrap-load.ts index ddf33fff7..95c709318 100644 --- a/benchmarks/bootstrap-load.ts +++ b/benchmarks/bootstrap-load.ts @@ -6,7 +6,7 @@ import { join } from "node:path"; import { performance } from "perf_hooks"; import { parsePatchFiles } from "@pierre/diffs"; import { getBundledVcsCatalog } from "../src/app/vcsCatalog"; -import { loadAppBootstrap } from "../src/core/changesetLoaders"; +import { loadAppBootstrap } from "../src/core/changeset/loaders"; const FILE_COUNT = 64; const LINES_PER_FILE = 420; diff --git a/benchmarks/changeset-parse.ts b/benchmarks/changeset-parse.ts index add4a8b8a..a090f999b 100644 --- a/benchmarks/changeset-parse.ts +++ b/benchmarks/changeset-parse.ts @@ -1,7 +1,7 @@ // Benchmark raw patch parsing and sanitized DiffFile construction for several diff shapes. import { performance } from "perf_hooks"; import { parsePatchFiles } from "@pierre/diffs"; -import { buildDiffFile } from "../src/core/diffFile"; +import { buildDiffFile } from "../src/core/changeset/diffFile"; import { findPatchChunk, splitPatchIntoFileChunks } from "../src/core/patch/chunks"; import { sanitizePatchText } from "../src/core/patch/sanitize"; import { createSyntheticPatch } from "./lib/fixtures"; diff --git a/benchmarks/working-tree-load.ts b/benchmarks/working-tree-load.ts index 7d700ca80..d8156cdef 100644 --- a/benchmarks/working-tree-load.ts +++ b/benchmarks/working-tree-load.ts @@ -1,7 +1,7 @@ // Benchmark git-backed working-tree loading, including untracked file handling. import { performance } from "perf_hooks"; import { getBundledVcsCatalog } from "../src/app/vcsCatalog"; -import { loadAppBootstrap } from "../src/core/changesetLoaders"; +import { loadAppBootstrap } from "../src/core/changeset/loaders"; import { addUntrackedFiles, createChangedRepo } from "./lib/fixtures"; interface Scenario { diff --git a/docs/browser-review-seam-audit.md b/docs/browser-review-seam-audit.md index 8feccf15a..67eabf7a3 100644 --- a/docs/browser-review-seam-audit.md +++ b/docs/browser-review-seam-audit.md @@ -134,7 +134,7 @@ whether a client needs more than that is Phase 5's first question. _Repaid (Phase 1 PR 2)_: `reviewDefaultHunkLineTarget` in `core/review/geometry.ts`; `firstCommentTargetForHunk` deleted and both terminal callers converted; every geometry fixture pins the target, `pure-deletion-hunk` and `hunk-with-leading-context` adversarially. -- **A11. Language registration side effect missing in browser.** `core/fileLanguage.ts` +- **A11. Language registration side effect missing in browser.** `core/changeset/fileLanguage.ts` registers `.mts`/`.cts`; the web bundle never imports it, so Pierre's own inference runs unregistered for files without an explicit `language`. Fix: side-effect import in `src/web/main.tsx` (or fold registration into the shared model). diff --git a/docs/extension-system-exploration.md b/docs/extension-system-exploration.md index e8adeed38..acf83b697 100644 --- a/docs/extension-system-exploration.md +++ b/docs/extension-system-exploration.md @@ -117,7 +117,7 @@ seams in very different states of readiness: - Dynamic theme registration exists (`ensureSyntaxHighlightThemeRegistered` → Pierre's `registerCustomTheme`), but the config layer caps custom themes at one `"custom"` slot. -- Pierre's `setCustomExtension` (`src/core/fileLanguage.ts`) is already used at +- Pierre's `setCustomExtension` (`src/core/changeset/fileLanguage.ts`) is already used at import time for `.mts`/`.cts`; extending it to plugin-declared mappings is trivial. - `StartupDeps` (`src/app/startup.ts`) fully injects the startup pipeline diff --git a/docs/module-boundaries.md b/docs/module-boundaries.md index 1961c4950..7fe53ab72 100644 --- a/docs/module-boundaries.md +++ b/docs/module-boundaries.md @@ -69,6 +69,24 @@ callers state intent and `planReviewIntent` owns the transition. Later phases ex pattern across `src/core` as its subdirectories take shape; the review model's named modules (`document`, `identity`, `geometry`, `state`, …) stay public by design. +Phase 1 (2026-08-17) grouped the changeset model and its acquisition pipeline — twelve loose +files at `core/*` root — into `core/changeset/`, with the surface split enforced by +`changeset-internals-stay-in-module`: + +- **Public:** `model` (the `Changeset` / `DiffFile` / `SidecarContext` shapes), `loaders` + (every input source, plus the app bootstrap built around one), `diffFile`, `fileSource`, + `fileLanguage`, `binary`, `diffPaths`, `hunkHeader`, `hunkSummary`. +- **Interior:** `fromPatch` turns patch text into the model and is reached through `loaders`; + `fileLanguageLookup` is the only reader/writer of Pierre's process-global extension table + and the import that drags in the diff engine; `sidecar` reads `--agent-context` as one step + of acquiring a changeset. + +The renames are path-only — `changeset.ts` → `changeset/model.ts`, `changesetLoaders.ts` → +`changeset/loaders.ts`, `changesetFromPatch.ts` → `changeset/fromPatch.ts`, the rest keep their +basenames — and no exported symbol changed. `core/types.ts` still re-exports the changeset and +sidecar shapes for legacy import sites; it names `changeset/model`, which is public, so the +interior rule needs no exception. `core/patch/` stayed where it is: it was already coherent. + ## Snapshot (2026-08-17, v0.19.0) 331 production modules, 1282 internal edges, **zero boundary violations and zero import @@ -77,9 +95,10 @@ clusters and 5 file-level cycles; all were repaid in the same change series that rules: - **Cycles.** Each cycle was a type-only back-edge from a lower module into a grab-bag above - it. The cuts: `core/types.ts` gave its changeset model to `core/changeset.ts` and its - command-input model to `core/commandInputs.ts` (re-exported from `core/types` so import - sites keep working); the diff row model moved to `ui/diff/diffRowModel.ts`; the worker's + it. The cuts: `core/types.ts` gave its changeset model to `core/changeset.ts` (since phase 1, + `core/changeset/model.ts`) and its command-input model to `core/commandInputs.ts` (re-exported + from `core/types` so import sites keep working); the diff row model moved to + `ui/diff/diffRowModel.ts`; the worker's compact encoder was retyped structurally (`HighlightedHastLines`); `HunkSessionBrokerClient` moved beside the client class it aliases; `CopySelectedRowRange` moved into `ui/lib/diffSpatial.ts`; `extensions/notifications.ts` now imports `ExtensionNotifyType` @@ -106,12 +125,13 @@ rules: The tier rules now hold with no exceptions. Two follow-ups are worth doing next: -1. **Give `src/core` an interior.** _Started (phase 0, see Module interiors)._ The - subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, `patch/`) are already coherent - modules; the ~40 loose files at `core/*` root are the grab-bag. Group them by audience - (changeset model, config/CLI, process/runtime concerns) and then add per-module rules - restricting which files other tiers may import — the review seam's named modules - (`document`, `geometry`, `state`, …) stay public; their helpers become internal. +1. **Give `src/core` an interior.** _In progress (phases 0–1, see Module interiors)._ The + subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, `patch/`, and now `changeset/`) are + coherent modules; the loose files still at `core/*` root are the remaining grab-bag. Keep + grouping them by audience — config/CLI next, then the process/runtime concerns — and give + each group a rule restricting which of its files other tiers may import. The review seam's + named modules (`document`, `geometry`, `state`, …) stay public; their helpers become + internal. 2. **Tighten the adapter allowlist.** `ui-couples-to-session-via-adapters` currently allowlists six files. As session coupling consolidates into `useTerminalReview` / `useHunkSessionBridge`, shrink the list. diff --git a/docs/source-architecture.md b/docs/source-architecture.md index bb7498d7f..818e5d5b3 100644 --- a/docs/source-architecture.md +++ b/docs/source-architecture.md @@ -9,8 +9,10 @@ Use it when adding a new module or deciding where an existing responsibility bel ```text src/app/ executable composition: CLI parsing, startup plans, and shared session bootstrap src/app/session/ mounted-review registration, bridge, and reload authorization -src/core/ normalized review model, loading, patch handling, VCS contracts, - configuration, and runtime primitives +src/core/ review model, patch handling, VCS contracts, configuration, and + runtime primitives +src/core/changeset/ the changeset model and the pipeline that acquires one: loaders, + per-file construction, sidecar/source reads, and hunk formatting src/core/theme/ bundled theme metadata, custom-theme rules, and terminal theme detection src/core/watch/ input signatures, observation plans/backends, and refresh coordination src/core/vcs/ provider-neutral VCS catalog, contracts, operation dispatch, and host support diff --git a/scripts/test-large-untracked-render.tsx b/scripts/test-large-untracked-render.tsx index c35034441..fecb6ce89 100644 --- a/scripts/test-large-untracked-render.tsx +++ b/scripts/test-large-untracked-render.tsx @@ -3,7 +3,7 @@ import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { act } from "react"; -import { loadAppBootstrap } from "../src/core/changesetLoaders"; +import { loadAppBootstrap } from "../src/core/changeset/loaders"; import { AppHost } from "../src/ui/AppHost"; function runGit(cwd: string, ...args: string[]) { diff --git a/src/app/review/producer.test.ts b/src/app/review/producer.test.ts index c9baeaac4..11458cfd8 100644 --- a/src/app/review/producer.test.ts +++ b/src/app/review/producer.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; import { createTestDiffFile, lines } from "../../../test/helpers/diff-helpers"; -import { SourceTextTooLargeError } from "../../core/fileSource"; +import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; import { parseReviewGeneration } from "../../core/review/generationOrder"; import { MAX_REVIEW_SOURCE_RESOURCE_BYTES, diff --git a/src/app/review/resourceStore.ts b/src/app/review/resourceStore.ts index 236d95861..423e5a3d5 100644 --- a/src/app/review/resourceStore.ts +++ b/src/app/review/resourceStore.ts @@ -18,7 +18,7 @@ * The store belongs to one publication, so a new generation starts with nothing cached and * the previous generation's bytes become collectable as soon as it is retired. */ -import { SourceTextTooLargeError } from "../../core/fileSource"; +import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; import { isMaterializedReviewResource, isReviewResourceRange, diff --git a/src/app/session/registration.ts b/src/app/session/registration.ts index 933c93bbf..2b86e322c 100644 --- a/src/app/session/registration.ts +++ b/src/app/session/registration.ts @@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto"; import { spawnSync } from "node:child_process"; import { resolveExperimentalFeatures } from "../../core/experimental"; import { isVcsReviewInput } from "../../core/vcs"; -import { summarizeHunk } from "../../core/hunkSummary"; +import { summarizeHunk } from "../../core/changeset/hunkSummary"; import { reviewHunkRanges } from "../../core/review/geometry"; import { reviewProcessCapability } from "../review/capability"; import type { ReviewPublication } from "../review/publication"; diff --git a/src/app/sessionBootstrap.ts b/src/app/sessionBootstrap.ts index 4ec391c03..45647f461 100644 --- a/src/app/sessionBootstrap.ts +++ b/src/app/sessionBootstrap.ts @@ -3,7 +3,7 @@ import { isVcsReviewInput } from "../core/vcs"; import type { VcsCatalog } from "../core/vcs/types"; import { getBundledVcsCatalog } from "./vcsCatalog"; import { collectSessionCustomThemes } from "../core/theme/customThemes"; -import { loadAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap } from "../core/changeset/loaders"; import type { CliInput } from "../core/types"; import type { AppBootstrap } from "./types"; import { diff --git a/src/app/startup.ts b/src/app/startup.ts index d927b13c4..73c6befc3 100644 --- a/src/app/startup.ts +++ b/src/app/startup.ts @@ -3,7 +3,7 @@ import { createExtensionApplyNotices, createUnknownVcsNotice } from "../extensio import type { loadStartupExtensions } from "../extensions/startup"; import { resolveConfiguredCliInput } from "../core/config"; import { HunkUserError } from "../core/errors"; -import type { loadAppBootstrap } from "../core/changesetLoaders"; +import type { loadAppBootstrap } from "../core/changeset/loaders"; import { looksLikePatchInput } from "../core/pager"; import { detectTerminalThemeModeFromBackground } from "../core/theme/detection"; import { @@ -318,7 +318,7 @@ export async function prepareStartupPlan( import("../extensions/startup"), ]); const loadAppBootstrapImpl = - deps.loadAppBootstrapImpl ?? (await import("../core/changesetLoaders")).loadAppBootstrap; + deps.loadAppBootstrapImpl ?? (await import("../core/changeset/loaders")).loadAppBootstrap; const loadStartupExtensionsImpl = deps.loadStartupExtensionsImpl ?? startupExtensions.loadStartupExtensions; diff --git a/src/core/binary.test.ts b/src/core/changeset/binary.test.ts similarity index 100% rename from src/core/binary.test.ts rename to src/core/changeset/binary.test.ts diff --git a/src/core/binary.ts b/src/core/changeset/binary.ts similarity index 100% rename from src/core/binary.ts rename to src/core/changeset/binary.ts diff --git a/src/core/diffFile.test.ts b/src/core/changeset/diffFile.test.ts similarity index 100% rename from src/core/diffFile.test.ts rename to src/core/changeset/diffFile.test.ts diff --git a/src/core/diffFile.ts b/src/core/changeset/diffFile.ts similarity index 99% rename from src/core/diffFile.ts rename to src/core/changeset/diffFile.ts index ce477aae3..cd944c9aa 100644 --- a/src/core/diffFile.ts +++ b/src/core/changeset/diffFile.ts @@ -4,7 +4,7 @@ import { patchLooksBinary } from "./binary"; import { fileLanguageForPath } from "./fileLanguageLookup"; import { normalizeDiffMetadataPaths, normalizeDiffPath } from "./diffPaths"; import type { FileSourceFetcher } from "./fileSource"; -import type { DiffFile, DiffLineMoveKinds, SidecarContext } from "./changeset"; +import type { DiffFile, DiffLineMoveKinds, SidecarContext } from "./model"; /** Count visible additions and deletions from parsed diff metadata. */ export function countDiffStats(metadata: FileDiffMetadata) { diff --git a/src/core/diffPaths.ts b/src/core/changeset/diffPaths.ts similarity index 100% rename from src/core/diffPaths.ts rename to src/core/changeset/diffPaths.ts diff --git a/src/core/fileLanguage.test.ts b/src/core/changeset/fileLanguage.test.ts similarity index 100% rename from src/core/fileLanguage.test.ts rename to src/core/changeset/fileLanguage.test.ts diff --git a/src/core/fileLanguage.ts b/src/core/changeset/fileLanguage.ts similarity index 100% rename from src/core/fileLanguage.ts rename to src/core/changeset/fileLanguage.ts diff --git a/src/core/fileLanguageLookup.ts b/src/core/changeset/fileLanguageLookup.ts similarity index 100% rename from src/core/fileLanguageLookup.ts rename to src/core/changeset/fileLanguageLookup.ts diff --git a/src/core/fileSource.test.ts b/src/core/changeset/fileSource.test.ts similarity index 100% rename from src/core/fileSource.test.ts rename to src/core/changeset/fileSource.test.ts diff --git a/src/core/fileSource.ts b/src/core/changeset/fileSource.ts similarity index 96% rename from src/core/fileSource.ts rename to src/core/changeset/fileSource.ts index a2e28486b..b654fdfd8 100644 --- a/src/core/fileSource.ts +++ b/src/core/changeset/fileSource.ts @@ -1,6 +1,6 @@ -import { DEFAULT_SOURCE_TEXT_MAX_BYTES, readFileTextWithLimit } from "../lib/sourceText"; +import { DEFAULT_SOURCE_TEXT_MAX_BYTES, readFileTextWithLimit } from "../../lib/sourceText"; -export { DEFAULT_SOURCE_TEXT_MAX_BYTES } from "../lib/sourceText"; +export { DEFAULT_SOURCE_TEXT_MAX_BYTES } from "../../lib/sourceText"; /** * Generic full-file source fetcher primitives used by input loaders and VCS adapters. diff --git a/src/core/changesetFromPatch.ts b/src/core/changeset/fromPatch.ts similarity index 95% rename from src/core/changesetFromPatch.ts rename to src/core/changeset/fromPatch.ts index ff388fb5e..897a3feae 100644 --- a/src/core/changesetFromPatch.ts +++ b/src/core/changeset/fromPatch.ts @@ -3,7 +3,7 @@ * * Every input mode converges here: a VCS spawn, a two-file comparison, and a patch read from * disk or stdin all end up as text, and this module is the one that turns text into - * `DiffFile`s. Keeping it apart from `changesetLoaders.ts` keeps the parse pure — the + * `DiffFile`s. Keeping it apart from `loaders.ts` keeps the parse pure — the * loaders own the I/O, this owns the model. * * Moved-line capture has to run before sanitizing: Git marks moved lines only through SGR @@ -11,9 +11,9 @@ */ import { parsePatchFiles } from "@pierre/diffs"; import { buildDiffFile, type BuildDiffFileOptions } from "./diffFile"; -import { splitPatchIntoFileChunks, findPatchChunk } from "./patch/chunks"; -import { sanitizePatch, stripTerminalControl } from "./patch/sanitize"; -import type { Changeset, DiffLineMoveKind, DiffLineMoveKinds, SidecarContext } from "./types"; +import { splitPatchIntoFileChunks, findPatchChunk } from "../patch/chunks"; +import { sanitizePatch, stripTerminalControl } from "../patch/sanitize"; +import type { Changeset, DiffLineMoveKind, DiffLineMoveKinds, SidecarContext } from "../types"; /** Return SGR parameter strings that Git emitted before one diff line marker. */ function leadingSgrParameters(rawLine: string, expectedSign: "+" | "-") { diff --git a/src/core/hunkHeader.test.ts b/src/core/changeset/hunkHeader.test.ts similarity index 100% rename from src/core/hunkHeader.test.ts rename to src/core/changeset/hunkHeader.test.ts diff --git a/src/core/hunkHeader.ts b/src/core/changeset/hunkHeader.ts similarity index 94% rename from src/core/hunkHeader.ts rename to src/core/changeset/hunkHeader.ts index 4c4a6da80..e73a3a5c7 100644 --- a/src/core/hunkHeader.ts +++ b/src/core/changeset/hunkHeader.ts @@ -1,4 +1,4 @@ -import type { ReviewHunkSpan } from "./review/geometry"; +import type { ReviewHunkSpan } from "../review/geometry"; /** * The facts a hunk header is built from. diff --git a/src/core/hunkSummary.test.ts b/src/core/changeset/hunkSummary.test.ts similarity index 91% rename from src/core/hunkSummary.test.ts rename to src/core/changeset/hunkSummary.test.ts index 10160be66..322985aea 100644 --- a/src/core/hunkSummary.test.ts +++ b/src/core/changeset/hunkSummary.test.ts @@ -1,12 +1,12 @@ import { describe, expect, test } from "bun:test"; import type { Hunk } from "@pierre/diffs"; -import { createJsxFileViewLayout } from "../../examples/extensions/jsx-file-view"; -import { createTestDiffFile } from "../../test/helpers/diff-helpers"; -import { createFileViewInput } from "../ui/fileViews/host"; -import { validateFileViewLayout } from "../ui/fileViews/layout"; +import { createJsxFileViewLayout } from "../../../examples/extensions/jsx-file-view"; +import { createTestDiffFile } from "../../../test/helpers/diff-helpers"; +import { createFileViewInput } from "../../ui/fileViews/host"; +import { validateFileViewLayout } from "../../ui/fileViews/layout"; import { formatHunkHeader } from "./hunkHeader"; import { summarizeHunk } from "./hunkSummary"; -import { reviewHunkRanges } from "./review/geometry"; +import { reviewHunkRanges } from "../review/geometry"; describe("summarizeHunk", () => { test("summarizes every hunk Pierre parses with its header and inclusive spans", () => { diff --git a/src/core/hunkSummary.ts b/src/core/changeset/hunkSummary.ts similarity index 92% rename from src/core/hunkSummary.ts rename to src/core/changeset/hunkSummary.ts index 6a305c6cf..135cabe7d 100644 --- a/src/core/hunkSummary.ts +++ b/src/core/changeset/hunkSummary.ts @@ -1,6 +1,6 @@ -import type { ExtensionDiffHunk } from "../extension-api/types"; +import type { ExtensionDiffHunk } from "../../extension-api/types"; import { formatHunkHeader, type ReviewHunkHeaderSource } from "./hunkHeader"; -import { reviewHunkRanges } from "./review/geometry"; +import { reviewHunkRanges } from "../review/geometry"; /** Report whether one hunk carries the numeric header fields ranges derive from. */ function hasLineNumbers(hunk: ReviewHunkHeaderSource) { diff --git a/src/core/changesetLoaders.ordering.test.ts b/src/core/changeset/loaders.ordering.test.ts similarity index 92% rename from src/core/changesetLoaders.ordering.test.ts rename to src/core/changeset/loaders.ordering.test.ts index 165ca6384..bfed7cbc6 100644 --- a/src/core/changesetLoaders.ordering.test.ts +++ b/src/core/changeset/loaders.ordering.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; -import type { SidecarContext } from "./types"; -import { orderDiffFiles } from "./changesetLoaders"; -import { createTestDiffFile } from "../../test/helpers/diff-helpers"; +import type { SidecarContext } from "../types"; +import { orderDiffFiles } from "./loaders"; +import { createTestDiffFile } from "../../../test/helpers/diff-helpers"; function sidecar(...paths: string[]): SidecarContext { return { diff --git a/src/core/changesetLoaders.test.ts b/src/core/changeset/loaders.test.ts similarity index 99% rename from src/core/changesetLoaders.test.ts rename to src/core/changeset/loaders.test.ts index afb4f3bd6..531a1cad6 100644 --- a/src/core/changesetLoaders.test.ts +++ b/src/core/changeset/loaders.test.ts @@ -11,17 +11,14 @@ import { import { platform, tmpdir } from "node:os"; import { join } from "node:path"; import { SourceTextTooLargeError } from "./fileSource"; -import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import { createGitVcsAdapter } from "../extensions/default/vcs/git"; -import { toInternalVcsAdapter } from "../extensions/runExtension"; -import { createVcsCatalog } from "./vcs"; -import { - loadAppBootstrap as loadCoreAppBootstrap, - type LoadAppBootstrapOptions, -} from "./changesetLoaders"; -import type { CliInput } from "./types"; -import type { VcsAdapter } from "./vcs/types"; -import { computeWatchSignature } from "./watch/signature"; +import { getBundledVcsCatalog } from "../../app/vcsCatalog"; +import { createGitVcsAdapter } from "../../extensions/default/vcs/git"; +import { toInternalVcsAdapter } from "../../extensions/runExtension"; +import { createVcsCatalog } from "../vcs"; +import { loadAppBootstrap as loadCoreAppBootstrap, type LoadAppBootstrapOptions } from "./loaders"; +import type { CliInput } from "../types"; +import type { VcsAdapter } from "../vcs/types"; +import { computeWatchSignature } from "../watch/signature"; const tempDirs: string[] = []; diff --git a/src/core/changesetLoaders.ts b/src/core/changeset/loaders.ts similarity index 97% rename from src/core/changesetLoaders.ts rename to src/core/changeset/loaders.ts index 7d1ea27df..cead29c44 100644 --- a/src/core/changesetLoaders.ts +++ b/src/core/changeset/loaders.ts @@ -13,18 +13,18 @@ import { findSidecarFileContext, loadSidecarContext } from "./sidecar"; import { createSkippedBinaryMetadata, isProbablyBinaryFile } from "./binary"; import { buildDiffFile, type BuildDiffFileOptions, type DiffFileSourceContext } from "./diffFile"; import { createFileSourceFetcher, type FileSourceSpec } from "./fileSource"; -import { changesetFromPatch } from "./changesetFromPatch"; +import { changesetFromPatch } from "./fromPatch"; -import { DEFAULT_TAB_WIDTH } from "./tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../tabWidth"; import { getConfiguredVcsAdapter, isVcsReviewInput, loadVcsReview, operationFromInput, -} from "./vcs"; -import type { VcsCatalog } from "./vcs/types"; -import { buildFilesystemUntrackedDiffFile } from "./vcs/untracked"; -import { computeWatchSignature } from "./watch/signature"; +} from "../vcs"; +import type { VcsCatalog } from "../vcs/types"; +import { buildFilesystemUntrackedDiffFile } from "../vcs/untracked"; +import { computeWatchSignature } from "../watch/signature"; import type { AppBootstrap, SidecarContext, @@ -38,7 +38,7 @@ import type { VcsShowCommandInput, VcsDiffCommandInput, VcsStashShowCommandInput, -} from "./types"; +} from "../types"; export interface LoadAppBootstrapOptions { cwd?: string; diff --git a/src/core/changeset.ts b/src/core/changeset/model.ts similarity index 95% rename from src/core/changeset.ts rename to src/core/changeset/model.ts index c3ca8fe6d..2fa4c8750 100644 --- a/src/core/changeset.ts +++ b/src/core/changeset/model.ts @@ -8,7 +8,7 @@ * app-facing types above them. */ import type { FileDiffMetadata } from "@pierre/diffs"; -import type { AgentFileContext } from "../extension-api/types"; +import type { AgentFileContext } from "../../extension-api/types"; import type { FileSourceFetcher } from "./fileSource"; /** One loaded review sidecar: the changeset summary plus every annotated file it names. */ diff --git a/src/core/sidecar.test.ts b/src/core/changeset/sidecar.test.ts similarity index 100% rename from src/core/sidecar.test.ts rename to src/core/changeset/sidecar.test.ts diff --git a/src/core/sidecar.ts b/src/core/changeset/sidecar.ts similarity index 97% rename from src/core/sidecar.ts rename to src/core/changeset/sidecar.ts index f949074e4..2540bd077 100644 --- a/src/core/sidecar.ts +++ b/src/core/changeset/sidecar.ts @@ -7,8 +7,8 @@ * mean the coding-agent command surface in `src/session/agent/`. */ import { resolve as resolvePath } from "node:path"; -import type { AgentAnnotation, AgentFileContext } from "../extension-api/types"; -import type { SidecarContext } from "./changeset"; +import type { AgentAnnotation, AgentFileContext } from "../../extension-api/types"; +import type { SidecarContext } from "./model"; interface SidecarLoadOptions { cwd?: string; diff --git a/src/core/config.test.ts b/src/core/config.test.ts index 53736d4ab..c0459b72e 100644 --- a/src/core/config.test.ts +++ b/src/core/config.test.ts @@ -10,7 +10,7 @@ import { saveGlobalViewPreferences, saveViewPreferencesPromptPreference, } from "./config"; -import { loadAppBootstrap } from "./changesetLoaders"; +import { loadAppBootstrap } from "./changeset/loaders"; import { LEGACY_CUSTOM_SYNTAX_NOTICE, LEGACY_CUSTOM_SYNTAX_NOTICES } from "./startupNotice"; const tempDirs: string[] = []; diff --git a/src/core/patch/chunks.ts b/src/core/patch/chunks.ts index c735cd6f3..309d96381 100644 --- a/src/core/patch/chunks.ts +++ b/src/core/patch/chunks.ts @@ -1,5 +1,5 @@ import type { FileDiffMetadata } from "@pierre/diffs"; -import { normalizeDiffPath } from "../diffPaths"; +import { normalizeDiffPath } from "../changeset/diffPaths"; /** Remove git-style a/ and b/ prefixes before matching diff paths. */ function stripPrefixes(path: string) { diff --git a/src/core/patch/sanitize.ts b/src/core/patch/sanitize.ts index e96958416..79500efea 100644 --- a/src/core/patch/sanitize.ts +++ b/src/core/patch/sanitize.ts @@ -3,7 +3,7 @@ * * Patch text reaches Hunk colored by a pager, CRLF-terminated, or wrapped in `git log` * metadata, and the parser accepts none of that. "Sanitize" is the rewrite of that text; - * "normalize" stays reserved for canonicalizing paths (`core/diffPaths.ts`), so a reader can + * "normalize" stays reserved for canonicalizing paths (`core/changeset/diffPaths.ts`), so a reader can * tell the two apart by name. * * Callers that need moved-line markers must read Git's SGR colors before calling this — the diff --git a/src/core/review/selectors.ts b/src/core/review/selectors.ts index ddb2968d3..699879d27 100644 --- a/src/core/review/selectors.ts +++ b/src/core/review/selectors.ts @@ -6,7 +6,7 @@ * differently. Selectors stay pure functions of state, and the ones that encode a rule * rather than a lookup say so by name. */ -import { normalizeDiffPath } from "../diffPaths"; +import { normalizeDiffPath } from "../changeset/diffPaths"; import { reviewGapId, reviewGapSourceForFile, diff --git a/src/core/types.ts b/src/core/types.ts index e67727b20..146640e2f 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -1,5 +1,5 @@ import type { NamedCustomThemeConfig } from "../extension-api/types"; -import type { Changeset, DiffFile } from "./changeset"; +import type { Changeset, DiffFile } from "./changeset/model"; import type { CliInput, CommonOptions, @@ -36,7 +36,7 @@ export type { DiffLineMoveKind, DiffLineMoveKinds, SidecarContext, -} from "./changeset"; +} from "./changeset/model"; export type { CliInput, CommonOptions, diff --git a/src/core/vcs/types.ts b/src/core/vcs/types.ts index 5c62503e9..dbe33a45d 100644 --- a/src/core/vcs/types.ts +++ b/src/core/vcs/types.ts @@ -1,11 +1,11 @@ import type { ExtensionVcsWatchPlan } from "../../extension-api/types"; -import type { DiffFile } from "../changeset"; +import type { DiffFile } from "../changeset/model"; import type { VcsDiffCommandInput, VcsShowCommandInput, VcsStashShowCommandInput, } from "../commandInputs"; -import type { BuildDiffFileOptions } from "../diffFile"; +import type { BuildDiffFileOptions } from "../changeset/diffFile"; export type VcsId = string; diff --git a/src/core/vcs/untracked.ts b/src/core/vcs/untracked.ts index d8fb64657..ea5187aa7 100644 --- a/src/core/vcs/untracked.ts +++ b/src/core/vcs/untracked.ts @@ -1,8 +1,8 @@ import fs from "node:fs"; import { join } from "node:path"; -import { createSkippedBinaryMetadata, isProbablyBinaryFile } from "../binary"; -import { buildDiffFile, createSkippedLargeMetadata } from "../diffFile"; -import { createFileSourceFetcher } from "../fileSource"; +import { createSkippedBinaryMetadata, isProbablyBinaryFile } from "../changeset/binary"; +import { buildDiffFile, createSkippedLargeMetadata } from "../changeset/diffFile"; +import { createFileSourceFetcher } from "../changeset/fileSource"; import { inspectLargeUntrackedFile } from "../../lib/largeFile"; import { escapeUntrackedPatchPath } from "../../lib/patchPath"; import { parseSingleFilePatch } from "../patch/singleFile"; diff --git a/src/extensions/apply.test.ts b/src/extensions/apply.test.ts index 2be6cf2a7..baebca606 100644 --- a/src/extensions/apply.test.ts +++ b/src/extensions/apply.test.ts @@ -107,7 +107,7 @@ describe("extension file languages", () => { }); test("lets the last extension registration win for the same file extension", async () => { - const { fileLanguageForPath } = await import("../core/fileLanguageLookup"); + const { fileLanguageForPath } = await import("../core/changeset/fileLanguageLookup"); const { result } = createTestLoadResult(); result.registry.fileLanguages.push( { extensionId: "first", extension: "hunkfixture", language: "python" }, diff --git a/src/extensions/apply.ts b/src/extensions/apply.ts index 6bce86d50..781d1aa12 100644 --- a/src/extensions/apply.ts +++ b/src/extensions/apply.ts @@ -1,4 +1,7 @@ -import { BUILT_IN_FILE_LANGUAGE_EXTENSIONS, registerFileLanguage } from "../core/fileLanguage"; +import { + BUILT_IN_FILE_LANGUAGE_EXTENSIONS, + registerFileLanguage, +} from "../core/changeset/fileLanguage"; import type { StartupNotice } from "../core/startupNotice"; import type { Changeset } from "../core/types"; import { detectVcs, extendVcsCatalog, getDefaultVcsAdapter } from "../core/vcs"; diff --git a/src/extensions/events.ts b/src/extensions/events.ts index 8709c5b2c..4d3bfa636 100644 --- a/src/extensions/events.ts +++ b/src/extensions/events.ts @@ -14,7 +14,7 @@ import type { ExtensionReviewNavigation, ExtensionVcsFileChangeType, } from "../extension-api/types"; -import { summarizeHunk } from "../core/hunkSummary"; +import { summarizeHunk } from "../core/changeset/hunkSummary"; /** * How long `shutdown` handlers may run before Hunk exits anyway. diff --git a/src/extensions/vcsPatchResult.test.ts b/src/extensions/vcsPatchResult.test.ts index e28f25fd8..a53701cbb 100644 --- a/src/extensions/vcsPatchResult.test.ts +++ b/src/extensions/vcsPatchResult.test.ts @@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test"; import { toInternalVcsPatchResult } from "./vcsPatchResult"; import { HunkExtensionUserError } from "../extension-api/types"; import { HunkUserError, toUserFacingError } from "../core/errors"; -import { SourceTextTooLargeError } from "../core/fileSource"; +import { SourceTextTooLargeError } from "../core/changeset/fileSource"; import { toInternalVcsAdapter } from "./runExtension"; import type { ExtensionVcsFileSourceRequest, diff --git a/src/extensions/vcsPatchResult.ts b/src/extensions/vcsPatchResult.ts index 8ccae2c83..d17a392f4 100644 --- a/src/extensions/vcsPatchResult.ts +++ b/src/extensions/vcsPatchResult.ts @@ -2,13 +2,13 @@ import { buildDiffFile, createSkippedLargeMetadata, type BuildDiffFileOptions, -} from "../core/diffFile"; +} from "../core/changeset/diffFile"; import { parseSingleFilePatch } from "../core/patch/singleFile"; import { DEFAULT_SOURCE_TEXT_MAX_BYTES, SourceTextTooLargeError, type FileSourceSide, -} from "../core/fileSource"; +} from "../core/changeset/fileSource"; import type { DiffFile } from "../core/types"; import type { VcsPatchResult } from "../core/vcs/types"; import type { diff --git a/src/opentui/model.ts b/src/opentui/model.ts index 4cae34488..5a6dfc69b 100644 --- a/src/opentui/model.ts +++ b/src/opentui/model.ts @@ -1,7 +1,7 @@ import { parsePatchFiles } from "@pierre/diffs"; -import { patchLooksBinary } from "../core/binary"; -import { normalizeDiffMetadataPaths, normalizeDiffPath } from "../core/diffPaths"; -import { countDiffStats } from "../core/diffFile"; +import { patchLooksBinary } from "../core/changeset/binary"; +import { normalizeDiffMetadataPaths, normalizeDiffPath } from "../core/changeset/diffPaths"; +import { countDiffStats } from "../core/changeset/diffFile"; import { splitPatchIntoFileChunks, findPatchChunk } from "../core/patch/chunks"; import { sanitizePatch } from "../core/patch/sanitize"; import type { DiffFile } from "../core/types"; diff --git a/src/ui/AppHost.extension-dialogs.test.tsx b/src/ui/AppHost.extension-dialogs.test.tsx index eb391b815..370c78e5b 100644 --- a/src/ui/AppHost.extension-dialogs.test.tsx +++ b/src/ui/AppHost.extension-dialogs.test.tsx @@ -6,7 +6,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import { removeTestDirectory } from "../../test/helpers/filesystem"; -import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/loaders"; import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; diff --git a/src/ui/AppHost.extension-navigation.test.tsx b/src/ui/AppHost.extension-navigation.test.tsx index 64743d5a5..a75a067c9 100644 --- a/src/ui/AppHost.extension-navigation.test.tsx +++ b/src/ui/AppHost.extension-navigation.test.tsx @@ -6,7 +6,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import { removeTestDirectory } from "../../test/helpers/filesystem"; -import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/loaders"; import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; diff --git a/src/ui/AppHost.extension-sidebar.test.tsx b/src/ui/AppHost.extension-sidebar.test.tsx index dceea2b7a..f2fdebaa1 100644 --- a/src/ui/AppHost.extension-sidebar.test.tsx +++ b/src/ui/AppHost.extension-sidebar.test.tsx @@ -7,7 +7,7 @@ import { KeyEvent, type ParsedKey } from "@opentui/core"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import { removeTestDirectory } from "../../test/helpers/filesystem"; -import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/loaders"; import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; diff --git a/src/ui/AppHost.extensions.test.tsx b/src/ui/AppHost.extensions.test.tsx index b4fe3c2d9..bb4d8b144 100644 --- a/src/ui/AppHost.extensions.test.tsx +++ b/src/ui/AppHost.extensions.test.tsx @@ -16,7 +16,7 @@ import { removeTestDirectory } from "../../test/helpers/filesystem"; import { ReviewProducer } from "../app/review/producer"; import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/loaders"; import type { CliInput } from "../core/types"; import type { HunkSessionBrokerClient } from "../session/broker/brokerClient"; diff --git a/src/ui/AppHost.file-view-modes.test.tsx b/src/ui/AppHost.file-view-modes.test.tsx index 919586ffa..f23fa7a72 100644 --- a/src/ui/AppHost.file-view-modes.test.tsx +++ b/src/ui/AppHost.file-view-modes.test.tsx @@ -8,7 +8,7 @@ import { act } from "react"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile } from "../../test/helpers/diff-helpers"; import { createWatchTestRuntime } from "../../test/helpers/watchTest"; -import { loadAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap } from "../core/changeset/loaders"; import { loadStartupExtensions } from "../extensions/startup"; import { AppHost } from "./AppHost"; diff --git a/src/ui/AppHost.interactions.test.tsx b/src/ui/AppHost.interactions.test.tsx index 35752d597..a6cc62773 100644 --- a/src/ui/AppHost.interactions.test.tsx +++ b/src/ui/AppHost.interactions.test.tsx @@ -20,7 +20,7 @@ import { createEmptyExtensionLoadResult } from "../extensions/types"; import { AGENT_SKILL_COMMAND, AGENT_SKILL_PROMPT } from "./components/chrome/AgentSkillDialog"; import { resolveTheme } from "./themes"; -const { loadAppBootstrap } = await import("../core/changesetLoaders"); +const { loadAppBootstrap } = await import("../core/changeset/loaders"); const { AppHost } = await import("./AppHost"); const TEST_KEY_PAGE_UP = "\x1B[5~"; diff --git a/src/ui/AppHost.keybindings.test.tsx b/src/ui/AppHost.keybindings.test.tsx index 986f5359b..9c984f95c 100644 --- a/src/ui/AppHost.keybindings.test.tsx +++ b/src/ui/AppHost.keybindings.test.tsx @@ -8,7 +8,7 @@ import { act } from "react"; import { removeTestDirectory } from "../../test/helpers/filesystem"; import { resolveConfiguredCliInput } from "../core/config"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import { loadAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap } from "../core/changeset/loaders"; import type { AppBootstrap } from "../core/types"; import { createEmptyExtensionLoadResult } from "../extensions/types"; import { AppHost } from "./AppHost"; diff --git a/src/ui/AppHost.reload.test.tsx b/src/ui/AppHost.reload.test.tsx index daa57dbae..a29becce6 100644 --- a/src/ui/AppHost.reload.test.tsx +++ b/src/ui/AppHost.reload.test.tsx @@ -15,7 +15,7 @@ import type { } from "../session/types"; const { getBundledVcsCatalog } = await import("../app/vcsCatalog"); -const { loadAppBootstrap } = await import("../core/changesetLoaders"); +const { loadAppBootstrap } = await import("../core/changeset/loaders"); const { AppHost } = await import("./AppHost"); /** Stand in for the session daemon so a test can send the commands agents send. */ diff --git a/src/ui/AppHost.watch.test.tsx b/src/ui/AppHost.watch.test.tsx index d20f06e27..1fd75a50d 100644 --- a/src/ui/AppHost.watch.test.tsx +++ b/src/ui/AppHost.watch.test.tsx @@ -5,7 +5,7 @@ import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import { capturedTestColorToHex } from "../../test/helpers/test-color-helpers"; import { createWatchTestRuntime } from "../../test/helpers/watchTest"; -import { loadAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap } from "../core/changeset/loaders"; import { AppHost } from "./AppHost"; import { resolveTheme } from "./themes"; diff --git a/src/ui/AppHost.workspace.test.tsx b/src/ui/AppHost.workspace.test.tsx index 2778b7927..c2ca73357 100644 --- a/src/ui/AppHost.workspace.test.tsx +++ b/src/ui/AppHost.workspace.test.tsx @@ -13,7 +13,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import { removeTestDirectory } from "../../test/helpers/filesystem"; -import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/loaders"; import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; diff --git a/src/ui/diff/diffRows.ts b/src/ui/diff/diffRows.ts index fbec1acce..fbb2bd6de 100644 --- a/src/ui/diff/diffRows.ts +++ b/src/ui/diff/diffRows.ts @@ -14,7 +14,7 @@ import { type FileContents, type FileDiffMetadata, } from "@pierre/diffs"; -import { formatHunkHeader } from "../../core/hunkHeader"; +import { formatHunkHeader } from "../../core/changeset/hunkHeader"; import { reviewLeadingGap, reviewTrailingGap, diff --git a/src/ui/hooks/useTerminalReview.test.tsx b/src/ui/hooks/useTerminalReview.test.tsx index 89b14c817..5cdcd2280 100644 --- a/src/ui/hooks/useTerminalReview.test.tsx +++ b/src/ui/hooks/useTerminalReview.test.tsx @@ -2,7 +2,7 @@ import { describe, expect, spyOn, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act, StrictMode, useEffect, useRef, useState } from "react"; import { builtinAppCommand } from "../../core/commandCatalog"; -import { SourceTextTooLargeError } from "../../core/fileSource"; +import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; import type { DiffFile } from "../../core/types"; import { createTestDeferred, diff --git a/src/ui/hooks/useTerminalReview.ts b/src/ui/hooks/useTerminalReview.ts index 7f928cec2..7568a57d2 100644 --- a/src/ui/hooks/useTerminalReview.ts +++ b/src/ui/hooks/useTerminalReview.ts @@ -30,7 +30,7 @@ import { type AppCommandId, type AppCommandLoweringContext, } from "../../core/commandCatalog"; -import { SourceTextTooLargeError } from "../../core/fileSource"; +import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; import { applyReviewIntent, ReviewIntentPlanningError, diff --git a/src/ui/lib/extensionWorkspace.ts b/src/ui/lib/extensionWorkspace.ts index ed10f2f8e..0590c6190 100644 --- a/src/ui/lib/extensionWorkspace.ts +++ b/src/ui/lib/extensionWorkspace.ts @@ -18,8 +18,8 @@ */ import { isAbsolute, relative, resolve, sep } from "node:path"; -import { normalizeDiffPath } from "../../core/diffPaths"; -import type { FileSourceSide } from "../../core/fileSource"; +import { normalizeDiffPath } from "../../core/changeset/diffPaths"; +import type { FileSourceSide } from "../../core/changeset/fileSource"; import { canReloadInput } from "../../core/inputReload"; import type { CliInput } from "../../core/types"; import { readMetadataChangeType } from "../../extensions/events"; diff --git a/src/ui/lib/files.ts b/src/ui/lib/files.ts index 38cc77b79..ff2b64308 100644 --- a/src/ui/lib/files.ts +++ b/src/ui/lib/files.ts @@ -1,6 +1,6 @@ import { basename, dirname } from "node:path/posix"; import type { FileDiffMetadata } from "@pierre/diffs"; -import { normalizeDiffPath } from "../../core/diffPaths"; +import { normalizeDiffPath } from "../../core/changeset/diffPaths"; import type { AgentAnnotation, DiffFile } from "../../core/types"; import { readMetadataChangeType } from "../../extensions/events"; import { formatTerminalPath } from "../../lib/terminalText"; diff --git a/src/ui/staticDiffPager.ts b/src/ui/staticDiffPager.ts index a58edb871..e132051ab 100644 --- a/src/ui/staticDiffPager.ts +++ b/src/ui/staticDiffPager.ts @@ -14,7 +14,7 @@ * here. If the static renderer cannot parse or render safely, callers fall back to the original patch * text so pager pipelines keep working. */ -import { loadAppBootstrap } from "../core/changesetLoaders"; +import { loadAppBootstrap } from "../core/changeset/loaders"; import { reviewEmptyDiffReason, type ReviewEmptyDiffReason } from "../core/review/document"; import { DEFAULT_TAB_WIDTH } from "../core/tabWidth"; import type { CommonOptions, DiffFile, NamedCustomThemeConfig } from "../core/types"; diff --git a/test/helpers/diff-helpers.ts b/test/helpers/diff-helpers.ts index d7f0dc308..e8e8b2808 100644 --- a/test/helpers/diff-helpers.ts +++ b/test/helpers/diff-helpers.ts @@ -1,5 +1,5 @@ import { parseDiffFromFile } from "@pierre/diffs"; -import type { FileSourceFetcher, FileSourceSide } from "../../src/core/fileSource"; +import type { FileSourceFetcher, FileSourceSide } from "../../src/core/changeset/fileSource"; import type { AgentAnnotation, AgentFileContext, DiffFile } from "../../src/core/types"; function collectChangeStats(metadata: DiffFile["metadata"]) { From d7aabf4fc9174262ebdce018980d0a9ab7b40a54 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 03:18:04 +0000 Subject: [PATCH 3/8] refactor(core): group invocation and configuration into core/invocation/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 2 of giving src/core an interior. The nine files describing how a run is asked for — command inputs, config, the command catalog, invocation errors, experimental flags, paths, tab width, reload capability, and version — become core/invocation/. The CLI-input type definitions (session/markup/extension command inputs and ParsedCliInput) move out of core/types.ts into invocation/commandInputs.ts, with core/types re-exporting the names still consumed elsewhere so no import site changes. The leaf-freeze rule follows commandInputs to its new path; all nine files have outside consumers, so this module declares no interior yet. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XcuayyxJrwQd9EHpuxNef1 --- .dependency-cruiser.cjs | 2 +- docs/browser-review-seam-audit.md | 2 +- docs/extension-system-exploration.md | 2 +- docs/module-boundaries.md | 39 ++- docs/source-architecture.md | 2 + scripts/build-prebuilt-artifact.test.ts | 2 +- scripts/build-prebuilt-artifact.ts | 2 +- scripts/generate-docs.test.ts | 2 +- scripts/generate-docs.ts | 4 +- src/app/cli.test.ts | 2 +- src/app/cli.ts | 6 +- src/app/extensionBootstrap.test.ts | 2 +- src/app/extensionBootstrap.ts | 2 +- src/app/session/registration.ts | 2 +- src/app/session/reloadBounds.ts | 2 +- src/app/sessionBootstrap.test.ts | 2 +- src/app/sessionBootstrap.ts | 2 +- src/app/startup.test.ts | 4 +- src/app/startup.ts | 6 +- src/app/startup.vcsExtensions.test.ts | 2 +- src/core/changeset/loaders.ts | 2 +- src/core/commandInputs.ts | 97 ----- .../{ => invocation}/commandCatalog.test.ts | 2 +- src/core/{ => invocation}/commandCatalog.ts | 10 +- src/core/invocation/commandInputs.ts | 331 ++++++++++++++++++ src/core/{ => invocation}/config.test.ts | 8 +- src/core/{ => invocation}/config.ts | 18 +- src/core/{ => invocation}/errors.test.ts | 2 +- src/core/{ => invocation}/errors.ts | 2 +- .../{ => invocation}/experimental.test.ts | 2 +- src/core/{ => invocation}/experimental.ts | 2 +- src/core/{ => invocation}/inputReload.ts | 2 +- src/core/{ => invocation}/paths.test.ts | 0 src/core/{ => invocation}/paths.ts | 0 src/core/{ => invocation}/tabWidth.ts | 0 src/core/{ => invocation}/version.ts | 2 +- src/core/types.ts | 263 ++------------ src/core/updateNotice.ts | 4 +- src/core/vcs/index.test.ts | 2 +- src/core/vcs/index.ts | 4 +- src/core/vcs/types.ts | 2 +- src/core/watch/plan.ts | 2 +- src/core/watch/signature.ts | 2 +- src/extensions/discovery.ts | 5 +- src/extensions/manage/cli.ts | 4 +- src/extensions/manage/install.ts | 2 +- src/extensions/runExtension.ts | 2 +- src/extensions/trust.test.ts | 2 +- src/extensions/trust.ts | 2 +- src/extensions/vcsPatchResult.test.ts | 2 +- src/main.tsx | 2 +- src/opentui/HunkDiffBody.tsx | 2 +- src/session/broker/wire.ts | 5 +- src/session/client/daemonHttp.ts | 2 +- src/session/types.ts | 2 +- src/ui/App.tsx | 11 +- src/ui/AppHost.keybindings.test.tsx | 2 +- src/ui/AppHost.tsx | 2 +- src/ui/components/panes/DiffPane.tsx | 2 +- src/ui/diff/DiffSectionBody.tsx | 2 +- src/ui/diff/codeColumns.ts | 2 +- src/ui/diff/diffRows.ts | 2 +- src/ui/diff/diffSectionGeometry.ts | 2 +- src/ui/diff/diffSectionRowPlan.ts | 2 +- src/ui/diff/expandCollapsedRows.ts | 2 +- src/ui/diff/lineHighlightPaint.test.ts | 2 +- src/ui/diff/lineHighlightPaint.ts | 2 +- src/ui/hooks/useTerminalReview.test.tsx | 2 +- src/ui/hooks/useTerminalReview.ts | 2 +- src/ui/lib/appCommands.test.ts | 2 +- src/ui/lib/appCommands.ts | 2 +- src/ui/lib/extensionWorkspace.ts | 2 +- src/ui/staticDiffPager.ts | 2 +- .../src/content/docs/docs/reference/config.md | 2 +- 74 files changed, 496 insertions(+), 431 deletions(-) delete mode 100644 src/core/commandInputs.ts rename src/core/{ => invocation}/commandCatalog.test.ts (98%) rename src/core/{ => invocation}/commandCatalog.ts (98%) create mode 100644 src/core/invocation/commandInputs.ts rename src/core/{ => invocation}/config.test.ts (99%) rename src/core/{ => invocation}/config.ts (99%) rename src/core/{ => invocation}/errors.test.ts (96%) rename src/core/{ => invocation}/errors.ts (98%) rename src/core/{ => invocation}/experimental.test.ts (97%) rename src/core/{ => invocation}/experimental.ts (99%) rename src/core/{ => invocation}/inputReload.ts (94%) rename src/core/{ => invocation}/paths.test.ts (100%) rename src/core/{ => invocation}/paths.ts (100%) rename src/core/{ => invocation}/tabWidth.ts (100%) rename src/core/{ => invocation}/version.ts (83%) diff --git a/.dependency-cruiser.cjs b/.dependency-cruiser.cjs index f1f6da389..61bc6a761 100644 --- a/.dependency-cruiser.cjs +++ b/.dependency-cruiser.cjs @@ -139,7 +139,7 @@ module.exports = { from: { path: [ "^src/core/changeset/(model|diffFile|sidecar)\\.ts$", - "^src/core/commandInputs\\.ts$", + "^src/core/invocation/commandInputs\\.ts$", "^src/core/(vcs|watch|patch)/", ], }, diff --git a/docs/browser-review-seam-audit.md b/docs/browser-review-seam-audit.md index 67eabf7a3..3a8c100de 100644 --- a/docs/browser-review-seam-audit.md +++ b/docs/browser-review-seam-audit.md @@ -515,7 +515,7 @@ here so the extraction happens before the duplication exists. Design detail in Fix: extract a renderer-neutral catalog (id, title, category, default chords, resolution locus — semantic / client-local / host-only); terminal keeps matchers and handlers, browser adds its own, both render menus/help/palette from the catalog. - _Repaid (Phase 1 PR 3)_: `src/core/commandCatalog.ts` carries id, title, category, default + _Repaid (Phase 1 PR 3)_: `src/core/invocation/commandCatalog.ts` carries id, title, category, default chords, resolution locus, extension visibility, and menu-closing behavior for all 44 built-ins. `ui/lib/appCommands.ts` builds its dispatch table from it — the handler map is keyed by `AppCommandId`, so a catalogued command with no terminal handler fails to typecheck — and diff --git a/docs/extension-system-exploration.md b/docs/extension-system-exploration.md index acf83b697..02f9dcba9 100644 --- a/docs/extension-system-exploration.md +++ b/docs/extension-system-exploration.md @@ -171,7 +171,7 @@ export default function (hunk: HunkExtensionAPI) { ```` - Discovery: `~/.config/hunk/extensions/*.ts` and `*/index.ts` (global, follows - our existing XDG path logic in `src/core/paths.ts`), `.hunk/extensions/` + our existing XDG path logic in `src/core/invocation/paths.ts`), `.hunk/extensions/` (repo-local, **trust-gated**, same posture as pi's project trust), explicit `[extensions] paths = [...]` in `config.toml`, and a `--extension ` dev flag. `--no-extensions` for a clean run and for bug triage. diff --git a/docs/module-boundaries.md b/docs/module-boundaries.md index 7fe53ab72..24862aeb2 100644 --- a/docs/module-boundaries.md +++ b/docs/module-boundaries.md @@ -87,6 +87,29 @@ basenames — and no exported symbol changed. `core/types.ts` still re-exports t sidecar shapes for legacy import sites; it names `changeset/model`, which is public, so the interior rule needs no exception. `core/patch/` stayed where it is: it was already coherent. +Phase 2 (2026-08-17) grouped **how a run is asked for** into `core/invocation/`: the command +inputs (`commandInputs`), the layered config resolver (`config`), the app command catalog +(`commandCatalog`), the invocation errors (`errors` — "a failure Hunk raises because of how it +was invoked"), launch-scoped experimental features (`experimental`), XDG/app paths (`paths`), +tab-width validation (`tabWidth`), reload eligibility (`inputReload`), and the CLI version +(`version`). The move is path-only; no exported symbol changed. + +Every one of the nine is **public**: each has production importers outside the module, so this +phase adds no `invocation-internals-stay-in-module` rule. Its value is the grouping plus +extending the freeze: `core-leaves-never-reimport-types` now names +`core/invocation/commandInputs.ts` in place of the old root path. Only `commandInputs` is a +types-leaf — `config`, `experimental`, and `inputReload` import `core/types` legally, since +`core/types` re-exports from `commandInputs` and never the other way round. + +`commandInputs` also absorbed the CLI-input half that was still declared in `core/types.ts`: +`HelpCommandInput`, `PagerCommandInput`, `DaemonServeCommandInput`, the whole +`Session*CommandInput` family with `SessionSelectorInput` / `SessionCommandOutput` / +`SessionCommentApplyItemInput`, `MarkupRenderCommandInput`, `MarkupGuideCommandInput`, the +`Extension*CommandInput` family, and `ParsedCliInput`. Two small aliases came with them because +those inputs name them and the leaf may not import `core/types` back: +`SessionCommentListType` and the `ReviewNoteSource` it unions over. `core/types.ts` re-exports +all of them, so no import site changed. + ## Snapshot (2026-08-17, v0.19.0) 331 production modules, 1282 internal edges, **zero boundary violations and zero import @@ -96,8 +119,9 @@ rules: - **Cycles.** Each cycle was a type-only back-edge from a lower module into a grab-bag above it. The cuts: `core/types.ts` gave its changeset model to `core/changeset.ts` (since phase 1, - `core/changeset/model.ts`) and its command-input model to `core/commandInputs.ts` (re-exported - from `core/types` so import sites keep working); the diff row model moved to + `core/changeset/model.ts`) and its command-input model to `core/commandInputs.ts` (since phase + 2, `core/invocation/commandInputs.ts`; re-exported from `core/types` so import sites keep + working); the diff row model moved to `ui/diff/diffRowModel.ts`; the worker's compact encoder was retyped structurally (`HighlightedHastLines`); `HunkSessionBrokerClient` moved beside the client class it aliases; `CopySelectedRowRange` moved into @@ -125,11 +149,12 @@ rules: The tier rules now hold with no exceptions. Two follow-ups are worth doing next: -1. **Give `src/core` an interior.** _In progress (phases 0–1, see Module interiors)._ The - subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, `patch/`, and now `changeset/`) are - coherent modules; the loose files still at `core/*` root are the remaining grab-bag. Keep - grouping them by audience — config/CLI next, then the process/runtime concerns — and give - each group a rule restricting which of its files other tiers may import. The review seam's +1. **Give `src/core` an interior.** _In progress (phases 0–2, see Module interiors)._ The + subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, `patch/`, and now `changeset/` and + `invocation/`) are coherent modules; the loose files still at `core/*` root are the remaining + grab-bag. Keep grouping them by audience — the process/runtime concerns next, then melting + what is left of `core/types.ts` — and give each group a rule restricting which of its files + other tiers may import. The review seam's named modules (`document`, `geometry`, `state`, …) stay public; their helpers become internal. 2. **Tighten the adapter allowlist.** `ui-couples-to-session-via-adapters` currently allowlists diff --git a/docs/source-architecture.md b/docs/source-architecture.md index 818e5d5b3..7e52a50e3 100644 --- a/docs/source-architecture.md +++ b/docs/source-architecture.md @@ -13,6 +13,8 @@ src/core/ review model, patch handling, VCS contracts, configuration, runtime primitives src/core/changeset/ the changeset model and the pipeline that acquires one: loaders, per-file construction, sidecar/source reads, and hunk formatting +src/core/invocation/ how a run is asked for: command inputs, layered configuration, the + command catalog, user-facing errors, paths, and version src/core/theme/ bundled theme metadata, custom-theme rules, and terminal theme detection src/core/watch/ input signatures, observation plans/backends, and refresh coordination src/core/vcs/ provider-neutral VCS catalog, contracts, operation dispatch, and host support diff --git a/scripts/build-prebuilt-artifact.test.ts b/scripts/build-prebuilt-artifact.test.ts index 7bbd530a3..c23a7f4b5 100644 --- a/scripts/build-prebuilt-artifact.test.ts +++ b/scripts/build-prebuilt-artifact.test.ts @@ -2,7 +2,7 @@ import { existsSync, mkdtempSync, mkdirSync, rmSync, statSync, writeFileSync } f import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, test } from "bun:test"; -import { BUNDLED_SKILL_NAMES } from "../src/core/paths"; +import { BUNDLED_SKILL_NAMES } from "../src/core/invocation/paths"; import { stagePrebuiltArtifact } from "./build-prebuilt-artifact"; import { binaryFilenameForSpec, getHostPlatformPackageSpec } from "./prebuilt-package-helpers"; diff --git a/scripts/build-prebuilt-artifact.ts b/scripts/build-prebuilt-artifact.ts index 454e2e814..39638f45f 100644 --- a/scripts/build-prebuilt-artifact.ts +++ b/scripts/build-prebuilt-artifact.ts @@ -2,7 +2,7 @@ import { chmodSync, cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; import path from "node:path"; -import { BUNDLED_SKILL_NAMES } from "../src/core/paths"; +import { BUNDLED_SKILL_NAMES } from "../src/core/invocation/paths"; import { binaryFilenameForSpec, getHostPlatformPackageSpec, diff --git a/scripts/generate-docs.test.ts b/scripts/generate-docs.test.ts index 84f9536db..1aa75ca74 100644 --- a/scripts/generate-docs.test.ts +++ b/scripts/generate-docs.test.ts @@ -2,7 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; -import { CONFIG_REFERENCE_OPTIONS } from "../src/core/config"; +import { CONFIG_REFERENCE_OPTIONS } from "../src/core/invocation/config"; import { renderHunkReviewSkill } from "../src/hunk-review/skillDocument"; import { SESSION_AGENT_COMMAND_LIST } from "../src/session/agent/surface"; import { diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts index 7022ef8ef..76604dc88 100644 --- a/scripts/generate-docs.ts +++ b/scripts/generate-docs.ts @@ -13,7 +13,7 @@ import { CONFIG_REFERENCE_CUSTOM_THEME, CONFIG_REFERENCE_EXTENSIONS, CONFIG_REFERENCE_OPTIONS, -} from "../src/core/config"; +} from "../src/core/invocation/config"; import { renderHunkReviewSkill } from "../src/hunk-review/skillDocument"; import { type AgentCommandOption, SESSION_AGENT_COMMAND_LIST } from "../src/session/agent/surface"; import { @@ -276,7 +276,7 @@ description: Exhaustive generated reference for Hunk TOML keys, defaults, aliase ${GENERATED_NOTICE} -Hunk reads TOML preferences from the user config and an optional repository config. This reference is generated from the same catalog that \`src/core/config.ts\` uses to parse preference keys. +Hunk reads TOML preferences from the user config and an optional repository config. This reference is generated from the same catalog that \`src/core/invocation/config.ts\` uses to parse preference keys. ## Resolution and scope diff --git a/src/app/cli.test.ts b/src/app/cli.test.ts index d9d734f3f..b0eaf3fbc 100644 --- a/src/app/cli.test.ts +++ b/src/app/cli.test.ts @@ -9,7 +9,7 @@ import { parseCli, WATCH_OPTION, } from "./cli"; -import { resolveCliVersion } from "../core/version"; +import { resolveCliVersion } from "../core/invocation/version"; const tempDirs: string[] = []; diff --git a/src/app/cli.ts b/src/app/cli.ts index 18fb8fdf6..112c4b239 100644 --- a/src/app/cli.ts +++ b/src/app/cli.ts @@ -18,7 +18,7 @@ import { resolveBundledSkillName, resolveBundledSkillPath, type BundledSkillName, -} from "../core/paths"; +} from "../core/invocation/paths"; import { type AgentCommandConstraint, type AgentCommandSpec, @@ -42,8 +42,8 @@ import { HIGHLIGHT_RANGE_MESSAGE, RELOAD_SEPARATOR_MESSAGE, } from "../session/agent/errors"; -import { DEFAULT_TAB_WIDTH, parseTabWidth } from "../core/tabWidth"; -import { resolveCliVersion } from "../core/version"; +import { DEFAULT_TAB_WIDTH, parseTabWidth } from "../core/invocation/tabWidth"; +import { resolveCliVersion } from "../core/invocation/version"; /** Structured option metadata shared by Commander registration and generated CLI docs. */ export interface CliReferenceOption { diff --git a/src/app/extensionBootstrap.test.ts b/src/app/extensionBootstrap.test.ts index 8c5a5bc8f..555177d0f 100644 --- a/src/app/extensionBootstrap.test.ts +++ b/src/app/extensionBootstrap.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { HunkConfigResolution } from "../core/config"; +import type { HunkConfigResolution } from "../core/invocation/config"; import type { CliInput } from "../core/types"; import { createEmptyExtensionLoadResult } from "../extensions/types"; import { resolveConfiguredExtensions } from "./extensionBootstrap"; diff --git a/src/app/extensionBootstrap.ts b/src/app/extensionBootstrap.ts index d076ca458..a349ee932 100644 --- a/src/app/extensionBootstrap.ts +++ b/src/app/extensionBootstrap.ts @@ -1,4 +1,4 @@ -import { resolveConfiguredCliInput, type HunkConfigResolution } from "../core/config"; +import { resolveConfiguredCliInput, type HunkConfigResolution } from "../core/invocation/config"; import { findProjectRootCandidate } from "../core/projectRoot"; import type { CliInput } from "../core/types"; import { extendVcsCatalog } from "../core/vcs"; diff --git a/src/app/session/registration.ts b/src/app/session/registration.ts index 2b86e322c..44d011746 100644 --- a/src/app/session/registration.ts +++ b/src/app/session/registration.ts @@ -1,6 +1,6 @@ import { randomUUID } from "node:crypto"; import { spawnSync } from "node:child_process"; -import { resolveExperimentalFeatures } from "../../core/experimental"; +import { resolveExperimentalFeatures } from "../../core/invocation/experimental"; import { isVcsReviewInput } from "../../core/vcs"; import { summarizeHunk } from "../../core/changeset/hunkSummary"; import { reviewHunkRanges } from "../../core/review/geometry"; diff --git a/src/app/session/reloadBounds.ts b/src/app/session/reloadBounds.ts index 23caaab8e..ee107d6ce 100644 --- a/src/app/session/reloadBounds.ts +++ b/src/app/session/reloadBounds.ts @@ -1,5 +1,5 @@ import { isAbsolute, relative, resolve } from "node:path"; -import { resolveCanonicalPath } from "../../core/paths"; +import { resolveCanonicalPath } from "../../core/invocation/paths"; import { findProjectRootCandidate } from "../../core/projectRoot"; import type { AppBootstrap, CliInput, CommonOptions } from "../../core/types"; import type { VcsCatalog } from "../../core/vcs/types"; diff --git a/src/app/sessionBootstrap.test.ts b/src/app/sessionBootstrap.test.ts index 861b2c067..05efe427a 100644 --- a/src/app/sessionBootstrap.test.ts +++ b/src/app/sessionBootstrap.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { HunkConfigResolution } from "../core/config"; +import type { HunkConfigResolution } from "../core/invocation/config"; import type { AppBootstrap, CliInput } from "../core/types"; import { createEmptyExtensionLoadResult } from "../extensions/types"; import { loadConfiguredSessionBootstrap } from "./sessionBootstrap"; diff --git a/src/app/sessionBootstrap.ts b/src/app/sessionBootstrap.ts index 45647f461..d695af354 100644 --- a/src/app/sessionBootstrap.ts +++ b/src/app/sessionBootstrap.ts @@ -1,4 +1,4 @@ -import type { HunkConfigResolution } from "../core/config"; +import type { HunkConfigResolution } from "../core/invocation/config"; import { isVcsReviewInput } from "../core/vcs"; import type { VcsCatalog } from "../core/vcs/types"; import { getBundledVcsCatalog } from "./vcsCatalog"; diff --git a/src/app/startup.test.ts b/src/app/startup.test.ts index bdf35d560..6eb7fa73e 100644 --- a/src/app/startup.test.ts +++ b/src/app/startup.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { createEmptyExtensionLoadResult } from "../extensions/types"; -import type { HunkConfigResolution } from "../core/config"; -import { HunkUserError } from "../core/errors"; +import type { HunkConfigResolution } from "../core/invocation/config"; +import { HunkUserError } from "../core/invocation/errors"; import { prepareStartupPlan } from "./startup"; import type { AppBootstrap, CliInput, NamedCustomThemeConfig, ParsedCliInput } from "../core/types"; diff --git a/src/app/startup.ts b/src/app/startup.ts index 73c6befc3..c64c7d646 100644 --- a/src/app/startup.ts +++ b/src/app/startup.ts @@ -1,8 +1,8 @@ import type { SessionBootstrapResult } from "./sessionBootstrap"; import { createExtensionApplyNotices, createUnknownVcsNotice } from "../extensions/apply"; import type { loadStartupExtensions } from "../extensions/startup"; -import { resolveConfiguredCliInput } from "../core/config"; -import { HunkUserError } from "../core/errors"; +import { resolveConfiguredCliInput } from "../core/invocation/config"; +import { HunkUserError } from "../core/invocation/errors"; import type { loadAppBootstrap } from "../core/changeset/loaders"; import { looksLikePatchInput } from "../core/pager"; import { detectTerminalThemeModeFromBackground } from "../core/theme/detection"; @@ -20,7 +20,7 @@ import type { ParsedCliInput, SessionCommandInput, } from "../core/types"; -import { canReloadInput } from "../core/inputReload"; +import { canReloadInput } from "../core/invocation/inputReload"; import { parseCli } from "./cli"; import { resolveSessionSelectorBoundary } from "./sessionSelector"; import type { VcsCatalog } from "../core/vcs/types"; diff --git a/src/app/startup.vcsExtensions.test.ts b/src/app/startup.vcsExtensions.test.ts index 18bab27fa..cbb574a1d 100644 --- a/src/app/startup.vcsExtensions.test.ts +++ b/src/app/startup.vcsExtensions.test.ts @@ -3,7 +3,7 @@ import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSy import { tmpdir } from "node:os"; import { join } from "node:path"; import { prepareStartupPlan } from "./startup"; -import { resolveConfiguredCliInput } from "../core/config"; +import { resolveConfiguredCliInput } from "../core/invocation/config"; import type { CliInput, ParsedCliInput } from "../core/types"; const tempDirs: string[] = []; diff --git a/src/core/changeset/loaders.ts b/src/core/changeset/loaders.ts index cead29c44..95e9f248d 100644 --- a/src/core/changeset/loaders.ts +++ b/src/core/changeset/loaders.ts @@ -15,7 +15,7 @@ import { buildDiffFile, type BuildDiffFileOptions, type DiffFileSourceContext } import { createFileSourceFetcher, type FileSourceSpec } from "./fileSource"; import { changesetFromPatch } from "./fromPatch"; -import { DEFAULT_TAB_WIDTH } from "../tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../invocation/tabWidth"; import { getConfiguredVcsAdapter, isVcsReviewInput, diff --git a/src/core/commandInputs.ts b/src/core/commandInputs.ts deleted file mode 100644 index 0b8bfbaa1..000000000 --- a/src/core/commandInputs.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Declares the review-launching command inputs and the resolved view options - * they carry: everything a `hunk diff`/`show`/`stash show`/`patch`/`difftool` - * invocation normalizes into before a changeset is loaded. - * - * Kept as a leaf module so the VCS contract and watch planning can name these - * inputs without importing `core/types`, which layers the app-facing types - * above them. - */ -import type { - ExtensionVcsDiffInput, - ExtensionVcsShowInput, - ExtensionVcsStashShowInput, -} from "../extension-api/types"; - -export type LayoutMode = "auto" | "split" | "stack"; -export type CursorLine = "row" | "number" | "off"; -export type SidebarVisibility = boolean | "auto"; -export type VcsMode = string; - -export interface CommonOptions { - mode?: LayoutMode; - cursorLine?: CursorLine; - vcs?: VcsMode; - theme?: string; - agentContext?: string; - pager?: boolean; - watch?: boolean; - /** Enable launch-scoped experimental review features. */ - experimental?: boolean; - /** Offload eligible large-diff highlighting for this launch. */ - fast?: boolean; - excludeUntracked?: boolean; - lineNumbers?: boolean; - tabWidth?: number; - wrapLines?: boolean; - hunkHeaders?: boolean; - menuBar?: boolean; - sidebar?: SidebarVisibility; - agentNotes?: boolean; - copyDecorations?: boolean; - promptSaveViewPreferences?: boolean; - transparentBackground?: boolean; - colorMoved?: boolean; - /** False only when `--no-extensions` disables user extension loading for this run. */ - extensions?: boolean; - /** Entry paths from repeated `--extension` flags, for development and testing. */ - extensionPaths?: string[]; -} - -/** - * Review requests extend the published input views rather than restating them, - * so an adapter written against the extension contract accepts the exact values - * Hunk's commands produce. `options` is the internal half: resolved CLI and - * config state that no adapter — bundled or third-party — needs to see. - */ -export interface VcsDiffCommandInput extends ExtensionVcsDiffInput { - options: CommonOptions; -} - -export interface VcsShowCommandInput extends ExtensionVcsShowInput { - options: CommonOptions; -} - -export interface VcsStashShowCommandInput extends ExtensionVcsStashShowInput { - options: CommonOptions; -} - -export interface FileCommandInput { - kind: "diff"; - left: string; - right: string; - options: CommonOptions; -} - -export interface PatchCommandInput { - kind: "patch"; - file?: string; - text?: string; - options: CommonOptions; -} - -export interface DiffToolCommandInput { - kind: "difftool"; - left: string; - right: string; - path?: string; - options: CommonOptions; -} - -export type CliInput = - | VcsDiffCommandInput - | VcsShowCommandInput - | VcsStashShowCommandInput - | FileCommandInput - | PatchCommandInput - | DiffToolCommandInput; diff --git a/src/core/commandCatalog.test.ts b/src/core/invocation/commandCatalog.test.ts similarity index 98% rename from src/core/commandCatalog.test.ts rename to src/core/invocation/commandCatalog.test.ts index fe4d5f86f..649a9a835 100644 --- a/src/core/commandCatalog.test.ts +++ b/src/core/invocation/commandCatalog.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { createTestReviewState } from "../../test/helpers/review-store-helpers"; +import { createTestReviewState } from "../../../test/helpers/review-store-helpers"; import { APP_COMMAND_CATALOG, appCommandCatalogEntry, diff --git a/src/core/commandCatalog.ts b/src/core/invocation/commandCatalog.ts similarity index 98% rename from src/core/commandCatalog.ts rename to src/core/invocation/commandCatalog.ts index 27f0431a9..0011247a4 100644 --- a/src/core/commandCatalog.ts +++ b/src/core/invocation/commandCatalog.ts @@ -25,11 +25,11 @@ * describes UI vocabulary rather than review semantics, and that module stays purely about * what a review *is*. */ -import type { ReviewIntent } from "./review/intents"; -import type { ReviewSelectionScope } from "./review/navigation"; -import { selectNormalizedSelection, selectReviewGapForSelection } from "./review/selectors"; -import type { ReviewState } from "./review/state"; -import type { ReviewLineAddressV1 } from "./review/types"; +import type { ReviewIntent } from "../review/intents"; +import type { ReviewSelectionScope } from "../review/navigation"; +import { selectNormalizedSelection, selectReviewGapForSelection } from "../review/selectors"; +import type { ReviewState } from "../review/state"; +import type { ReviewLineAddressV1 } from "../review/types"; /** Where one command's effect resolves, and therefore who may invoke it. */ export type AppCommandLocus = "semantic" | "client-local" | "host-only"; diff --git a/src/core/invocation/commandInputs.ts b/src/core/invocation/commandInputs.ts new file mode 100644 index 000000000..66b095ef6 --- /dev/null +++ b/src/core/invocation/commandInputs.ts @@ -0,0 +1,331 @@ +/** + * Declares every shape a parsed `hunk` invocation can take: the review-launching + * inputs and the view options they carry, plus the non-review commands — help, + * pager, `daemon serve`, `session *`, `markup *`, and `extension *` — that + * `ParsedCliInput` unions together. + * + * Kept as a leaf module so the VCS contract, watch planning, and the session + * surfaces can name these inputs without importing `core/types`, which layers + * the app-facing types above them. + */ +import type { + ExtensionVcsDiffInput, + ExtensionVcsShowInput, + ExtensionVcsStashShowInput, +} from "../../extension-api/types"; + +export type LayoutMode = "auto" | "split" | "stack"; +export type CursorLine = "row" | "number" | "off"; +export type SidebarVisibility = boolean | "auto"; +export type VcsMode = string; + +export interface CommonOptions { + mode?: LayoutMode; + cursorLine?: CursorLine; + vcs?: VcsMode; + theme?: string; + agentContext?: string; + pager?: boolean; + watch?: boolean; + /** Enable launch-scoped experimental review features. */ + experimental?: boolean; + /** Offload eligible large-diff highlighting for this launch. */ + fast?: boolean; + excludeUntracked?: boolean; + lineNumbers?: boolean; + tabWidth?: number; + wrapLines?: boolean; + hunkHeaders?: boolean; + menuBar?: boolean; + sidebar?: SidebarVisibility; + agentNotes?: boolean; + copyDecorations?: boolean; + promptSaveViewPreferences?: boolean; + transparentBackground?: boolean; + colorMoved?: boolean; + /** False only when `--no-extensions` disables user extension loading for this run. */ + extensions?: boolean; + /** Entry paths from repeated `--extension` flags, for development and testing. */ + extensionPaths?: string[]; +} + +/** + * Review requests extend the published input views rather than restating them, + * so an adapter written against the extension contract accepts the exact values + * Hunk's commands produce. `options` is the internal half: resolved CLI and + * config state that no adapter — bundled or third-party — needs to see. + */ +export interface VcsDiffCommandInput extends ExtensionVcsDiffInput { + options: CommonOptions; +} + +export interface VcsShowCommandInput extends ExtensionVcsShowInput { + options: CommonOptions; +} + +export interface VcsStashShowCommandInput extends ExtensionVcsStashShowInput { + options: CommonOptions; +} + +export interface FileCommandInput { + kind: "diff"; + left: string; + right: string; + options: CommonOptions; +} + +export interface PatchCommandInput { + kind: "patch"; + file?: string; + text?: string; + options: CommonOptions; +} + +export interface DiffToolCommandInput { + kind: "difftool"; + left: string; + right: string; + path?: string; + options: CommonOptions; +} + +export type CliInput = + | VcsDiffCommandInput + | VcsShowCommandInput + | VcsStashShowCommandInput + | FileCommandInput + | PatchCommandInput + | DiffToolCommandInput; + +/** + * Note provenance, and the filter `hunk session comment-list --type` accepts. + * Declared here because the session command inputs name them; `core/types` + * re-exports both for the review model and the session surfaces. + */ +export type ReviewNoteSource = "ai" | "agent" | "user"; +export type SessionCommentListType = "live" | "all" | ReviewNoteSource; + +export interface HelpCommandInput { + kind: "help"; + text: string; +} + +export interface PagerCommandInput { + kind: "pager"; + options: CommonOptions; +} + +export interface DaemonServeCommandInput { + kind: "daemon-serve"; +} + +export type SessionCommandOutput = "text" | "json"; + +export interface SessionSelectorInput { + sessionId?: string; + sessionPath?: string; + repoRoot?: string; + /** Nearest project boundary known for this repo-path selector. */ + repoBoundary?: string; +} + +export interface SessionListCommandInput { + kind: "session"; + action: "list"; + output: SessionCommandOutput; +} + +export interface SessionGetCommandInput { + kind: "session"; + action: "get" | "context"; + output: SessionCommandOutput; + selector: SessionSelectorInput; +} + +export interface SessionReviewCommandInput { + kind: "session"; + action: "review"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + includePatch: boolean; + includeNotes?: boolean; +} + +export interface SessionNavigateCommandInput { + kind: "session"; + action: "navigate"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + filePath?: string; + hunkNumber?: number; + side?: "old" | "new"; + line?: number; + commentDirection?: "next" | "prev"; +} + +export interface SessionReloadCommandInput { + kind: "session"; + action: "reload"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + nextInput: CliInput; + sourcePath?: string; +} + +export interface SessionCommentAddCommandInput { + kind: "session"; + action: "comment-add"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + filePath: string; + side: "old" | "new"; + line: number; + summary: string; + rationale?: string; + markup?: string; + author?: string; + reveal: boolean; +} + +export interface SessionCommentApplyItemInput { + filePath: string; + hunkNumber?: number; + side?: "old" | "new"; + line?: number; + summary: string; + rationale?: string; + markup?: string; + author?: string; +} + +export interface SessionCommentApplyCommandInput { + kind: "session"; + action: "comment-apply"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + comments: SessionCommentApplyItemInput[]; + revealMode: "none" | "first"; +} + +export interface SessionCommentListCommandInput { + kind: "session"; + action: "comment-list"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + filePath?: string; + type?: SessionCommentListType; +} + +export interface SessionCommentRemoveCommandInput { + kind: "session"; + action: "comment-rm"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + commentId: string; +} + +export interface SessionCommentClearCommandInput { + kind: "session"; + action: "comment-clear"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + filePath?: string; + includeUser?: boolean; + confirmed: boolean; +} + +export interface SessionHighlightAddCommandInput { + kind: "session"; + action: "highlight-add"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + filePath: string; + side: "old" | "new"; + line: number; + /** 0-based inclusive UTF-16 code-unit offset into the line's raw text. */ + start: number; + /** Exclusive end offset; must exceed `start`. */ + end: number; + tone?: "match" | "current" | "info" | "warning" | "error"; + reveal: boolean; +} + +export interface SessionHighlightClearCommandInput { + kind: "session"; + action: "highlight-clear"; + output: SessionCommandOutput; + selector: SessionSelectorInput; + filePath?: string; +} + +export type SessionCommandInput = + | SessionListCommandInput + | SessionGetCommandInput + | SessionReviewCommandInput + | SessionNavigateCommandInput + | SessionReloadCommandInput + | SessionCommentAddCommandInput + | SessionCommentApplyCommandInput + | SessionCommentListCommandInput + | SessionCommentRemoveCommandInput + | SessionCommentClearCommandInput + | SessionHighlightAddCommandInput + | SessionHighlightClearCommandInput; + +export interface MarkupRenderCommandInput { + kind: "markup-render"; + /** Markup source path, or "-" for stdin. */ + file: string; + width: number; + color: "auto" | "always" | "never"; + theme?: string; + json: boolean; +} + +export interface MarkupGuideCommandInput { + kind: "markup-guide"; +} + +export interface ExtensionInstallCommandInput { + kind: "extension-manage"; + action: "install"; + /** Install source spec: owner/repo, git:host/path, a git URL, or a local path. */ + source: string; + /** Skip the interactive confirmation (required when stdin is not a TTY). */ + yes: boolean; +} + +export interface ExtensionListCommandInput { + kind: "extension-manage"; + action: "list"; +} + +export interface ExtensionUpdateCommandInput { + kind: "extension-manage"; + action: "update"; + /** One managed install to update; every managed install when omitted. */ + name?: string; +} + +export interface ExtensionRemoveCommandInput { + kind: "extension-manage"; + action: "remove"; + name: string; +} + +/** `hunk extension ...` managed-install commands. */ +export type ExtensionManageCommandInput = + | ExtensionInstallCommandInput + | ExtensionListCommandInput + | ExtensionUpdateCommandInput + | ExtensionRemoveCommandInput; + +export type ParsedCliInput = + | CliInput + | HelpCommandInput + | PagerCommandInput + | DaemonServeCommandInput + | SessionCommandInput + | MarkupRenderCommandInput + | MarkupGuideCommandInput + | ExtensionManageCommandInput; diff --git a/src/core/config.test.ts b/src/core/invocation/config.test.ts similarity index 99% rename from src/core/config.test.ts rename to src/core/invocation/config.test.ts index c0459b72e..a15c4d686 100644 --- a/src/core/config.test.ts +++ b/src/core/invocation/config.test.ts @@ -2,16 +2,16 @@ import { afterEach, describe, expect, test } from "bun:test"; import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import type { CliInput } from "./types"; +import { getBundledVcsCatalog } from "../../app/vcsCatalog"; +import type { CliInput } from "../types"; import { diffPersistedViewPreferences, resolveConfiguredCliInput, saveGlobalViewPreferences, saveViewPreferencesPromptPreference, } from "./config"; -import { loadAppBootstrap } from "./changeset/loaders"; -import { LEGACY_CUSTOM_SYNTAX_NOTICE, LEGACY_CUSTOM_SYNTAX_NOTICES } from "./startupNotice"; +import { loadAppBootstrap } from "../changeset/loaders"; +import { LEGACY_CUSTOM_SYNTAX_NOTICE, LEGACY_CUSTOM_SYNTAX_NOTICES } from "../startupNotice"; const tempDirs: string[] = []; diff --git a/src/core/config.ts b/src/core/invocation/config.ts similarity index 99% rename from src/core/config.ts rename to src/core/invocation/config.ts index 850a560a8..cee0f4225 100644 --- a/src/core/config.ts +++ b/src/core/invocation/config.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import { dirname, join } from "node:path"; -import { sanitizeTerminalLine } from "../lib/terminalText"; -import { BUNDLED_SHIKI_THEME_IDS, LEGACY_THEME_ID_ALIASES } from "./theme/catalog"; +import { sanitizeTerminalLine } from "../../lib/terminalText"; +import { BUNDLED_SHIKI_THEME_IDS, LEGACY_THEME_ID_ALIASES } from "../theme/catalog"; import { createInvalidThemeIdNotice, createThemeCollisionNotice, @@ -11,17 +11,17 @@ import { LEGACY_CUSTOM_THEME_ID, normalizeThemeColorValue, resolveThemeBase, -} from "./theme/customThemes"; +} from "../theme/customThemes"; import { LEGACY_CUSTOM_SYNTAX_COLOR_KEYS, resolveSyntaxScopeOverrides, -} from "./theme/legacySyntaxScopes"; +} from "../theme/legacySyntaxScopes"; import { resolveGlobalConfigPath } from "./paths"; -import { LEGACY_CUSTOM_SYNTAX_NOTICES, type StartupNotice } from "./startupNotice"; +import { LEGACY_CUSTOM_SYNTAX_NOTICES, type StartupNotice } from "../startupNotice"; import { DEFAULT_TAB_WIDTH, validateTabWidth } from "./tabWidth"; -import { findProjectRootCandidate } from "./projectRoot"; -import { createVcsCatalog, detectVcs } from "./vcs"; -import type { VcsCatalog } from "./vcs/types"; +import { findProjectRootCandidate } from "../projectRoot"; +import { createVcsCatalog, detectVcs } from "../vcs"; +import type { VcsCatalog } from "../vcs/types"; import type { CliInput, CommonOptions, @@ -35,7 +35,7 @@ import type { SidebarVisibility, UserKeyBinding, VcsMode, -} from "./types"; +} from "../types"; export const BUILT_IN_THEME_IDS = BUNDLED_SHIKI_THEME_IDS; // Widen the large literal tuple before formatting it, avoiding TypeScript's deep tuple inference. diff --git a/src/core/errors.test.ts b/src/core/invocation/errors.test.ts similarity index 96% rename from src/core/errors.test.ts rename to src/core/invocation/errors.test.ts index 8242177b5..fc6744691 100644 --- a/src/core/errors.test.ts +++ b/src/core/invocation/errors.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, test } from "bun:test"; import { formatCliError, HunkUserError, isUserFacingError } from "./errors"; -import { HunkExtensionUserError } from "../extension-api/types"; +import { HunkExtensionUserError } from "../../extension-api/types"; const originalDebug = process.env.HUNK_DEBUG; diff --git a/src/core/errors.ts b/src/core/invocation/errors.ts similarity index 98% rename from src/core/errors.ts rename to src/core/invocation/errors.ts index bc9ac9222..8e96f7003 100644 --- a/src/core/errors.ts +++ b/src/core/invocation/errors.ts @@ -1,4 +1,4 @@ -import { HUNK_EXTENSION_USER_ERROR_NAME, HunkExtensionUserError } from "../extension-api/types"; +import { HUNK_EXTENSION_USER_ERROR_NAME, HunkExtensionUserError } from "../../extension-api/types"; /** * A failure Hunk raises because of how it was invoked, not because of a bug. diff --git a/src/core/experimental.test.ts b/src/core/invocation/experimental.test.ts similarity index 97% rename from src/core/experimental.test.ts rename to src/core/invocation/experimental.test.ts index a0d034b21..d16c51ac3 100644 --- a/src/core/experimental.test.ts +++ b/src/core/invocation/experimental.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { createTestAgentFileContext, createTestDiffFile } from "../../test/helpers/diff-helpers"; +import { createTestAgentFileContext, createTestDiffFile } from "../../../test/helpers/diff-helpers"; import { resolveExperimentalDiffFiles, resolveExperimentalFeatures } from "./experimental"; describe("experimental review features", () => { diff --git a/src/core/experimental.ts b/src/core/invocation/experimental.ts similarity index 99% rename from src/core/experimental.ts rename to src/core/invocation/experimental.ts index 8a4362988..c842d09af 100644 --- a/src/core/experimental.ts +++ b/src/core/invocation/experimental.ts @@ -1,4 +1,4 @@ -import type { AgentFileContext, CommonOptions, DiffFile } from "./types"; +import type { AgentFileContext, CommonOptions, DiffFile } from "../types"; export const EXPERIMENTAL_FEATURES = ["stml"] as const; export type ExperimentalFeature = (typeof EXPERIMENTAL_FEATURES)[number]; diff --git a/src/core/inputReload.ts b/src/core/invocation/inputReload.ts similarity index 94% rename from src/core/inputReload.ts rename to src/core/invocation/inputReload.ts index 136025a10..f300b1980 100644 --- a/src/core/inputReload.ts +++ b/src/core/invocation/inputReload.ts @@ -8,7 +8,7 @@ * signature machinery so those callers can ask it without pulling either in. */ -import type { CliInput } from "./types"; +import type { CliInput } from "../types"; /** Return whether the current input can be rebuilt from files or VCS state without rereading stdin. */ export function canReloadInput(input: CliInput) { diff --git a/src/core/paths.test.ts b/src/core/invocation/paths.test.ts similarity index 100% rename from src/core/paths.test.ts rename to src/core/invocation/paths.test.ts diff --git a/src/core/paths.ts b/src/core/invocation/paths.ts similarity index 100% rename from src/core/paths.ts rename to src/core/invocation/paths.ts diff --git a/src/core/tabWidth.ts b/src/core/invocation/tabWidth.ts similarity index 100% rename from src/core/tabWidth.ts rename to src/core/invocation/tabWidth.ts diff --git a/src/core/version.ts b/src/core/invocation/version.ts similarity index 83% rename from src/core/version.ts rename to src/core/invocation/version.ts index 795778a40..69ae8f439 100644 --- a/src/core/version.ts +++ b/src/core/invocation/version.ts @@ -1,4 +1,4 @@ -import packageJson from "../../package.json" with { type: "json" }; +import packageJson from "../../../package.json" with { type: "json" }; export const UNKNOWN_CLI_VERSION = "0.0.0-unknown"; diff --git a/src/core/types.ts b/src/core/types.ts index 146640e2f..103d4b277 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -2,11 +2,10 @@ import type { NamedCustomThemeConfig } from "../extension-api/types"; import type { Changeset, DiffFile } from "./changeset/model"; import type { CliInput, - CommonOptions, CursorLine, LayoutMode, SidebarVisibility, -} from "./commandInputs"; +} from "./invocation/commandInputs"; import type { StartupNotice } from "./startupNotice"; import type { VcsCatalog } from "./vcs/types"; @@ -26,9 +25,12 @@ export type { } from "../extension-api/types"; /** - * The changeset model and command-input shapes moved to leaf modules so the - * VCS contract and watch planning can import them without this module's - * app-facing layer; they are re-exported here to keep one import site. + * The changeset model and the command-input shapes moved to leaf modules — + * `changeset/model` and `invocation/commandInputs` — so the VCS contract, watch + * planning, and the session surfaces can import them without this module's + * app-facing layer; they are re-exported here to keep one import site. Only the + * names other modules actually reach for are listed; the union members nothing + * imports stay where they are declared. */ export type { Changeset, @@ -42,21 +44,39 @@ export type { CommonOptions, CursorLine, DiffToolCommandInput, + ExtensionManageCommandInput, FileCommandInput, + HelpCommandInput, LayoutMode, + MarkupRenderCommandInput, + PagerCommandInput, + ParsedCliInput, PatchCommandInput, + ReviewNoteSource, + SessionCommandInput, + SessionCommandOutput, + SessionCommentAddCommandInput, + SessionCommentApplyCommandInput, + SessionCommentApplyItemInput, + SessionCommentClearCommandInput, + SessionCommentListCommandInput, + SessionCommentListType, + SessionCommentRemoveCommandInput, + SessionHighlightAddCommandInput, + SessionHighlightClearCommandInput, + SessionNavigateCommandInput, + SessionReloadCommandInput, + SessionReviewCommandInput, + SessionSelectorInput, SidebarVisibility, VcsDiffCommandInput, VcsMode, VcsShowCommandInput, VcsStashShowCommandInput, -} from "./commandInputs"; +} from "./invocation/commandInputs"; export type TerminalThemeMode = "light" | "dark"; -export type ReviewNoteSource = "ai" | "agent" | "user"; -export type SessionCommentListType = "live" | "all" | ReviewNoteSource; - export interface UserNoteLineTarget { side: "old" | "new"; line: number; @@ -102,231 +122,6 @@ export interface PersistedViewPreferences { cursorLine: CursorLine; } -export interface HelpCommandInput { - kind: "help"; - text: string; -} - -export interface PagerCommandInput { - kind: "pager"; - options: CommonOptions; -} - -export interface DaemonServeCommandInput { - kind: "daemon-serve"; -} - -export type SessionCommandOutput = "text" | "json"; - -export interface SessionSelectorInput { - sessionId?: string; - sessionPath?: string; - repoRoot?: string; - /** Nearest project boundary known for this repo-path selector. */ - repoBoundary?: string; -} - -export interface SessionListCommandInput { - kind: "session"; - action: "list"; - output: SessionCommandOutput; -} - -export interface SessionGetCommandInput { - kind: "session"; - action: "get" | "context"; - output: SessionCommandOutput; - selector: SessionSelectorInput; -} - -export interface SessionReviewCommandInput { - kind: "session"; - action: "review"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - includePatch: boolean; - includeNotes?: boolean; -} - -export interface SessionNavigateCommandInput { - kind: "session"; - action: "navigate"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - filePath?: string; - hunkNumber?: number; - side?: "old" | "new"; - line?: number; - commentDirection?: "next" | "prev"; -} - -export interface SessionReloadCommandInput { - kind: "session"; - action: "reload"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - nextInput: CliInput; - sourcePath?: string; -} - -export interface SessionCommentAddCommandInput { - kind: "session"; - action: "comment-add"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - filePath: string; - side: "old" | "new"; - line: number; - summary: string; - rationale?: string; - markup?: string; - author?: string; - reveal: boolean; -} - -export interface SessionCommentApplyItemInput { - filePath: string; - hunkNumber?: number; - side?: "old" | "new"; - line?: number; - summary: string; - rationale?: string; - markup?: string; - author?: string; -} - -export interface SessionCommentApplyCommandInput { - kind: "session"; - action: "comment-apply"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - comments: SessionCommentApplyItemInput[]; - revealMode: "none" | "first"; -} - -export interface SessionCommentListCommandInput { - kind: "session"; - action: "comment-list"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - filePath?: string; - type?: SessionCommentListType; -} - -export interface SessionCommentRemoveCommandInput { - kind: "session"; - action: "comment-rm"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - commentId: string; -} - -export interface SessionCommentClearCommandInput { - kind: "session"; - action: "comment-clear"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - filePath?: string; - includeUser?: boolean; - confirmed: boolean; -} - -export interface SessionHighlightAddCommandInput { - kind: "session"; - action: "highlight-add"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - filePath: string; - side: "old" | "new"; - line: number; - /** 0-based inclusive UTF-16 code-unit offset into the line's raw text. */ - start: number; - /** Exclusive end offset; must exceed `start`. */ - end: number; - tone?: "match" | "current" | "info" | "warning" | "error"; - reveal: boolean; -} - -export interface SessionHighlightClearCommandInput { - kind: "session"; - action: "highlight-clear"; - output: SessionCommandOutput; - selector: SessionSelectorInput; - filePath?: string; -} - -export type SessionCommandInput = - | SessionListCommandInput - | SessionGetCommandInput - | SessionReviewCommandInput - | SessionNavigateCommandInput - | SessionReloadCommandInput - | SessionCommentAddCommandInput - | SessionCommentApplyCommandInput - | SessionCommentListCommandInput - | SessionCommentRemoveCommandInput - | SessionCommentClearCommandInput - | SessionHighlightAddCommandInput - | SessionHighlightClearCommandInput; - -export interface MarkupRenderCommandInput { - kind: "markup-render"; - /** Markup source path, or "-" for stdin. */ - file: string; - width: number; - color: "auto" | "always" | "never"; - theme?: string; - json: boolean; -} - -export interface MarkupGuideCommandInput { - kind: "markup-guide"; -} - -export interface ExtensionInstallCommandInput { - kind: "extension-manage"; - action: "install"; - /** Install source spec: owner/repo, git:host/path, a git URL, or a local path. */ - source: string; - /** Skip the interactive confirmation (required when stdin is not a TTY). */ - yes: boolean; -} - -export interface ExtensionListCommandInput { - kind: "extension-manage"; - action: "list"; -} - -export interface ExtensionUpdateCommandInput { - kind: "extension-manage"; - action: "update"; - /** One managed install to update; every managed install when omitted. */ - name?: string; -} - -export interface ExtensionRemoveCommandInput { - kind: "extension-manage"; - action: "remove"; - name: string; -} - -/** `hunk extension ...` managed-install commands. */ -export type ExtensionManageCommandInput = - | ExtensionInstallCommandInput - | ExtensionListCommandInput - | ExtensionUpdateCommandInput - | ExtensionRemoveCommandInput; - -export type ParsedCliInput = - | CliInput - | HelpCommandInput - | PagerCommandInput - | DaemonServeCommandInput - | SessionCommandInput - | MarkupRenderCommandInput - | MarkupGuideCommandInput - | ExtensionManageCommandInput; - export interface ReloadContext { cwd: string; repoRoot?: string; diff --git a/src/core/updateNotice.ts b/src/core/updateNotice.ts index 7d8865b19..fd5a88899 100644 --- a/src/core/updateNotice.ts +++ b/src/core/updateNotice.ts @@ -1,8 +1,8 @@ import { posix, win32 } from "node:path"; import { readAppStateRecord, updateAppStateRecord } from "./appStateFile"; -import { resolveAppStatePath } from "./paths"; +import { resolveAppStatePath } from "./invocation/paths"; import type { StartupNotice } from "./startupNotice"; -import { resolveCliVersion, UNKNOWN_CLI_VERSION } from "./version"; +import { resolveCliVersion, UNKNOWN_CLI_VERSION } from "./invocation/version"; const DIST_TAGS_URL = "https://registry.npmjs.org/-/package/hunkdiff/dist-tags"; const STABLE_SEMVER_PATTERN = /^\d+\.\d+\.\d+$/; diff --git a/src/core/vcs/index.test.ts b/src/core/vcs/index.test.ts index 1a5179bab..4abf50083 100644 --- a/src/core/vcs/index.test.ts +++ b/src/core/vcs/index.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { HunkUserError } from "../errors"; +import { HunkUserError } from "../invocation/errors"; import { createUnsupportedVcsOperationError, createVcsCatalog, diff --git a/src/core/vcs/index.ts b/src/core/vcs/index.ts index b15a89ec8..59ff89805 100644 --- a/src/core/vcs/index.ts +++ b/src/core/vcs/index.ts @@ -1,7 +1,7 @@ import { relative, resolve } from "node:path"; import { HUNK_DEFAULT_VCS_DETECTION_PRIORITY } from "../../extension-api/types"; -import { HunkUserError } from "../errors"; -import type { CliInput } from "../commandInputs"; +import { HunkUserError } from "../invocation/errors"; +import type { CliInput } from "../invocation/commandInputs"; import type { VcsAdapter, VcsCatalog, diff --git a/src/core/vcs/types.ts b/src/core/vcs/types.ts index dbe33a45d..8944ae090 100644 --- a/src/core/vcs/types.ts +++ b/src/core/vcs/types.ts @@ -4,7 +4,7 @@ import type { VcsDiffCommandInput, VcsShowCommandInput, VcsStashShowCommandInput, -} from "../commandInputs"; +} from "../invocation/commandInputs"; import type { BuildDiffFileOptions } from "../changeset/diffFile"; export type VcsId = string; diff --git a/src/core/watch/plan.ts b/src/core/watch/plan.ts index e31be886c..c46820029 100644 --- a/src/core/watch/plan.ts +++ b/src/core/watch/plan.ts @@ -7,7 +7,7 @@ import type { ExtensionVcsWatchTargetSource, } from "../../extension-api/types"; import { normalizePathForOS } from "../../lib/osPath"; -import type { CliInput } from "../commandInputs"; +import type { CliInput } from "../invocation/commandInputs"; import { createVcsWatchPlan, getConfiguredVcsAdapter, operationFromInput } from "../vcs"; import type { VcsCatalog } from "../vcs/types"; diff --git a/src/core/watch/signature.ts b/src/core/watch/signature.ts index 7e198a405..6384ee703 100644 --- a/src/core/watch/signature.ts +++ b/src/core/watch/signature.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import { resolve } from "node:path"; import { createVcsWatchSignature, getConfiguredVcsAdapter, operationFromInput } from "../vcs"; -import type { CliInput } from "../commandInputs"; +import type { CliInput } from "../invocation/commandInputs"; import type { VcsCatalog } from "../vcs/types"; /** Format one file stat into a stable signature fragment, or mark the path missing. */ diff --git a/src/extensions/discovery.ts b/src/extensions/discovery.ts index 0c58ce53b..9f6591de5 100644 --- a/src/extensions/discovery.ts +++ b/src/extensions/discovery.ts @@ -1,7 +1,10 @@ import fs from "node:fs"; import { homedir } from "node:os"; import { basename, isAbsolute, join, resolve } from "node:path"; -import { INSTALLED_EXTENSIONS_DIR_NAME, resolveGlobalExtensionsDir } from "../core/paths"; +import { + INSTALLED_EXTENSIONS_DIR_NAME, + resolveGlobalExtensionsDir, +} from "../core/invocation/paths"; import { findProjectRootCandidate } from "../core/projectRoot"; import { deriveExtensionId, type ExtensionCandidate, type ExtensionOrigin } from "./types"; diff --git a/src/extensions/manage/cli.ts b/src/extensions/manage/cli.ts index 42f1af87f..0744a6661 100644 --- a/src/extensions/manage/cli.ts +++ b/src/extensions/manage/cli.ts @@ -1,5 +1,5 @@ -import { HunkUserError } from "../../core/errors"; -import { resolveInstalledExtensionsRoot } from "../../core/paths"; +import { HunkUserError } from "../../core/invocation/errors"; +import { resolveInstalledExtensionsRoot } from "../../core/invocation/paths"; import type { ExtensionManageCommandInput } from "../../core/types"; import { installExtension, diff --git a/src/extensions/manage/install.ts b/src/extensions/manage/install.ts index 7c8558c14..18392787c 100644 --- a/src/extensions/manage/install.ts +++ b/src/extensions/manage/install.ts @@ -1,6 +1,6 @@ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync } from "node:fs"; import { basename, dirname, join } from "node:path"; -import { HunkUserError } from "../../core/errors"; +import { HunkUserError } from "../../core/invocation/errors"; import { directoryContainsExtensionEntries } from "../discovery"; import { readInstallRecords, writeInstallRecords, type ExtensionInstallRecord } from "./records"; import type { ExtensionInstallSource } from "./source"; diff --git a/src/extensions/runExtension.ts b/src/extensions/runExtension.ts index 517510366..3bec8a738 100644 --- a/src/extensions/runExtension.ts +++ b/src/extensions/runExtension.ts @@ -22,7 +22,7 @@ import { type HunkExtensionAPI, } from "./types"; import { parseKeyChord, toKeyChordList } from "../lib/commandKeys"; -import { toUserFacingError } from "../core/errors"; +import { toUserFacingError } from "../core/invocation/errors"; import { toInternalVcsPatchResult } from "./vcsPatchResult"; import type { ExtensionVcsOperation } from "../extension-api/types"; import type { VcsAdapter, VcsOperation, VcsReviewInput } from "../core/vcs/types"; diff --git a/src/extensions/trust.test.ts b/src/extensions/trust.test.ts index 014d806fb..aaa972d6a 100644 --- a/src/extensions/trust.test.ts +++ b/src/extensions/trust.test.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; -import { resolveCanonicalPath } from "../core/paths"; +import { resolveCanonicalPath } from "../core/invocation/paths"; import { join, resolve } from "node:path"; import { loadExtensions } from "./host"; import { readExtensionTrust, resolveRepoTrust, writeExtensionTrust } from "./trust"; diff --git a/src/extensions/trust.ts b/src/extensions/trust.ts index 2ee40a02c..b979bee31 100644 --- a/src/extensions/trust.ts +++ b/src/extensions/trust.ts @@ -1,6 +1,6 @@ import { resolve } from "node:path"; import { readAppStateRecord, updateAppStateRecord } from "../core/appStateFile"; -import { resolveCanonicalPath, resolveAppStatePath } from "../core/paths"; +import { resolveCanonicalPath, resolveAppStatePath } from "../core/invocation/paths"; /** * Repo-local extensions run arbitrary code from the repository under review, diff --git a/src/extensions/vcsPatchResult.test.ts b/src/extensions/vcsPatchResult.test.ts index a53701cbb..0b2d3201e 100644 --- a/src/extensions/vcsPatchResult.test.ts +++ b/src/extensions/vcsPatchResult.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { toInternalVcsPatchResult } from "./vcsPatchResult"; import { HunkExtensionUserError } from "../extension-api/types"; -import { HunkUserError, toUserFacingError } from "../core/errors"; +import { HunkUserError, toUserFacingError } from "../core/invocation/errors"; import { SourceTextTooLargeError } from "../core/changeset/fileSource"; import { toInternalVcsAdapter } from "./runExtension"; import type { diff --git a/src/main.tsx b/src/main.tsx index 069d08d43..1681f4f44 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { formatCliError } from "./core/errors"; +import { formatCliError } from "./core/invocation/errors"; import { pagePlainText } from "./core/pager"; import { prepareStartupPlan } from "./app/startup"; import { sanitizeTerminalText } from "./lib/terminalText"; diff --git a/src/opentui/HunkDiffBody.tsx b/src/opentui/HunkDiffBody.tsx index 0d20be36b..4a238b6d6 100644 --- a/src/opentui/HunkDiffBody.tsx +++ b/src/opentui/HunkDiffBody.tsx @@ -1,5 +1,5 @@ import { useMemo } from "react"; -import { DEFAULT_TAB_WIDTH } from "../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../core/invocation/tabWidth"; import { findMaxLineNumber } from "../ui/diff/codeColumns"; import { buildSplitRows, buildStackRows } from "../ui/diff/diffRows"; import { diffMessage, DiffRowView, fitText } from "../ui/diff/renderRows"; diff --git a/src/session/broker/wire.ts b/src/session/broker/wire.ts index cd270845a..9ae429269 100644 --- a/src/session/broker/wire.ts +++ b/src/session/broker/wire.ts @@ -1,4 +1,7 @@ -import { EXPERIMENTAL_FEATURES, type ExperimentalFeature } from "../../core/experimental"; +import { + EXPERIMENTAL_FEATURES, + type ExperimentalFeature, +} from "../../core/invocation/experimental"; import type { CliInput } from "../../core/types"; import { MAX_REGISTRATION_FILES, diff --git a/src/session/client/daemonHttp.ts b/src/session/client/daemonHttp.ts index 9b834abc3..7dee703c2 100644 --- a/src/session/client/daemonHttp.ts +++ b/src/session/client/daemonHttp.ts @@ -1,4 +1,4 @@ -import { HunkUserError } from "../../core/errors"; +import { HunkUserError } from "../../core/invocation/errors"; import { resolveSessionBrokerConfig, type ResolvedSessionBrokerConfig, diff --git a/src/session/types.ts b/src/session/types.ts index 381b388e9..a6d54a1df 100644 --- a/src/session/types.ts +++ b/src/session/types.ts @@ -1,4 +1,4 @@ -import type { ExperimentalFeature } from "../core/experimental"; +import type { ExperimentalFeature } from "../core/invocation/experimental"; import type { ExtensionLineHighlightTone, SessionReloadReason } from "../extension-api/types"; import type { CommentTargetInput, DiffSide } from "../core/liveComments"; import type { ReviewPublicationAddress } from "../core/review/generationOrder"; diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 718682816..18bef4949 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -19,9 +19,12 @@ import { diffPersistedViewPreferences, saveGlobalViewPreferences, saveViewPreferencesPromptPreference, -} from "../core/config"; -import { experimentalFeatureEnabled, resolveExperimentalDiffFiles } from "../core/experimental"; -import { DEFAULT_TAB_WIDTH } from "../core/tabWidth"; +} from "../core/invocation/config"; +import { + experimentalFeatureEnabled, + resolveExperimentalDiffFiles, +} from "../core/invocation/experimental"; +import { DEFAULT_TAB_WIDTH } from "../core/invocation/tabWidth"; import { isVcsReviewInput } from "../core/vcs"; import type { AppBootstrap, @@ -31,7 +34,7 @@ import type { PersistedViewPreferences, UserNoteLineTarget, } from "../core/types"; -import { canReloadInput } from "../core/inputReload"; +import { canReloadInput } from "../core/invocation/inputReload"; import { sanitizeTerminalLine } from "../lib/terminalText"; import { resolveExtensionCommands, diff --git a/src/ui/AppHost.keybindings.test.tsx b/src/ui/AppHost.keybindings.test.tsx index 9c984f95c..ad6ff613e 100644 --- a/src/ui/AppHost.keybindings.test.tsx +++ b/src/ui/AppHost.keybindings.test.tsx @@ -6,7 +6,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import { removeTestDirectory } from "../../test/helpers/filesystem"; -import { resolveConfiguredCliInput } from "../core/config"; +import { resolveConfiguredCliInput } from "../core/invocation/config"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; import { loadAppBootstrap } from "../core/changeset/loaders"; import type { AppBootstrap } from "../core/types"; diff --git a/src/ui/AppHost.tsx b/src/ui/AppHost.tsx index 54bee9241..9381ef50c 100644 --- a/src/ui/AppHost.tsx +++ b/src/ui/AppHost.tsx @@ -3,7 +3,7 @@ import { resolveConfiguredExtensions } from "../app/extensionBootstrap"; import { ReviewProducer } from "../app/review/producer"; import { loadConfiguredSessionBootstrap } from "../app/sessionBootstrap"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import { resolveConfiguredCliInput } from "../core/config"; +import { resolveConfiguredCliInput } from "../core/invocation/config"; import { resolveRuntimeCliInput } from "../core/terminal"; import type { StartupNotice } from "../core/startupNotice"; import type { AppBootstrap, CliInput } from "../core/types"; diff --git a/src/ui/components/panes/DiffPane.tsx b/src/ui/components/panes/DiffPane.tsx index d02823dae..9b242cf53 100644 --- a/src/ui/components/panes/DiffPane.tsx +++ b/src/ui/components/panes/DiffPane.tsx @@ -13,7 +13,7 @@ import { useState, type RefObject, } from "react"; -import { DEFAULT_TAB_WIDTH } from "../../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../../core/invocation/tabWidth"; import type { AgentAnnotation, CursorLine, diff --git a/src/ui/diff/DiffSectionBody.tsx b/src/ui/diff/DiffSectionBody.tsx index 2e21d1fca..d060a779a 100644 --- a/src/ui/diff/DiffSectionBody.tsx +++ b/src/ui/diff/DiffSectionBody.tsx @@ -6,7 +6,7 @@ */ import { useRenderer } from "@opentui/react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { DEFAULT_TAB_WIDTH } from "../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; import type { DiffFile, LayoutMode, UserNoteLineTarget } from "../../core/types"; import { AgentInlineNote } from "../components/panes/AgentInlineNote"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; diff --git a/src/ui/diff/codeColumns.ts b/src/ui/diff/codeColumns.ts index f56070ffb..04a276968 100644 --- a/src/ui/diff/codeColumns.ts +++ b/src/ui/diff/codeColumns.ts @@ -1,4 +1,4 @@ -import { DEFAULT_TAB_WIDTH, validateTabWidth } from "../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH, validateTabWidth } from "../../core/invocation/tabWidth"; import type { DiffFile, LayoutMode } from "../../core/types"; import { measureTextWidth } from "../lib/text"; import type { DiffRow } from "./diffRowModel"; diff --git a/src/ui/diff/diffRows.ts b/src/ui/diff/diffRows.ts index fbb2bd6de..a98187be0 100644 --- a/src/ui/diff/diffRows.ts +++ b/src/ui/diff/diffRows.ts @@ -20,7 +20,7 @@ import { reviewTrailingGap, type ReviewGapAddress, } from "../../core/review/expansion"; -import { DEFAULT_TAB_WIDTH } from "../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; import type { DiffFile, DiffLineMoveKind } from "../../core/types"; import { blendHex, hexColorDistance } from "../lib/color"; import { measureTextWidth } from "../lib/text"; diff --git a/src/ui/diff/diffSectionGeometry.ts b/src/ui/diff/diffSectionGeometry.ts index 402324fe8..d414074c9 100644 --- a/src/ui/diff/diffSectionGeometry.ts +++ b/src/ui/diff/diffSectionGeometry.ts @@ -1,4 +1,4 @@ -import { DEFAULT_TAB_WIDTH } from "../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; import type { DiffFile, LayoutMode } from "../../core/types"; import { measureAgentInlineNoteHeight } from "../components/panes/AgentInlineNote"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; diff --git a/src/ui/diff/diffSectionRowPlan.ts b/src/ui/diff/diffSectionRowPlan.ts index c07beaa15..5de658e4b 100644 --- a/src/ui/diff/diffSectionRowPlan.ts +++ b/src/ui/diff/diffSectionRowPlan.ts @@ -1,5 +1,5 @@ import { reviewExpansionSide } from "../../core/review/expansion"; -import { DEFAULT_TAB_WIDTH } from "../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; import type { DiffFile, LayoutMode } from "../../core/types"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; import type { AppTheme } from "../themes"; diff --git a/src/ui/diff/expandCollapsedRows.ts b/src/ui/diff/expandCollapsedRows.ts index e02f70727..be9d815a8 100644 --- a/src/ui/diff/expandCollapsedRows.ts +++ b/src/ui/diff/expandCollapsedRows.ts @@ -1,6 +1,6 @@ import { reviewGapId } from "../../core/review/expansion"; import { normalizedReviewSourceLines } from "../../core/review/geometry"; -import { DEFAULT_TAB_WIDTH } from "../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; import { sanitizeTerminalLine, sanitizeTerminalSpans } from "../../lib/terminalText"; import { expandDiffTabs } from "./codeColumns"; import type { diff --git a/src/ui/diff/lineHighlightPaint.test.ts b/src/ui/diff/lineHighlightPaint.test.ts index 8cd2bfc4f..0b955f25e 100644 --- a/src/ui/diff/lineHighlightPaint.test.ts +++ b/src/ui/diff/lineHighlightPaint.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; import { createTestDiffFile, lines } from "../../../test/helpers/diff-helpers"; -import { DEFAULT_TAB_WIDTH } from "../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; import type { ValidatedLineHighlight } from "../highlights/validate"; import { measureTextWidth } from "../lib/text"; import { expandDiffTabs } from "./codeColumns"; diff --git a/src/ui/diff/lineHighlightPaint.ts b/src/ui/diff/lineHighlightPaint.ts index 2f7d5e098..6a03fc2a0 100644 --- a/src/ui/diff/lineHighlightPaint.ts +++ b/src/ui/diff/lineHighlightPaint.ts @@ -18,7 +18,7 @@ import { type ReviewGapAddress, } from "../../core/review/expansion"; import { normalizedReviewSourceLines } from "../../core/review/geometry"; -import { DEFAULT_TAB_WIDTH } from "../../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; import type { DiffFile } from "../../core/types"; import type { ExtensionLineHighlightTone } from "../../extension-api/types"; import { sanitizeTerminalLine } from "../../lib/terminalText"; diff --git a/src/ui/hooks/useTerminalReview.test.tsx b/src/ui/hooks/useTerminalReview.test.tsx index 5cdcd2280..aa45818d7 100644 --- a/src/ui/hooks/useTerminalReview.test.tsx +++ b/src/ui/hooks/useTerminalReview.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, spyOn, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act, StrictMode, useEffect, useRef, useState } from "react"; -import { builtinAppCommand } from "../../core/commandCatalog"; +import { builtinAppCommand } from "../../core/invocation/commandCatalog"; import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; import type { DiffFile } from "../../core/types"; import { diff --git a/src/ui/hooks/useTerminalReview.ts b/src/ui/hooks/useTerminalReview.ts index 7568a57d2..a95634ac8 100644 --- a/src/ui/hooks/useTerminalReview.ts +++ b/src/ui/hooks/useTerminalReview.ts @@ -29,7 +29,7 @@ import { lowerAppCommandToReviewIntent, type AppCommandId, type AppCommandLoweringContext, -} from "../../core/commandCatalog"; +} from "../../core/invocation/commandCatalog"; import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; import { applyReviewIntent, diff --git a/src/ui/lib/appCommands.test.ts b/src/ui/lib/appCommands.test.ts index 55947e5c4..5e27830c4 100644 --- a/src/ui/lib/appCommands.test.ts +++ b/src/ui/lib/appCommands.test.ts @@ -12,7 +12,7 @@ import { type BuildAppCommandsOptions, type ResolvedCommandKeys, } from "./appCommands"; -import { APP_COMMAND_CATALOG } from "../../core/commandCatalog"; +import { APP_COMMAND_CATALOG } from "../../core/invocation/commandCatalog"; import { buildAppMenus } from "./appMenus"; import { buildHelpSections, HELP_COMMAND_IDS } from "./helpContent"; import { resolveCommandKeys } from "./keymap"; diff --git a/src/ui/lib/appCommands.ts b/src/ui/lib/appCommands.ts index 036d8f7bb..fc4ca52be 100644 --- a/src/ui/lib/appCommands.ts +++ b/src/ui/lib/appCommands.ts @@ -4,7 +4,7 @@ import { type AppCommandCatalogEntry, type AppCommandId, type VerticalCommandDirection, -} from "../../core/commandCatalog"; +} from "../../core/invocation/commandCatalog"; import type { ReviewSelectionScope } from "../../core/review/navigation"; import type { CursorLine, LayoutMode } from "../../core/types"; import type { ExtensionCommandExecutionOptions } from "../../extension-api/types"; diff --git a/src/ui/lib/extensionWorkspace.ts b/src/ui/lib/extensionWorkspace.ts index 0590c6190..0e7cb8e6b 100644 --- a/src/ui/lib/extensionWorkspace.ts +++ b/src/ui/lib/extensionWorkspace.ts @@ -20,7 +20,7 @@ import { isAbsolute, relative, resolve, sep } from "node:path"; import { normalizeDiffPath } from "../../core/changeset/diffPaths"; import type { FileSourceSide } from "../../core/changeset/fileSource"; -import { canReloadInput } from "../../core/inputReload"; +import { canReloadInput } from "../../core/invocation/inputReload"; import type { CliInput } from "../../core/types"; import { readMetadataChangeType } from "../../extensions/events"; diff --git a/src/ui/staticDiffPager.ts b/src/ui/staticDiffPager.ts index e132051ab..6b0d99969 100644 --- a/src/ui/staticDiffPager.ts +++ b/src/ui/staticDiffPager.ts @@ -16,7 +16,7 @@ */ import { loadAppBootstrap } from "../core/changeset/loaders"; import { reviewEmptyDiffReason, type ReviewEmptyDiffReason } from "../core/review/document"; -import { DEFAULT_TAB_WIDTH } from "../core/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../core/invocation/tabWidth"; import type { CommonOptions, DiffFile, NamedCustomThemeConfig } from "../core/types"; import { buildSplitRows, diff --git a/website/src/content/docs/docs/reference/config.md b/website/src/content/docs/docs/reference/config.md index f099a5dad..47bf83140 100644 --- a/website/src/content/docs/docs/reference/config.md +++ b/website/src/content/docs/docs/reference/config.md @@ -5,7 +5,7 @@ description: Exhaustive generated reference for Hunk TOML keys, defaults, aliase -Hunk reads TOML preferences from the user config and an optional repository config. This reference is generated from the same catalog that `src/core/config.ts` uses to parse preference keys. +Hunk reads TOML preferences from the user config and an optional repository config. This reference is generated from the same catalog that `src/core/invocation/config.ts` uses to parse preference keys. ## Resolution and scope From 91a1ffeeffff2cf2e91f513d51cd30e6d542d98c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 03:24:12 +0000 Subject: [PATCH 4/8] refactor(core): group process and terminal concerns into core/runtime/ Phase 3 of giving src/core an interior. terminal, pager, jobControl, shutdown, projectRoot, appStateFile, updateNotice, and startupNotice move from core root into core/runtime/. Pure move with no symbol renames; all eight have outside consumers, so the module declares no interior. core root now holds only types.ts, reviewDigest.ts, and liveComments.ts beside the module directories. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XcuayyxJrwQd9EHpuxNef1 --- docs/changelog-on-hunk-dev.md | 2 +- docs/extension-architecture.md | 2 +- docs/module-boundaries.md | 34 ++++++++++++++++----- docs/source-architecture.md | 3 ++ src/app/extensionBootstrap.ts | 2 +- src/app/session/reloadBounds.ts | 2 +- src/app/sessionSelector.ts | 2 +- src/app/startup.ts | 4 +-- src/core/invocation/config.test.ts | 5 ++- src/core/invocation/config.ts | 4 +-- src/core/{ => runtime}/appStateFile.test.ts | 0 src/core/{ => runtime}/appStateFile.ts | 0 src/core/{ => runtime}/jobControl.test.ts | 0 src/core/{ => runtime}/jobControl.ts | 0 src/core/{ => runtime}/pager.test.ts | 0 src/core/{ => runtime}/pager.ts | 4 +-- src/core/{ => runtime}/projectRoot.test.ts | 4 +-- src/core/{ => runtime}/projectRoot.ts | 2 +- src/core/{ => runtime}/shutdown.test.ts | 0 src/core/{ => runtime}/shutdown.ts | 0 src/core/{ => runtime}/startupNotice.ts | 0 src/core/{ => runtime}/terminal.test.ts | 2 +- src/core/{ => runtime}/terminal.ts | 2 +- src/core/{ => runtime}/updateNotice.test.ts | 0 src/core/{ => runtime}/updateNotice.ts | 4 +-- src/core/theme/customThemes.ts | 2 +- src/core/types.ts | 2 +- src/extensions/apply.ts | 2 +- src/extensions/discovery.ts | 2 +- src/extensions/host.ts | 2 +- src/extensions/manage/records.ts | 2 +- src/extensions/startup.ts | 2 +- src/extensions/trust.ts | 2 +- src/main.tsx | 2 +- src/ui/AppHost.interactions.test.tsx | 2 +- src/ui/AppHost.tsx | 4 +-- src/ui/hooks/useStartupNotices.ts | 2 +- src/ui/runInteractiveApp.tsx | 8 ++--- 38 files changed, 68 insertions(+), 44 deletions(-) rename src/core/{ => runtime}/appStateFile.test.ts (100%) rename src/core/{ => runtime}/appStateFile.ts (100%) rename src/core/{ => runtime}/jobControl.test.ts (100%) rename src/core/{ => runtime}/jobControl.ts (100%) rename src/core/{ => runtime}/pager.test.ts (100%) rename src/core/{ => runtime}/pager.ts (97%) rename src/core/{ => runtime}/projectRoot.test.ts (96%) rename src/core/{ => runtime}/projectRoot.ts (95%) rename src/core/{ => runtime}/shutdown.test.ts (100%) rename src/core/{ => runtime}/shutdown.ts (100%) rename src/core/{ => runtime}/startupNotice.ts (100%) rename src/core/{ => runtime}/terminal.test.ts (98%) rename src/core/{ => runtime}/terminal.ts (98%) rename src/core/{ => runtime}/updateNotice.test.ts (100%) rename src/core/{ => runtime}/updateNotice.ts (98%) diff --git a/docs/changelog-on-hunk-dev.md b/docs/changelog-on-hunk-dev.md index 5b34d27eb..ab8a19ad6 100644 --- a/docs/changelog-on-hunk-dev.md +++ b/docs/changelog-on-hunk-dev.md @@ -106,6 +106,6 @@ path list, or release commits will not trigger a deploy. launch-video pipeline keeps generated media out of Git. - **Contributor lists.** The GitHub release bodies name first-time contributors, which is community goodwill and organic links. `CHANGELOG.md` does not carry authors, so this needs a second input. -- **The in-app update notice.** `src/core/updateNotice.ts` tells users a new version exists without +- **The in-app update notice.** `src/core/runtime/updateNotice.ts` tells users a new version exists without linking what changed. Appending `hunk.dev/changelog/` is the highest-intent entry point available and is deliberately left as a separate change. diff --git a/docs/extension-architecture.md b/docs/extension-architecture.md index 1fe9600e1..6cf0c38f1 100644 --- a/docs/extension-architecture.md +++ b/docs/extension-architecture.md @@ -300,7 +300,7 @@ and exact-source reading — live entirely under `src/extensions/default/vcs//`. `src/extensions/vcsPatchResult.ts` is the one conversion boundary where a published `ExtensionVcsPatchResult` becomes Hunk's internal diff model, including structural `too-large` source -results. `src/core/projectRoot.ts` treats `.hunk` as a provider-independent +results. `src/core/runtime/projectRoot.ts` treats `.hunk` as a provider-independent bootstrap marker and also consults the available catalog; startup performs a second root/config pass when a global, config-path, or CLI adapter recognizes a repository unavailable to the bundled catalog. diff --git a/docs/module-boundaries.md b/docs/module-boundaries.md index 24862aeb2..8d143c4b0 100644 --- a/docs/module-boundaries.md +++ b/docs/module-boundaries.md @@ -110,6 +110,25 @@ those inputs name them and the leaf may not import `core/types` back: `SessionCommentListType` and the `ReviewNoteSource` it unions over. `core/types.ts` re-exports all of them, so no import site changed. +Phase 3 (2026-08-17) grouped **the process and terminal a run lives in** into `core/runtime/`: +TTY capability detection and runtime CLI-input resolution (`terminal`), the external pager and +its plain-text fallback (`pager`), SIGTSTP/SIGINT job control (`jobControl`), ordered session +teardown (`shutdown`), `.hunk`/VCS project-root discovery (`projectRoot`), the atomically +written app-state file (`appStateFile`), the version-check notice built on it (`updateNotice`), +and the startup-notice shape every tier reports through (`startupNotice`). The move is +path-only; no exported symbol changed, and `core/types.ts` now re-exports `StartupNotice` from +`runtime/startupNotice`. + +All eight are **public** — each has production importers outside the module — so this phase adds +no `runtime-internals-stay-in-module` rule; the grouping is its value. The audiences are worth +naming, because they are why these files never belonged at `core/*` root together with the review +model: `terminal`, `jobControl`, `shutdown`, and `updateNotice` serve the interactive surface; +`pager` serves the CLI entry and the startup plan; `projectRoot` and `appStateFile` serve the +extension host and config resolution. + +After this phase `src/core/` root holds only `types.ts`, `reviewDigest.ts`, and `liveComments.ts` +beside the seven subdirectories. Phase 4 melts what is left of `core/types.ts`. + ## Snapshot (2026-08-17, v0.19.0) 331 production modules, 1282 internal edges, **zero boundary violations and zero import @@ -149,14 +168,13 @@ rules: The tier rules now hold with no exceptions. Two follow-ups are worth doing next: -1. **Give `src/core` an interior.** _In progress (phases 0–2, see Module interiors)._ The - subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, `patch/`, and now `changeset/` and - `invocation/`) are coherent modules; the loose files still at `core/*` root are the remaining - grab-bag. Keep grouping them by audience — the process/runtime concerns next, then melting - what is left of `core/types.ts` — and give each group a rule restricting which of its files - other tiers may import. The review seam's - named modules (`document`, `geometry`, `state`, …) stay public; their helpers become - internal. +1. **Give `src/core` an interior.** _In progress (phases 0–3, see Module interiors)._ The + subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, `patch/`, and now `changeset/`, + `invocation/`, and `runtime/`) are coherent modules; `types.ts`, `reviewDigest.ts`, and + `liveComments.ts` are all that is left at `core/*` root. Melting what remains of + `core/types.ts` is the next step, giving each group a rule restricting which of its files + other tiers may import. The review seam's named modules (`document`, `geometry`, `state`, …) + stay public; their helpers become internal. 2. **Tighten the adapter allowlist.** `ui-couples-to-session-via-adapters` currently allowlists six files. As session coupling consolidates into `useTerminalReview` / `useHunkSessionBridge`, shrink the list. diff --git a/docs/source-architecture.md b/docs/source-architecture.md index 7e52a50e3..ede6100c0 100644 --- a/docs/source-architecture.md +++ b/docs/source-architecture.md @@ -15,6 +15,9 @@ src/core/changeset/ the changeset model and the pipeline that acquires one: loa per-file construction, sidecar/source reads, and hunk formatting src/core/invocation/ how a run is asked for: command inputs, layered configuration, the command catalog, user-facing errors, paths, and version +src/core/runtime/ the process and terminal a run lives in: TTY capabilities, the pager, + job control, shutdown, project-root discovery, persisted app state, + and startup/update notices src/core/theme/ bundled theme metadata, custom-theme rules, and terminal theme detection src/core/watch/ input signatures, observation plans/backends, and refresh coordination src/core/vcs/ provider-neutral VCS catalog, contracts, operation dispatch, and host support diff --git a/src/app/extensionBootstrap.ts b/src/app/extensionBootstrap.ts index a349ee932..eeaad2569 100644 --- a/src/app/extensionBootstrap.ts +++ b/src/app/extensionBootstrap.ts @@ -1,5 +1,5 @@ import { resolveConfiguredCliInput, type HunkConfigResolution } from "../core/invocation/config"; -import { findProjectRootCandidate } from "../core/projectRoot"; +import { findProjectRootCandidate } from "../core/runtime/projectRoot"; import type { CliInput } from "../core/types"; import { extendVcsCatalog } from "../core/vcs"; import type { VcsCatalog } from "../core/vcs/types"; diff --git a/src/app/session/reloadBounds.ts b/src/app/session/reloadBounds.ts index ee107d6ce..44f234851 100644 --- a/src/app/session/reloadBounds.ts +++ b/src/app/session/reloadBounds.ts @@ -1,6 +1,6 @@ import { isAbsolute, relative, resolve } from "node:path"; import { resolveCanonicalPath } from "../../core/invocation/paths"; -import { findProjectRootCandidate } from "../../core/projectRoot"; +import { findProjectRootCandidate } from "../../core/runtime/projectRoot"; import type { AppBootstrap, CliInput, CommonOptions } from "../../core/types"; import type { VcsCatalog } from "../../core/vcs/types"; diff --git a/src/app/sessionSelector.ts b/src/app/sessionSelector.ts index f590fecf2..dd1c6fd71 100644 --- a/src/app/sessionSelector.ts +++ b/src/app/sessionSelector.ts @@ -1,4 +1,4 @@ -import { findProjectRootCandidate } from "../core/projectRoot"; +import { findProjectRootCandidate } from "../core/runtime/projectRoot"; import type { SessionSelectorInput } from "../core/types"; import type { VcsCatalog } from "../core/vcs/types"; diff --git a/src/app/startup.ts b/src/app/startup.ts index c64c7d646..b7820709d 100644 --- a/src/app/startup.ts +++ b/src/app/startup.ts @@ -4,14 +4,14 @@ import type { loadStartupExtensions } from "../extensions/startup"; import { resolveConfiguredCliInput } from "../core/invocation/config"; import { HunkUserError } from "../core/invocation/errors"; import type { loadAppBootstrap } from "../core/changeset/loaders"; -import { looksLikePatchInput } from "../core/pager"; +import { looksLikePatchInput } from "../core/runtime/pager"; import { detectTerminalThemeModeFromBackground } from "../core/theme/detection"; import { openControllingTerminal, resolveRuntimeCliInput, usesPipedPatchInput, type ControllingTerminal, -} from "../core/terminal"; +} from "../core/runtime/terminal"; import type { AppBootstrap } from "./types"; import type { CliInput, diff --git a/src/core/invocation/config.test.ts b/src/core/invocation/config.test.ts index a15c4d686..58b53a4f6 100644 --- a/src/core/invocation/config.test.ts +++ b/src/core/invocation/config.test.ts @@ -11,7 +11,10 @@ import { saveViewPreferencesPromptPreference, } from "./config"; import { loadAppBootstrap } from "../changeset/loaders"; -import { LEGACY_CUSTOM_SYNTAX_NOTICE, LEGACY_CUSTOM_SYNTAX_NOTICES } from "../startupNotice"; +import { + LEGACY_CUSTOM_SYNTAX_NOTICE, + LEGACY_CUSTOM_SYNTAX_NOTICES, +} from "../runtime/startupNotice"; const tempDirs: string[] = []; diff --git a/src/core/invocation/config.ts b/src/core/invocation/config.ts index cee0f4225..db0ac939d 100644 --- a/src/core/invocation/config.ts +++ b/src/core/invocation/config.ts @@ -17,9 +17,9 @@ import { resolveSyntaxScopeOverrides, } from "../theme/legacySyntaxScopes"; import { resolveGlobalConfigPath } from "./paths"; -import { LEGACY_CUSTOM_SYNTAX_NOTICES, type StartupNotice } from "../startupNotice"; +import { LEGACY_CUSTOM_SYNTAX_NOTICES, type StartupNotice } from "../runtime/startupNotice"; import { DEFAULT_TAB_WIDTH, validateTabWidth } from "./tabWidth"; -import { findProjectRootCandidate } from "../projectRoot"; +import { findProjectRootCandidate } from "../runtime/projectRoot"; import { createVcsCatalog, detectVcs } from "../vcs"; import type { VcsCatalog } from "../vcs/types"; import type { diff --git a/src/core/appStateFile.test.ts b/src/core/runtime/appStateFile.test.ts similarity index 100% rename from src/core/appStateFile.test.ts rename to src/core/runtime/appStateFile.test.ts diff --git a/src/core/appStateFile.ts b/src/core/runtime/appStateFile.ts similarity index 100% rename from src/core/appStateFile.ts rename to src/core/runtime/appStateFile.ts diff --git a/src/core/jobControl.test.ts b/src/core/runtime/jobControl.test.ts similarity index 100% rename from src/core/jobControl.test.ts rename to src/core/runtime/jobControl.test.ts diff --git a/src/core/jobControl.ts b/src/core/runtime/jobControl.ts similarity index 100% rename from src/core/jobControl.ts rename to src/core/runtime/jobControl.ts diff --git a/src/core/pager.test.ts b/src/core/runtime/pager.test.ts similarity index 100% rename from src/core/pager.test.ts rename to src/core/runtime/pager.test.ts diff --git a/src/core/pager.ts b/src/core/runtime/pager.ts similarity index 97% rename from src/core/pager.ts rename to src/core/runtime/pager.ts index 7b2d4d5bc..4b2be67b1 100644 --- a/src/core/pager.ts +++ b/src/core/runtime/pager.ts @@ -1,7 +1,7 @@ import { spawn, type ChildProcess, type SpawnOptions } from "node:child_process"; import { parse as parseShellCommand, type ParseEntry } from "shell-quote"; -import { stripTerminalControl } from "./patch/sanitize"; -import { sanitizeTerminalText } from "../lib/terminalText"; +import { stripTerminalControl } from "../patch/sanitize"; +import { sanitizeTerminalText } from "../../lib/terminalText"; /** Detect whether generic pager stdin looks like a diff/patch that Hunk should review. */ export function looksLikePatchInput(text: string) { diff --git a/src/core/projectRoot.test.ts b/src/core/runtime/projectRoot.test.ts similarity index 96% rename from src/core/projectRoot.test.ts rename to src/core/runtime/projectRoot.test.ts index d542b4402..5fb56513d 100644 --- a/src/core/projectRoot.test.ts +++ b/src/core/runtime/projectRoot.test.ts @@ -3,8 +3,8 @@ import { existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { findProjectRootCandidate } from "./projectRoot"; -import { createVcsCatalog } from "./vcs"; -import type { VcsAdapter } from "./vcs/types"; +import { createVcsCatalog } from "../vcs"; +import type { VcsAdapter } from "../vcs/types"; const tempDirs: string[] = []; diff --git a/src/core/projectRoot.ts b/src/core/runtime/projectRoot.ts similarity index 95% rename from src/core/projectRoot.ts rename to src/core/runtime/projectRoot.ts index ef301e454..4589ff9c8 100644 --- a/src/core/projectRoot.ts +++ b/src/core/runtime/projectRoot.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import { dirname, join, resolve } from "node:path"; -import type { VcsCatalog } from "./vcs/types"; +import type { VcsCatalog } from "../vcs/types"; /** Return whether one path is a `.hunk` project directory, following directory symlinks. */ function isHunkProjectDirectory(path: string) { diff --git a/src/core/shutdown.test.ts b/src/core/runtime/shutdown.test.ts similarity index 100% rename from src/core/shutdown.test.ts rename to src/core/runtime/shutdown.test.ts diff --git a/src/core/shutdown.ts b/src/core/runtime/shutdown.ts similarity index 100% rename from src/core/shutdown.ts rename to src/core/runtime/shutdown.ts diff --git a/src/core/startupNotice.ts b/src/core/runtime/startupNotice.ts similarity index 100% rename from src/core/startupNotice.ts rename to src/core/runtime/startupNotice.ts diff --git a/src/core/terminal.test.ts b/src/core/runtime/terminal.test.ts similarity index 98% rename from src/core/terminal.test.ts rename to src/core/runtime/terminal.test.ts index 67a3e7284..d66d61050 100644 --- a/src/core/terminal.test.ts +++ b/src/core/runtime/terminal.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { CliInput } from "./types"; +import type { CliInput } from "../types"; import { openControllingTerminal, resolveRuntimeCliInput, diff --git a/src/core/terminal.ts b/src/core/runtime/terminal.ts similarity index 98% rename from src/core/terminal.ts rename to src/core/runtime/terminal.ts index ccfd28d3d..b95e0fdfb 100644 --- a/src/core/terminal.ts +++ b/src/core/runtime/terminal.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import tty from "node:tty"; -import type { CliInput } from "./types"; +import type { CliInput } from "../types"; export interface AppMouseOptions { stdinIsTTY?: boolean; diff --git a/src/core/updateNotice.test.ts b/src/core/runtime/updateNotice.test.ts similarity index 100% rename from src/core/updateNotice.test.ts rename to src/core/runtime/updateNotice.test.ts diff --git a/src/core/updateNotice.ts b/src/core/runtime/updateNotice.ts similarity index 98% rename from src/core/updateNotice.ts rename to src/core/runtime/updateNotice.ts index fd5a88899..78d97949f 100644 --- a/src/core/updateNotice.ts +++ b/src/core/runtime/updateNotice.ts @@ -1,8 +1,8 @@ import { posix, win32 } from "node:path"; import { readAppStateRecord, updateAppStateRecord } from "./appStateFile"; -import { resolveAppStatePath } from "./invocation/paths"; +import { resolveAppStatePath } from "../invocation/paths"; import type { StartupNotice } from "./startupNotice"; -import { resolveCliVersion, UNKNOWN_CLI_VERSION } from "./invocation/version"; +import { resolveCliVersion, UNKNOWN_CLI_VERSION } from "../invocation/version"; const DIST_TAGS_URL = "https://registry.npmjs.org/-/package/hunkdiff/dist-tags"; const STABLE_SEMVER_PATTERN = /^\d+\.\d+\.\d+$/; diff --git a/src/core/theme/customThemes.ts b/src/core/theme/customThemes.ts index d479a0f5e..3c47eb195 100644 --- a/src/core/theme/customThemes.ts +++ b/src/core/theme/customThemes.ts @@ -1,4 +1,4 @@ -import type { StartupNotice } from "../startupNotice"; +import type { StartupNotice } from "../runtime/startupNotice"; import type { NamedCustomThemeConfig } from "../types"; import { BUNDLED_SHIKI_THEME_IDS, resolveBundledShikiThemeId } from "./catalog"; import { LEGACY_CUSTOM_SYNTAX_COLOR_KEYS } from "./legacySyntaxScopes"; diff --git a/src/core/types.ts b/src/core/types.ts index 103d4b277..ab0d05d2b 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -6,7 +6,7 @@ import type { LayoutMode, SidebarVisibility, } from "./invocation/commandInputs"; -import type { StartupNotice } from "./startupNotice"; +import type { StartupNotice } from "./runtime/startupNotice"; import type { VcsCatalog } from "./vcs/types"; /** diff --git a/src/extensions/apply.ts b/src/extensions/apply.ts index 781d1aa12..6b3872ef5 100644 --- a/src/extensions/apply.ts +++ b/src/extensions/apply.ts @@ -2,7 +2,7 @@ import { BUILT_IN_FILE_LANGUAGE_EXTENSIONS, registerFileLanguage, } from "../core/changeset/fileLanguage"; -import type { StartupNotice } from "../core/startupNotice"; +import type { StartupNotice } from "../core/runtime/startupNotice"; import type { Changeset } from "../core/types"; import { detectVcs, extendVcsCatalog, getDefaultVcsAdapter } from "../core/vcs"; import type { VcsAdapter, VcsCatalog } from "../core/vcs/types"; diff --git a/src/extensions/discovery.ts b/src/extensions/discovery.ts index 9f6591de5..610e5a7b2 100644 --- a/src/extensions/discovery.ts +++ b/src/extensions/discovery.ts @@ -5,7 +5,7 @@ import { INSTALLED_EXTENSIONS_DIR_NAME, resolveGlobalExtensionsDir, } from "../core/invocation/paths"; -import { findProjectRootCandidate } from "../core/projectRoot"; +import { findProjectRootCandidate } from "../core/runtime/projectRoot"; import { deriveExtensionId, type ExtensionCandidate, type ExtensionOrigin } from "./types"; /** Entry-file suffixes Hunk will import directly, in preference order. */ diff --git a/src/extensions/host.ts b/src/extensions/host.ts index a5704d1cd..ded756342 100644 --- a/src/extensions/host.ts +++ b/src/extensions/host.ts @@ -1,5 +1,5 @@ import { pathToFileURL } from "node:url"; -import { findProjectRootCandidate } from "../core/projectRoot"; +import { findProjectRootCandidate } from "../core/runtime/projectRoot"; import { EXTENSION_ID_RULE, HUNK_VENDOR_EXTENSION_ID, isValidExtensionId } from "./extensionIds"; import { bindExtensionEventBus } from "./events"; import { registerHostRuntimeModules } from "./hostRuntimeModules"; diff --git a/src/extensions/manage/records.ts b/src/extensions/manage/records.ts index c0e3188a5..f31f838b2 100644 --- a/src/extensions/manage/records.ts +++ b/src/extensions/manage/records.ts @@ -1,5 +1,5 @@ import { join } from "node:path"; -import { readAppStateRecord, writeAppStateRecord } from "../../core/appStateFile"; +import { readAppStateRecord, writeAppStateRecord } from "../../core/runtime/appStateFile"; /** * What `hunk extension install` remembers about one managed install. diff --git a/src/extensions/startup.ts b/src/extensions/startup.ts index 09d38b6fd..cc4b75626 100644 --- a/src/extensions/startup.ts +++ b/src/extensions/startup.ts @@ -1,5 +1,5 @@ import { isDeepStrictEqual } from "node:util"; -import type { StartupNotice } from "../core/startupNotice"; +import type { StartupNotice } from "../core/runtime/startupNotice"; import type { ExtensionsConfig } from "../core/types"; import { sanitizeTerminalText } from "../lib/terminalText"; import { discoverExtensions } from "./discovery"; diff --git a/src/extensions/trust.ts b/src/extensions/trust.ts index b979bee31..d807a8935 100644 --- a/src/extensions/trust.ts +++ b/src/extensions/trust.ts @@ -1,5 +1,5 @@ import { resolve } from "node:path"; -import { readAppStateRecord, updateAppStateRecord } from "../core/appStateFile"; +import { readAppStateRecord, updateAppStateRecord } from "../core/runtime/appStateFile"; import { resolveCanonicalPath, resolveAppStatePath } from "../core/invocation/paths"; /** diff --git a/src/main.tsx b/src/main.tsx index 1681f4f44..e3996392b 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,7 +1,7 @@ #!/usr/bin/env bun import { formatCliError } from "./core/invocation/errors"; -import { pagePlainText } from "./core/pager"; +import { pagePlainText } from "./core/runtime/pager"; import { prepareStartupPlan } from "./app/startup"; import { sanitizeTerminalText } from "./lib/terminalText"; import { serveSessionBrokerDaemon } from "./session/broker/brokerServer"; diff --git a/src/ui/AppHost.interactions.test.tsx b/src/ui/AppHost.interactions.test.tsx index a6cc62773..bb799f21a 100644 --- a/src/ui/AppHost.interactions.test.tsx +++ b/src/ui/AppHost.interactions.test.tsx @@ -11,7 +11,7 @@ import type { HunkSessionServerMessage, HunkSessionSnapshot, } from "../session/types"; -import { LEGACY_CUSTOM_SYNTAX_NOTICE } from "../core/startupNotice"; +import { LEGACY_CUSTOM_SYNTAX_NOTICE } from "../core/runtime/startupNotice"; import type { AppBootstrap, LayoutMode } from "../core/types"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { capturedTestColorToHex } from "../../test/helpers/test-color-helpers"; diff --git a/src/ui/AppHost.tsx b/src/ui/AppHost.tsx index 9381ef50c..9eb71f05c 100644 --- a/src/ui/AppHost.tsx +++ b/src/ui/AppHost.tsx @@ -4,8 +4,8 @@ import { ReviewProducer } from "../app/review/producer"; import { loadConfiguredSessionBootstrap } from "../app/sessionBootstrap"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; import { resolveConfiguredCliInput } from "../core/invocation/config"; -import { resolveRuntimeCliInput } from "../core/terminal"; -import type { StartupNotice } from "../core/startupNotice"; +import { resolveRuntimeCliInput } from "../core/runtime/terminal"; +import type { StartupNotice } from "../core/runtime/startupNotice"; import type { AppBootstrap, CliInput } from "../core/types"; import type { ExtensionLoadResult } from "../extensions/types"; import { diff --git a/src/ui/hooks/useStartupNotices.ts b/src/ui/hooks/useStartupNotices.ts index 2b18f7bfe..60366c109 100644 --- a/src/ui/hooks/useStartupNotices.ts +++ b/src/ui/hooks/useStartupNotices.ts @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from "react"; -import type { StartupNotice } from "../../core/startupNotice"; +import type { StartupNotice } from "../../core/runtime/startupNotice"; const DEFAULT_STARTUP_NOTICE_DELAY_MS = 1200; const DEFAULT_STARTUP_NOTICE_DURATION_MS = 7000; diff --git a/src/ui/runInteractiveApp.tsx b/src/ui/runInteractiveApp.tsx index 8ffd4180b..48769d895 100644 --- a/src/ui/runInteractiveApp.tsx +++ b/src/ui/runInteractiveApp.tsx @@ -5,11 +5,11 @@ import { installJobControlSuspendSupport, type JobControlInterruptSupport, type JobControlSuspendSupport, -} from "../core/jobControl"; -import { shutdownSession } from "../core/shutdown"; -import { shouldUseMouseForApp, type ControllingTerminal } from "../core/terminal"; +} from "../core/runtime/jobControl"; +import { shutdownSession } from "../core/runtime/shutdown"; +import { shouldUseMouseForApp, type ControllingTerminal } from "../core/runtime/terminal"; import type { AppBootstrap } from "../core/types"; -import { resolveStartupUpdateNotice } from "../core/updateNotice"; +import { resolveStartupUpdateNotice } from "../core/runtime/updateNotice"; import { ReviewProducer } from "../app/review/producer"; import { createInitialSessionSnapshot, From 7eae160f891e5ec83208bdb44d4efb965dfe44d0 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 03:44:57 +0000 Subject: [PATCH 5/8] refactor(core): melt the core/types re-export shell into core/bootstrap Phase 4, the last of giving src/core an interior. core/types.ts had 147 importing files bound to it for names that phases 1-3 had already moved; every import site now names the declaring module directly (changeset model, invocation inputs, extension-api contract, runtime notices), the re-exports are deleted, and the file becomes core/bootstrap.ts holding only the AppBootstrap/ReloadContext contract - 28 importers instead of 147, so editing it no longer invalidates half the typecheck graph. Stragglers rehomed by role: TerminalThemeMode to theme/detection, ExtensionsConfig/UserKeyBinding/PersistedViewPreferences to invocation/config, UserNoteLineTarget to liveComments. The leaf-freeze rule becomes core-leaves-stay-below-bootstrap across all eight core module dirs, with one named exception (changeset/loaders.ts assembles the bootstrap value) recorded for a future move to src/app. Internal import paths only; the published extension and opentui entry points are unchanged. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XcuayyxJrwQd9EHpuxNef1 --- .changeset/lazy-grapes-divide.md | 2 + .dependency-cruiser.cjs | 13 +- benchmarks/compact-highlight-payload.ts | 2 +- benchmarks/highlight-prefetch.ts | 3 +- benchmarks/large-stream-fixture.ts | 3 +- benchmarks/wrapped-cjk.ts | 3 +- docs/module-boundaries.md | 93 +++++++++-- scripts/source-boundaries.test.ts | 8 +- src/app/cli.ts | 2 +- src/app/extensionBootstrap.test.ts | 2 +- src/app/extensionBootstrap.ts | 2 +- src/app/review/producer.test.ts | 2 +- src/app/review/producer.ts | 2 +- src/app/review/publication.ts | 2 +- src/app/session/registration.test.ts | 2 +- src/app/session/registration.ts | 2 +- src/app/session/reloadBounds.test.ts | 3 +- src/app/session/reloadBounds.ts | 3 +- src/app/sessionBootstrap.test.ts | 3 +- src/app/sessionBootstrap.ts | 2 +- src/app/sessionSelector.ts | 2 +- src/app/startup.test.ts | 4 +- src/app/startup.ts | 2 +- src/app/startup.vcsExtensions.test.ts | 2 +- src/app/types.ts | 2 +- src/core/bootstrap.ts | 66 ++++++++ src/core/changeset/fromPatch.ts | 2 +- src/core/changeset/loaders.ordering.test.ts | 2 +- src/core/changeset/loaders.test.ts | 2 +- src/core/changeset/loaders.ts | 10 +- src/core/invocation/config.test.ts | 2 +- src/core/invocation/config.ts | 54 +++++- src/core/invocation/experimental.ts | 4 +- src/core/invocation/inputReload.ts | 2 +- src/core/liveComments.ts | 13 +- src/core/review/annotations.ts | 3 +- src/core/review/document.test.ts | 2 +- src/core/review/document.ts | 2 +- src/core/review/types.ts | 2 +- src/core/runtime/terminal.test.ts | 2 +- src/core/runtime/terminal.ts | 2 +- src/core/theme/customThemes.test.ts | 2 +- src/core/theme/customThemes.ts | 2 +- src/core/theme/detection.ts | 8 +- src/core/theme/legacySyntaxScopes.ts | 2 +- src/core/types.ts | 157 ------------------ src/core/watch/plan.test.ts | 2 +- src/core/watch/signature.test.ts | 2 +- src/extensions/apply.test.ts | 2 +- src/extensions/apply.ts | 2 +- src/extensions/host.test.ts | 2 +- src/extensions/manage/cli.ts | 2 +- src/extensions/publicApiRobustness.test.ts | 2 +- src/extensions/startup.test.ts | 2 +- src/extensions/startup.ts | 2 +- src/extensions/vcsPatchResult.ts | 2 +- src/opentui/model.ts | 2 +- src/session/agent/cliClient.test.ts | 2 +- src/session/agent/cliClient.ts | 2 +- src/session/agent/commands.daemon.test.ts | 2 +- src/session/agent/commands.test.ts | 5 +- src/session/agent/commands.ts | 2 +- src/session/broker/wire.ts | 2 +- src/session/protocol.ts | 2 +- src/session/protocolSchemas.ts | 2 +- src/session/types.ts | 2 +- src/ui/App.tsx | 12 +- src/ui/AppHost.cursor-line.test.tsx | 2 +- src/ui/AppHost.edit-in-editor.test.tsx | 2 +- src/ui/AppHost.extension-dialogs.test.tsx | 2 +- src/ui/AppHost.extensions.test.tsx | 2 +- src/ui/AppHost.interactions.test.tsx | 3 +- src/ui/AppHost.key-routing.test.tsx | 2 +- src/ui/AppHost.keybindings.test.tsx | 2 +- src/ui/AppHost.responsive.test.tsx | 3 +- src/ui/AppHost.scroll-regression.test.tsx | 2 +- src/ui/AppHost.selection.test.tsx | 2 +- src/ui/AppHost.sidebar-resize.test.tsx | 2 +- src/ui/AppHost.sidebar-visibility.test.tsx | 3 +- src/ui/AppHost.tsx | 3 +- src/ui/AppHost.workspace.test.tsx | 2 +- src/ui/components/panes/AgentInlineNote.tsx | 4 +- src/ui/components/panes/DiffFileHeaderRow.tsx | 2 +- src/ui/components/panes/DiffPane.tsx | 11 +- src/ui/components/panes/DiffSection.tsx | 4 +- src/ui/components/panes/ExtensionPane.tsx | 2 +- src/ui/components/panes/FileView.tsx | 2 +- src/ui/components/panes/copySelection.test.ts | 2 +- src/ui/components/panes/copySelection.ts | 3 +- .../scrollbar/VerticalScrollbar.test.tsx | 3 +- src/ui/components/ui-components.test.tsx | 3 +- src/ui/diff/DiffSectionBody.tsx | 4 +- src/ui/diff/codeColumns.test.ts | 2 +- src/ui/diff/codeColumns.ts | 3 +- src/ui/diff/diffRowModel.ts | 2 +- src/ui/diff/diffRows.test.ts | 2 +- src/ui/diff/diffRows.ts | 2 +- src/ui/diff/diffSectionGeometry.ts | 3 +- src/ui/diff/diffSectionRowPlan.ts | 3 +- src/ui/diff/lineHighlightPaint.ts | 2 +- src/ui/diff/renderRows.tsx | 5 +- src/ui/diff/reviewRenderPlan.test.ts | 2 +- src/ui/diff/reviewRenderPlan.ts | 3 +- src/ui/diff/reviewRowGeometry.ts | 2 +- src/ui/diff/useHighlightedDiff.ts | 2 +- src/ui/diff/useHighlightedSource.ts | 2 +- src/ui/diff/worker/highlightCompact.test.ts | 2 +- src/ui/fileViews/host.ts | 2 +- src/ui/fileViews/renderPlan.ts | 2 +- .../useFilePresentationController.test.tsx | 2 +- .../useFilePresentationController.ts | 2 +- .../fileViews/useFilePresentationRendering.ts | 2 +- src/ui/fileViews/useFileViews.ts | 2 +- src/ui/highlights/useLineHighlights.ts | 2 +- .../useLineHighlightsController.test.tsx | 2 +- .../highlights/useLineHighlightsController.ts | 2 +- src/ui/hooks/useHunkSessionBridge.ts | 3 +- src/ui/hooks/useTerminalReview.test.tsx | 2 +- src/ui/hooks/useTerminalReview.ts | 5 +- src/ui/hooks/useWatchedInput.ts | 3 +- src/ui/lib/agentAnnotations.ts | 4 +- src/ui/lib/agentNoteGeometry.ts | 2 +- src/ui/lib/appCommands.ts | 2 +- src/ui/lib/appMenus.ts | 2 +- src/ui/lib/extensionDocumentReader.ts | 2 +- src/ui/lib/extensionWorkspace.test.ts | 2 +- src/ui/lib/extensionWorkspace.ts | 2 +- src/ui/lib/fileHeader.ts | 2 +- src/ui/lib/fileRenderWindow.test.ts | 2 +- src/ui/lib/fileSectionLayout.ts | 2 +- src/ui/lib/files.ts | 3 +- src/ui/lib/keymap.ts | 2 +- src/ui/lib/lineCursors.test.ts | 3 +- src/ui/lib/lineCursors.ts | 3 +- src/ui/lib/openInEditor.ts | 2 +- src/ui/lib/responsive.ts | 2 +- src/ui/lib/reviewNoteMapping.ts | 3 +- src/ui/lib/reviewState.ts | 3 +- src/ui/lib/stml/cli.ts | 2 +- src/ui/lib/ui-lib.test.ts | 2 +- src/ui/lib/viewportAnchor.ts | 2 +- src/ui/lib/viewportSelection.ts | 2 +- src/ui/runInteractiveApp.tsx | 2 +- src/ui/staticDiffPager.ts | 4 +- src/ui/themes.ts | 2 +- test/helpers/app-bootstrap.ts | 4 +- test/helpers/diff-helpers.ts | 3 +- test/helpers/review-session-harness.ts | 3 +- test/helpers/theme-helpers.ts | 2 +- .../consumers/terminalRenderPlan.ts | 2 +- test/review-conformance/geometryFixtures.ts | 2 +- test/review-conformance/navigationFixtures.ts | 2 +- test/review-conformance/types.ts | 2 +- 153 files changed, 423 insertions(+), 358 deletions(-) create mode 100644 .changeset/lazy-grapes-divide.md create mode 100644 src/core/bootstrap.ts delete mode 100644 src/core/types.ts diff --git a/.changeset/lazy-grapes-divide.md b/.changeset/lazy-grapes-divide.md new file mode 100644 index 000000000..a845151cc --- /dev/null +++ b/.changeset/lazy-grapes-divide.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.dependency-cruiser.cjs b/.dependency-cruiser.cjs index 61bc6a761..249581c8a 100644 --- a/.dependency-cruiser.cjs +++ b/.dependency-cruiser.cjs @@ -132,18 +132,15 @@ module.exports = { }, }, { - name: "core-leaves-never-reimport-types", + name: "core-leaves-stay-below-bootstrap", comment: - "Freezes the 2026-08 cycle fix. core/types.ts handed its changeset, command-input, sidecar, and file models to these leaves and now re-exports them for existing import sites; a leaf importing core/types.ts back would recreate the cycle that made the grab-bag and its members one module.", + "core/bootstrap.ts composes the leaves: it names the changeset, the parsed input, the resolved preferences, and the detected theme mode to describe one launch. A module directory importing it back would invert that layering and rebuild the grab-bag cycle the 2026-08 phases dismantled. core/changeset/loaders.ts is the single exception — loadAppBootstrap assembles the value, so it names the shape it returns; its natural home is the app tier, and moving it there retires this exception.", severity: "error", from: { - path: [ - "^src/core/changeset/(model|diffFile|sidecar)\\.ts$", - "^src/core/invocation/commandInputs\\.ts$", - "^src/core/(vcs|watch|patch)/", - ], + path: "^src/core/(changeset|invocation|runtime|review|vcs|watch|patch|theme)/", + pathNot: "^src/core/changeset/loaders\\.ts$", }, - to: { path: "^src/core/types\\.ts$" }, + to: { path: "^src/core/bootstrap\\.ts$" }, }, { name: "review-reducer-is-module-internal", diff --git a/benchmarks/compact-highlight-payload.ts b/benchmarks/compact-highlight-payload.ts index 004178312..f09189b59 100644 --- a/benchmarks/compact-highlight-payload.ts +++ b/benchmarks/compact-highlight-payload.ts @@ -3,7 +3,7 @@ // normalizes it, and the terminal paint seam remains a later milestone. import { performance } from "node:perf_hooks"; import { cleanLastNewline, parseDiffFromFile } from "@pierre/diffs"; -import type { DiffFile } from "../src/core/types"; +import type { DiffFile } from "../src/core/changeset/model"; import { buildSplitRows, loadHighlightedDiff, diff --git a/benchmarks/highlight-prefetch.ts b/benchmarks/highlight-prefetch.ts index e5af16233..1ccd7946c 100644 --- a/benchmarks/highlight-prefetch.ts +++ b/benchmarks/highlight-prefetch.ts @@ -6,7 +6,8 @@ import { testRender } from "@opentui/react/test-utils"; import { parseDiffFromFile } from "@pierre/diffs"; import { act } from "react"; import { AppHost } from "../src/ui/AppHost"; -import type { AppBootstrap, DiffFile } from "../src/core/types"; +import type { AppBootstrap } from "../src/core/bootstrap"; +import type { DiffFile } from "../src/core/changeset/model"; function createDiffFile(index: number, marker: string): DiffFile { const path = `src/example${index}.ts`; diff --git a/benchmarks/large-stream-fixture.ts b/benchmarks/large-stream-fixture.ts index 82d70a667..c55366de3 100644 --- a/benchmarks/large-stream-fixture.ts +++ b/benchmarks/large-stream-fixture.ts @@ -1,5 +1,6 @@ import { parseDiffFromFile, parsePatchFiles } from "@pierre/diffs"; -import type { AppBootstrap, DiffFile } from "../src/core/types"; +import type { AppBootstrap } from "../src/core/bootstrap"; +import type { DiffFile } from "../src/core/changeset/model"; export const DEFAULT_FILE_COUNT = 180; export const DEFAULT_LINES_PER_FILE = 120; diff --git a/benchmarks/wrapped-cjk.ts b/benchmarks/wrapped-cjk.ts index 30ad79e28..760e441f5 100644 --- a/benchmarks/wrapped-cjk.ts +++ b/benchmarks/wrapped-cjk.ts @@ -4,7 +4,8 @@ import { performance } from "node:perf_hooks"; import { parsePatchFiles } from "@pierre/diffs"; import { testRender } from "@opentui/react/test-utils"; import React, { act } from "react"; -import type { AppBootstrap, DiffFile } from "../src/core/types"; +import type { AppBootstrap } from "../src/core/bootstrap"; +import type { DiffFile } from "../src/core/changeset/model"; import { AppHost } from "../src/ui/AppHost"; import { prefetchHighlightedDiff } from "../src/ui/diff/useHighlightedDiff"; import { VIEWPORT_READ_COALESCE_MS } from "../src/ui/lib/viewportTiming"; diff --git a/docs/module-boundaries.md b/docs/module-boundaries.md index 8d143c4b0..3600449e4 100644 --- a/docs/module-boundaries.md +++ b/docs/module-boundaries.md @@ -59,8 +59,10 @@ Two supporting rules keep the interiors honest: disconnected files and so misses dead code that still imports. A hit is deleted, or — when tests are its only genuine consumer — listed in the rule's `TEST_ONLY_MODULES` allowlist with the reason. That allowlist is **shrink-only**, like the baseline. -- **`core-leaves-never-reimport-types`** freezes the cycle fix below: the leaves extracted out - of `core/types.ts` may never import it back, even though it re-exports them. +- **`core-leaves-stay-below-bootstrap`** freezes the cycle fix below: `core/bootstrap.ts` + composes the module directories to describe one launch, so none of them may import it back. + (Through phase 3 this rule was `core-leaves-never-reimport-types` and guarded + `core/types.ts`; phase 4 melted that shell and repointed the rule at what replaced it.) Phase 0 (2026-08-17) established the mechanism: it deleted `core/review/address.ts` (a speculative primitive with no consumers), added the two rules above, and froze the first @@ -84,8 +86,9 @@ files at `core/*` root — into `core/changeset/`, with the surface split enforc The renames are path-only — `changeset.ts` → `changeset/model.ts`, `changesetLoaders.ts` → `changeset/loaders.ts`, `changesetFromPatch.ts` → `changeset/fromPatch.ts`, the rest keep their basenames — and no exported symbol changed. `core/types.ts` still re-exports the changeset and -sidecar shapes for legacy import sites; it names `changeset/model`, which is public, so the -interior rule needs no exception. `core/patch/` stayed where it is: it was already coherent. +sidecar shapes for legacy import sites (since phase 4: those sites name `changeset/model` +directly); it names `changeset/model`, which is public, so the interior rule needs no +exception. `core/patch/` stayed where it is: it was already coherent. Phase 2 (2026-08-17) grouped **how a run is asked for** into `core/invocation/`: the command inputs (`commandInputs`), the layered config resolver (`config`), the app command catalog @@ -99,7 +102,9 @@ phase adds no `invocation-internals-stay-in-module` rule. Its value is the group extending the freeze: `core-leaves-never-reimport-types` now names `core/invocation/commandInputs.ts` in place of the old root path. Only `commandInputs` is a types-leaf — `config`, `experimental`, and `inputReload` import `core/types` legally, since -`core/types` re-exports from `commandInputs` and never the other way round. +`core/types` re-exports from `commandInputs` and never the other way round. (Since phase 4 +there is no shell to import: those three name `commandInputs` directly, and `config` declares +the config-owned shapes itself.) `commandInputs` also absorbed the CLI-input half that was still declared in `core/types.ts`: `HelpCommandInput`, `PagerCommandInput`, `DaemonServeCommandInput`, the whole @@ -108,7 +113,8 @@ types-leaf — `config`, `experimental`, and `inputReload` import `core/types` l `Extension*CommandInput` family, and `ParsedCliInput`. Two small aliases came with them because those inputs name them and the leaf may not import `core/types` back: `SessionCommentListType` and the `ReviewNoteSource` it unions over. `core/types.ts` re-exports -all of them, so no import site changed. +all of them, so no import site changed at the time; phase 4 moved the import sites onto +`commandInputs` and deleted the re-exports. Phase 3 (2026-08-17) grouped **the process and terminal a run lives in** into `core/runtime/`: TTY capability detection and runtime CLI-input resolution (`terminal`), the external pager and @@ -117,7 +123,7 @@ teardown (`shutdown`), `.hunk`/VCS project-root discovery (`projectRoot`), the a written app-state file (`appStateFile`), the version-check notice built on it (`updateNotice`), and the startup-notice shape every tier reports through (`startupNotice`). The move is path-only; no exported symbol changed, and `core/types.ts` now re-exports `StartupNotice` from -`runtime/startupNotice`. +`runtime/startupNotice` (a re-export nothing ever imported, deleted unused in phase 4). All eight are **public** — each has production importers outside the module — so this phase adds no `runtime-internals-stay-in-module` rule; the grouping is its value. The audiences are worth @@ -129,18 +135,62 @@ extension host and config resolution. After this phase `src/core/` root holds only `types.ts`, `reviewDigest.ts`, and `liveComments.ts` beside the seven subdirectories. Phase 4 melts what is left of `core/types.ts`. +Phase 4 (2026-08-17) melted that shell. `core/types.ts` had stopped declaring most of what it +exported: 147 files imported it, almost all for names phases 1–3 had already moved elsewhere, +and the re-export list was the only thing holding those import sites to a module that no longer +owned the answer. A grab-bag that re-exports is still a grab-bag — every importer binds to it, +so nothing downstream reveals which module it actually depends on. + +Every import site was retargeted at the declaring module (mixed statements split one target per +module), the re-exports were deleted, and the file was renamed `core/types.ts` → +`core/bootstrap.ts` for what is genuinely left: `AppBootstrap` and `ReloadContext`, the contract +a composed launch hands the interactive shell. The stragglers it still declared went to the +module that owns their behaviour, one home each: + +- `TerminalThemeMode` → `core/theme/detection.ts`, which probes the terminal for it and had + been re-exporting the name from the shell. +- `ExtensionsConfig`, `UserKeyBinding`, `PersistedViewPreferences` → `core/invocation/config.ts`, + which resolves `[extensions]`, `[keybindings]`, and the persisted view options. +- `UserNoteLineTarget` → `core/liveComments.ts`, beside `DiffSide` and `CommentTargetInput`: it + is the line a user note hangs on, and every consumer reaches it through note code. + +Deleting the re-exports made one hidden dependency visible: `core/review/annotations.ts` names +`AgentAnnotation`, which is declared in `src/extension-api/types.ts` because it is +simultaneously an internal model type and part of the published contract. Routing that through +`core/types.ts` had disguised it as a core-local import, and `scripts/source-boundaries.test.ts` +("keeps the review model contained in core") caught it the moment the disguise came off. The +allowance is now explicit and narrow — that one file, not the tree — and it cannot widen the +seam, since `extension-api-is-import-free` forbids `extension-api/types.ts` any import at all. + +Fan-in tells the story: 147 importing files became 28 (13 outside tests) — the review stream, +the diff renderer, and the session surfaces never needed the bootstrap contract, only the +changeset and command-input models they now name. `core/bootstrap.ts` imports downward into +`changeset/model`, `invocation/commandInputs`, `invocation/config`, `runtime/startupNotice`, +`theme/detection`, and `vcs/types`, and `core-leaves-stay-below-bootstrap` forbids the reverse +edge from every module directory. One exception is carved out and named in the rule: +`core/changeset/loaders.ts` returns an `AppBootstrap` from `loadAppBootstrap`, so it names the +shape it assembles; that function is composition living in the domain tier, and moving it to +`src/app` retires the exception. + +`src/core/` root now holds `bootstrap.ts`, `reviewDigest.ts`, and `liveComments.ts` beside the +eight module directories. + ## Snapshot (2026-08-17, v0.19.0) -331 production modules, 1282 internal edges, **zero boundary violations and zero import -cycles** — the baseline is empty. The initial audit (2026-08-16) found 28 violations in five +331 production modules, 1322 internal edges, **zero boundary violations and zero import +cycles** — the baseline is empty. (The edge count grew from 1282 in phase 4: import sites that +used to funnel through one re-export shell now name the modules they actually depend on, so the +same dependencies are finally visible in the graph.) The initial audit (2026-08-16) found 28 +violations in five clusters and 5 file-level cycles; all were repaid in the same change series that introduced the rules: - **Cycles.** Each cycle was a type-only back-edge from a lower module into a grab-bag above it. The cuts: `core/types.ts` gave its changeset model to `core/changeset.ts` (since phase 1, `core/changeset/model.ts`) and its command-input model to `core/commandInputs.ts` (since phase - 2, `core/invocation/commandInputs.ts`; re-exported from `core/types` so import sites keep - working); the diff row model moved to + 2, `core/invocation/commandInputs.ts`; re-exported from `core/types` so import sites kept + working, until phase 4 melted that shell into `core/bootstrap.ts` and moved the sites onto the + declaring modules); the diff row model moved to `ui/diff/diffRowModel.ts`; the worker's compact encoder was retyped structurally (`HighlightedHastLines`); `HunkSessionBrokerClient` moved beside the client class it aliases; `CopySelectedRowRange` moved into @@ -168,13 +218,20 @@ rules: The tier rules now hold with no exceptions. Two follow-ups are worth doing next: -1. **Give `src/core` an interior.** _In progress (phases 0–3, see Module interiors)._ The - subdirectories (`review/`, `vcs/`, `theme/`, `watch/`, `patch/`, and now `changeset/`, - `invocation/`, and `runtime/`) are coherent modules; `types.ts`, `reviewDigest.ts`, and - `liveComments.ts` are all that is left at `core/*` root. Melting what remains of - `core/types.ts` is the next step, giving each group a rule restricting which of its files - other tiers may import. The review seam's named modules (`document`, `geometry`, `state`, …) - stay public; their helpers become internal. +1. **Give `src/core` an interior.** _Done (phases 0–4, see Module interiors)._ Every group is a + module directory — `review/`, `vcs/`, `theme/`, `watch/`, `patch/`, `changeset/`, + `invocation/`, `runtime/` — and `core/*` root is down to `bootstrap.ts`, `reviewDigest.ts`, + and `liveComments.ts`, with no grab-bag left to import. What remains is per-file public + surfaces for the modules that never got one: `changeset` has + `changeset-internals-stay-in-module` and `review` has `review-reducer-is-module-internal`, + while `invocation`, `runtime`, `theme`, `vcs`, `watch`, and `patch` are still public in full + because every file in them has an outside importer today. Two named follow-ups: move + `loadAppBootstrap` out of `core/changeset/loaders.ts` into `src/app` (it is composition, and + it is the one exception `core-leaves-stay-below-bootstrap` has to carve out), and split + `core/invocation/config.ts`, whose readers reach it for three unrelated reasons — the + resolved `HunkConfigResolution`, the persisted view preferences, and the extension/keybinding + tables. The review seam's named modules (`document`, `geometry`, `state`, …) stay public; + their helpers become internal. 2. **Tighten the adapter allowlist.** `ui-couples-to-session-via-adapters` currently allowlists six files. As session coupling consolidates into `useTerminalReview` / `useHunkSessionBridge`, shrink the list. diff --git a/scripts/source-boundaries.test.ts b/scripts/source-boundaries.test.ts index f22bffe3a..a0835172e 100644 --- a/scripts/source-boundaries.test.ts +++ b/scripts/source-boundaries.test.ts @@ -8,6 +8,12 @@ const CORE_ROOT = join(SRC_ROOT, "core"); const EXTENSIONS_ROOT = join(SRC_ROOT, "extensions"); const BUNDLED_PROVIDER_ROOT = join(EXTENSIONS_ROOT, "default", "vcs"); const REVIEW_MODEL_ROOT = join(CORE_ROOT, "review"); +// The published extension contract, which the review model may name for the annotation shapes +// that are simultaneously internal model types and part of `hunkdiff/extension`. It cannot widen +// the seam: `extension-api-is-import-free` (.dependency-cruiser.cjs) forbids it any import at +// all, so it can never carry a renderer or a platform runtime in. Only this one file is allowed, +// not the tree — `extension-api/index.ts` is the runtime boundary and imports freely. +const EXTENSION_API_TYPES_PATH = join(SRC_ROOT, "extension-api", "types.ts"); const REVIEW_PROTOCOL_PATH = join(SRC_ROOT, "session", "reviewProtocol.ts"); const WEB_CLIENT_ROOT = join(SRC_ROOT, "web"); @@ -291,7 +297,7 @@ describe("shared review primitives seam", () => { } test("keeps the review model contained in core", () => { - expect(escapingImports(REVIEW_MODEL_ROOT, [CORE_ROOT])).toEqual([]); + expect(escapingImports(REVIEW_MODEL_ROOT, [CORE_ROOT, EXTENSION_API_TYPES_PATH])).toEqual([]); }); test("keeps rendering and platform runtimes out of the review model", () => { diff --git a/src/app/cli.ts b/src/app/cli.ts index 112c4b239..837f46416 100644 --- a/src/app/cli.ts +++ b/src/app/cli.ts @@ -12,7 +12,7 @@ import type { ParsedCliInput, SessionCommentListType, SessionCommentApplyItemInput, -} from "../core/types"; +} from "../core/invocation/commandInputs"; import { BUNDLED_SKILL_NAMES, resolveBundledSkillName, diff --git a/src/app/extensionBootstrap.test.ts b/src/app/extensionBootstrap.test.ts index 555177d0f..36a6d3bc5 100644 --- a/src/app/extensionBootstrap.test.ts +++ b/src/app/extensionBootstrap.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; import type { HunkConfigResolution } from "../core/invocation/config"; -import type { CliInput } from "../core/types"; +import type { CliInput } from "../core/invocation/commandInputs"; import { createEmptyExtensionLoadResult } from "../extensions/types"; import { resolveConfiguredExtensions } from "./extensionBootstrap"; import { getBundledVcsCatalog } from "./vcsCatalog"; diff --git a/src/app/extensionBootstrap.ts b/src/app/extensionBootstrap.ts index eeaad2569..ae4c37e5d 100644 --- a/src/app/extensionBootstrap.ts +++ b/src/app/extensionBootstrap.ts @@ -1,6 +1,6 @@ import { resolveConfiguredCliInput, type HunkConfigResolution } from "../core/invocation/config"; import { findProjectRootCandidate } from "../core/runtime/projectRoot"; -import type { CliInput } from "../core/types"; +import type { CliInput } from "../core/invocation/commandInputs"; import { extendVcsCatalog } from "../core/vcs"; import type { VcsCatalog } from "../core/vcs/types"; import { resolveExtensionVcsAdapters } from "../extensions/apply"; diff --git a/src/app/review/producer.test.ts b/src/app/review/producer.test.ts index 11458cfd8..57fb45769 100644 --- a/src/app/review/producer.test.ts +++ b/src/app/review/producer.test.ts @@ -8,7 +8,7 @@ import { reviewResourceId, } from "../../core/review/resources"; import { createReviewStore } from "../../core/review/store"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { parseReadReviewResourceRequest } from "../../core/review/resources"; import { ReviewProducer } from "./producer"; diff --git a/src/app/review/producer.ts b/src/app/review/producer.ts index 8353397d1..2073bcc2c 100644 --- a/src/app/review/producer.ts +++ b/src/app/review/producer.ts @@ -41,7 +41,7 @@ import { } from "../../core/review/resources"; import type { ReviewDigestFn } from "../../core/review/validation"; import type { ReviewStore } from "../../core/review/store"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { nodeReviewDigest } from "../../core/reviewDigest"; import { buildReviewPublication, type ReviewPublication } from "./publication"; import { ReviewResourceStore, type ReviewResourceFailure } from "./resourceStore"; diff --git a/src/app/review/publication.ts b/src/app/review/publication.ts index 515d07d7a..b9af070b7 100644 --- a/src/app/review/publication.ts +++ b/src/app/review/publication.ts @@ -26,7 +26,7 @@ import { type ReviewResourceDescriptorV1, } from "../../core/review/resources"; import type { ReviewDocumentV1, ReviewFileV1 } from "../../core/review/types"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; export interface ReviewPublication { /** Serialized generation identity; every descriptor below repeats it. */ diff --git a/src/app/session/registration.test.ts b/src/app/session/registration.test.ts index 5700efbdd..e5e607f08 100644 --- a/src/app/session/registration.test.ts +++ b/src/app/session/registration.test.ts @@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test"; import { createTestDiffFile } from "../../../test/helpers/diff-helpers"; import { reviewProcessCapability } from "../review/capability"; import { buildReviewPublication } from "../review/publication"; -import type { AppBootstrap } from "../../core/types"; +import type { AppBootstrap } from "../../core/bootstrap"; import { SESSION_BROKER_REGISTRATION_VERSION } from "@hunk/session-broker-core"; import { createInitialSessionSnapshot, diff --git a/src/app/session/registration.ts b/src/app/session/registration.ts index 44d011746..6327ee21a 100644 --- a/src/app/session/registration.ts +++ b/src/app/session/registration.ts @@ -6,7 +6,7 @@ import { summarizeHunk } from "../../core/changeset/hunkSummary"; import { reviewHunkRanges } from "../../core/review/geometry"; import { reviewProcessCapability } from "../review/capability"; import type { ReviewPublication } from "../review/publication"; -import type { AppBootstrap } from "../../core/types"; +import type { AppBootstrap } from "../../core/bootstrap"; import { SESSION_BROKER_REGISTRATION_VERSION, resolveSessionTerminalMetadata, diff --git a/src/app/session/reloadBounds.test.ts b/src/app/session/reloadBounds.test.ts index c6210c20d..8329b7546 100644 --- a/src/app/session/reloadBounds.test.ts +++ b/src/app/session/reloadBounds.test.ts @@ -3,7 +3,8 @@ import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { describe, expect, test } from "bun:test"; import { getBundledVcsCatalog } from "../vcsCatalog"; -import type { AppBootstrap, CliInput } from "../../core/types"; +import type { AppBootstrap } from "../../core/bootstrap"; +import type { CliInput } from "../../core/invocation/commandInputs"; import { createSessionReloadBounds, validateSessionReloadWithinBounds } from "./reloadBounds"; /** Resolve expected paths the same way production bounds do, including Windows long names. */ diff --git a/src/app/session/reloadBounds.ts b/src/app/session/reloadBounds.ts index 44f234851..587ffa96f 100644 --- a/src/app/session/reloadBounds.ts +++ b/src/app/session/reloadBounds.ts @@ -1,7 +1,8 @@ import { isAbsolute, relative, resolve } from "node:path"; import { resolveCanonicalPath } from "../../core/invocation/paths"; import { findProjectRootCandidate } from "../../core/runtime/projectRoot"; -import type { AppBootstrap, CliInput, CommonOptions } from "../../core/types"; +import type { AppBootstrap } from "../../core/bootstrap"; +import type { CliInput, CommonOptions } from "../../core/invocation/commandInputs"; import type { VcsCatalog } from "../../core/vcs/types"; /** diff --git a/src/app/sessionBootstrap.test.ts b/src/app/sessionBootstrap.test.ts index 05efe427a..8651ef32e 100644 --- a/src/app/sessionBootstrap.test.ts +++ b/src/app/sessionBootstrap.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test } from "bun:test"; import type { HunkConfigResolution } from "../core/invocation/config"; -import type { AppBootstrap, CliInput } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; +import type { CliInput } from "../core/invocation/commandInputs"; import { createEmptyExtensionLoadResult } from "../extensions/types"; import { loadConfiguredSessionBootstrap } from "./sessionBootstrap"; diff --git a/src/app/sessionBootstrap.ts b/src/app/sessionBootstrap.ts index d695af354..15ceaf620 100644 --- a/src/app/sessionBootstrap.ts +++ b/src/app/sessionBootstrap.ts @@ -4,7 +4,7 @@ import type { VcsCatalog } from "../core/vcs/types"; import { getBundledVcsCatalog } from "./vcsCatalog"; import { collectSessionCustomThemes } from "../core/theme/customThemes"; import { loadAppBootstrap } from "../core/changeset/loaders"; -import type { CliInput } from "../core/types"; +import type { CliInput } from "../core/invocation/commandInputs"; import type { AppBootstrap } from "./types"; import { applyExtensionChangesetTransforms, diff --git a/src/app/sessionSelector.ts b/src/app/sessionSelector.ts index dd1c6fd71..e2d9cf5b4 100644 --- a/src/app/sessionSelector.ts +++ b/src/app/sessionSelector.ts @@ -1,5 +1,5 @@ import { findProjectRootCandidate } from "../core/runtime/projectRoot"; -import type { SessionSelectorInput } from "../core/types"; +import type { SessionSelectorInput } from "../core/invocation/commandInputs"; import type { VcsCatalog } from "../core/vcs/types"; /** Attach the nearest known project boundary to one repo-path session selector. */ diff --git a/src/app/startup.test.ts b/src/app/startup.test.ts index 6eb7fa73e..73a8bc0f6 100644 --- a/src/app/startup.test.ts +++ b/src/app/startup.test.ts @@ -3,7 +3,9 @@ import { createEmptyExtensionLoadResult } from "../extensions/types"; import type { HunkConfigResolution } from "../core/invocation/config"; import { HunkUserError } from "../core/invocation/errors"; import { prepareStartupPlan } from "./startup"; -import type { AppBootstrap, CliInput, NamedCustomThemeConfig, ParsedCliInput } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; +import type { CliInput, ParsedCliInput } from "../core/invocation/commandInputs"; +import type { NamedCustomThemeConfig } from "../extension-api/types"; /** * Build a config resolution for tests that are not exercising config layering. diff --git a/src/app/startup.ts b/src/app/startup.ts index b7820709d..4e813bbea 100644 --- a/src/app/startup.ts +++ b/src/app/startup.ts @@ -19,7 +19,7 @@ import type { MarkupRenderCommandInput, ParsedCliInput, SessionCommandInput, -} from "../core/types"; +} from "../core/invocation/commandInputs"; import { canReloadInput } from "../core/invocation/inputReload"; import { parseCli } from "./cli"; import { resolveSessionSelectorBoundary } from "./sessionSelector"; diff --git a/src/app/startup.vcsExtensions.test.ts b/src/app/startup.vcsExtensions.test.ts index cbb574a1d..cc265ddfc 100644 --- a/src/app/startup.vcsExtensions.test.ts +++ b/src/app/startup.vcsExtensions.test.ts @@ -4,7 +4,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { prepareStartupPlan } from "./startup"; import { resolveConfiguredCliInput } from "../core/invocation/config"; -import type { CliInput, ParsedCliInput } from "../core/types"; +import type { CliInput, ParsedCliInput } from "../core/invocation/commandInputs"; const tempDirs: string[] = []; const initialCwd = process.cwd(); diff --git a/src/app/types.ts b/src/app/types.ts index da9e30cf8..201814135 100644 --- a/src/app/types.ts +++ b/src/app/types.ts @@ -1,4 +1,4 @@ -import type { AppBootstrap as CoreAppBootstrap } from "../core/types"; +import type { AppBootstrap as CoreAppBootstrap } from "../core/bootstrap"; import type { ExtensionLoadResult } from "../extensions/types"; /** Interactive app bootstrap specialized with the extension host's session state. */ diff --git a/src/core/bootstrap.ts b/src/core/bootstrap.ts new file mode 100644 index 000000000..a8c04dee7 --- /dev/null +++ b/src/core/bootstrap.ts @@ -0,0 +1,66 @@ +/** + * Declares the app bootstrap contract: everything a composed launch hands the + * interactive shell, plus the context that shell needs to reload the review it + * was given. + * + * This module names shapes the tiers below it already own — the changeset, the + * parsed command input, the resolved view and keybinding preferences, the + * detected theme mode — and composes them into the one value that crosses from + * startup into the UI. The module directories under `src/core` do not import it + * back — composition sits above the leaves it composes — with one exception the + * boundary rules name: `changeset/loaders.ts` assembles this value in + * `loadAppBootstrap`, so it has to name the shape it returns. + */ +import type { NamedCustomThemeConfig } from "../extension-api/types"; +import type { Changeset } from "./changeset/model"; +import type { + CliInput, + CursorLine, + LayoutMode, + SidebarVisibility, +} from "./invocation/commandInputs"; +import type { UserKeyBinding } from "./invocation/config"; +import type { StartupNotice } from "./runtime/startupNotice"; +import type { TerminalThemeMode } from "./theme/detection"; +import type { VcsCatalog } from "./vcs/types"; + +/** Where a review was loaded from, retained so the session can reload and watch it. */ +export interface ReloadContext { + cwd: string; + repoRoot?: string; + initialWatchSignature?: string; + /** Complete catalog used to load this review, retained for reload and watch. */ + vcsCatalog?: VcsCatalog; +} + +/** + * One fully resolved launch: the changeset to review, the input that asked for it, + * and every view option settled before the first frame. `initial*` fields are + * starting values the shell then owns — the shell, not this record, is where they + * change during the session. + */ +export interface AppBootstrap { + input: CliInput; + reloadContext: ReloadContext; + changeset: Changeset; + initialMode: LayoutMode; + initialTheme?: string; + initialThemeMode?: TerminalThemeMode; + /** Selectable custom themes for this session, in menu order. */ + customThemes?: readonly NamedCustomThemeConfig[]; + initialShowLineNumbers?: boolean; + initialTabWidth?: number; + initialWrapLines?: boolean; + initialShowHunkHeaders?: boolean; + initialShowMenuBar?: boolean; + initialSidebar?: SidebarVisibility; + initialShowAgentNotes?: boolean; + initialCopyDecorations?: boolean; + initialCursorLine?: CursorLine; + startupNotices?: readonly StartupNotice[]; + viewPreferencesConfigPath?: string; + /** The user's `[keybindings]` table, resolved against command defaults in App. */ + keybindings?: Record; + /** App-owned extension state carried without coupling core to the extension host. */ + extensions?: ExtensionState; +} diff --git a/src/core/changeset/fromPatch.ts b/src/core/changeset/fromPatch.ts index 897a3feae..b07a1c354 100644 --- a/src/core/changeset/fromPatch.ts +++ b/src/core/changeset/fromPatch.ts @@ -13,7 +13,7 @@ import { parsePatchFiles } from "@pierre/diffs"; import { buildDiffFile, type BuildDiffFileOptions } from "./diffFile"; import { splitPatchIntoFileChunks, findPatchChunk } from "../patch/chunks"; import { sanitizePatch, stripTerminalControl } from "../patch/sanitize"; -import type { Changeset, DiffLineMoveKind, DiffLineMoveKinds, SidecarContext } from "../types"; +import type { Changeset, DiffLineMoveKind, DiffLineMoveKinds, SidecarContext } from "./model"; /** Return SGR parameter strings that Git emitted before one diff line marker. */ function leadingSgrParameters(rawLine: string, expectedSign: "+" | "-") { diff --git a/src/core/changeset/loaders.ordering.test.ts b/src/core/changeset/loaders.ordering.test.ts index bfed7cbc6..3143077b4 100644 --- a/src/core/changeset/loaders.ordering.test.ts +++ b/src/core/changeset/loaders.ordering.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { SidecarContext } from "../types"; +import type { SidecarContext } from "./model"; import { orderDiffFiles } from "./loaders"; import { createTestDiffFile } from "../../../test/helpers/diff-helpers"; diff --git a/src/core/changeset/loaders.test.ts b/src/core/changeset/loaders.test.ts index 531a1cad6..f18e30568 100644 --- a/src/core/changeset/loaders.test.ts +++ b/src/core/changeset/loaders.test.ts @@ -16,7 +16,7 @@ import { createGitVcsAdapter } from "../../extensions/default/vcs/git"; import { toInternalVcsAdapter } from "../../extensions/runExtension"; import { createVcsCatalog } from "../vcs"; import { loadAppBootstrap as loadCoreAppBootstrap, type LoadAppBootstrapOptions } from "./loaders"; -import type { CliInput } from "../types"; +import type { CliInput } from "../invocation/commandInputs"; import type { VcsAdapter } from "../vcs/types"; import { computeWatchSignature } from "../watch/signature"; diff --git a/src/core/changeset/loaders.ts b/src/core/changeset/loaders.ts index 95e9f248d..37002372e 100644 --- a/src/core/changeset/loaders.ts +++ b/src/core/changeset/loaders.ts @@ -25,20 +25,18 @@ import { import type { VcsCatalog } from "../vcs/types"; import { buildFilesystemUntrackedDiffFile } from "../vcs/untracked"; import { computeWatchSignature } from "../watch/signature"; +import type { NamedCustomThemeConfig } from "../../extension-api/types"; +import type { AppBootstrap } from "../bootstrap"; import type { - AppBootstrap, - SidecarContext, - Changeset, CliInput, - NamedCustomThemeConfig, - DiffFile, DiffToolCommandInput, FileCommandInput, PatchCommandInput, VcsShowCommandInput, VcsDiffCommandInput, VcsStashShowCommandInput, -} from "../types"; +} from "../invocation/commandInputs"; +import type { SidecarContext, Changeset, DiffFile } from "./model"; export interface LoadAppBootstrapOptions { cwd?: string; diff --git a/src/core/invocation/config.test.ts b/src/core/invocation/config.test.ts index 58b53a4f6..d57c93a6e 100644 --- a/src/core/invocation/config.test.ts +++ b/src/core/invocation/config.test.ts @@ -3,7 +3,7 @@ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "nod import { tmpdir } from "node:os"; import { join } from "node:path"; import { getBundledVcsCatalog } from "../../app/vcsCatalog"; -import type { CliInput } from "../types"; +import type { CliInput } from "./commandInputs"; import { diffPersistedViewPreferences, resolveConfiguredCliInput, diff --git a/src/core/invocation/config.ts b/src/core/invocation/config.ts index db0ac939d..a02b71378 100644 --- a/src/core/invocation/config.ts +++ b/src/core/invocation/config.ts @@ -22,20 +22,60 @@ import { DEFAULT_TAB_WIDTH, validateTabWidth } from "./tabWidth"; import { findProjectRootCandidate } from "../runtime/projectRoot"; import { createVcsCatalog, detectVcs } from "../vcs"; import type { VcsCatalog } from "../vcs/types"; +import type { + CustomSyntaxColorsConfig, + CustomSyntaxScopesConfig, + NamedCustomThemeConfig, +} from "../../extension-api/types"; import type { CliInput, CommonOptions, CursorLine, - CustomSyntaxColorsConfig, - CustomSyntaxScopesConfig, - ExtensionsConfig, LayoutMode, - NamedCustomThemeConfig, - PersistedViewPreferences, SidebarVisibility, - UserKeyBinding, VcsMode, -} from "../types"; +} from "./commandInputs"; + +/** Resolved `[extensions]` and `[extension.]` configuration for one invocation. */ +export interface ExtensionsConfig { + /** + * False when `--no-extensions` or `[extensions] enabled = false` disables loading. + * + * Scoped to user extensions. Hunk's bundled tier — the Jujutsu and Sapling + * backends — always loads: these switches exist to triage extensions you + * installed, not to drop VCS support. + */ + enabled: boolean; + /** Explicit entry paths from the user config layer. */ + paths: string[]; + /** Explicit entry paths contributed by the repo config layer; trust-gated like `.hunk/extensions`. */ + repoPaths: string[]; + /** Per-extension config tables, keyed by extension id. */ + extensionConfigs: Record>; +} + +/** + * One `[keybindings]` entry: the chord(s) to bind a command to, or `false` to unbind it. + * + * Command ids are the ones the dispatch table declares — `"hunk.app.quit"`, + * `"hunk.review.nextHunk"`, or `"."` for an extension + * command. Resolution against each command's defaults lives in + * `src/ui/lib/keymap.ts`. + */ +export type UserKeyBinding = string | readonly string[] | false; + +/** The view options a session persists back to config when the reader saves them. */ +export interface PersistedViewPreferences { + mode: LayoutMode; + theme?: string; + showLineNumbers: boolean; + wrapLines: boolean; + showHunkHeaders: boolean; + showMenuBar: boolean; + showAgentNotes: boolean; + copyDecorations: boolean; + cursorLine: CursorLine; +} export const BUILT_IN_THEME_IDS = BUNDLED_SHIKI_THEME_IDS; // Widen the large literal tuple before formatting it, avoiding TypeScript's deep tuple inference. diff --git a/src/core/invocation/experimental.ts b/src/core/invocation/experimental.ts index c842d09af..785416e92 100644 --- a/src/core/invocation/experimental.ts +++ b/src/core/invocation/experimental.ts @@ -1,4 +1,6 @@ -import type { AgentFileContext, CommonOptions, DiffFile } from "../types"; +import type { AgentFileContext } from "../../extension-api/types"; +import type { DiffFile } from "../changeset/model"; +import type { CommonOptions } from "./commandInputs"; export const EXPERIMENTAL_FEATURES = ["stml"] as const; export type ExperimentalFeature = (typeof EXPERIMENTAL_FEATURES)[number]; diff --git a/src/core/invocation/inputReload.ts b/src/core/invocation/inputReload.ts index f300b1980..5df22ea3c 100644 --- a/src/core/invocation/inputReload.ts +++ b/src/core/invocation/inputReload.ts @@ -8,7 +8,7 @@ * signature machinery so those callers can ask it without pulling either in. */ -import type { CliInput } from "../types"; +import type { CliInput } from "./commandInputs"; /** Return whether the current input can be rebuilt from files or VCS state without rereading stdin. */ export function canReloadInput(input: CliInput) { diff --git a/src/core/liveComments.ts b/src/core/liveComments.ts index 7c68698d2..b4d431167 100644 --- a/src/core/liveComments.ts +++ b/src/core/liveComments.ts @@ -1,8 +1,19 @@ +import type { AgentAnnotation } from "../extension-api/types"; +import type { DiffFile } from "./changeset/model"; import { reviewDefaultHunkLineTarget, reviewHunkIndexForLine } from "./review/geometry"; -import type { AgentAnnotation, DiffFile } from "./types"; export type DiffSide = "old" | "new"; +/** + * The one diff line a user note hangs on: which side of the hunk, and the line + * number on that side. Surfaces resolve a click or cursor position into this + * before asking for a note, so the note's anchor never depends on rendered rows. + */ +export interface UserNoteLineTarget { + side: DiffSide; + line: number; +} + export interface CommentTargetInput { filePath: string; hunkIndex?: number; diff --git a/src/core/review/annotations.ts b/src/core/review/annotations.ts index 622508154..4c2f61031 100644 --- a/src/core/review/annotations.ts +++ b/src/core/review/annotations.ts @@ -14,7 +14,8 @@ */ import { reviewHunkRanges, reviewRangesOverlap, type ReviewHunkSpan } from "./geometry"; import type { ReviewAnnotationIndex } from "./navigation"; -import type { AgentAnnotation, DiffFile } from "../types"; +import type { AgentAnnotation } from "../../extension-api/types"; +import type { DiffFile } from "../changeset/model"; /** Whether one annotation lands inside a hunk's visible span on either side. */ export function reviewAnnotationOverlapsHunk(annotation: AgentAnnotation, hunk: ReviewHunkSpan) { diff --git a/src/core/review/document.test.ts b/src/core/review/document.test.ts index ff503f99b..003afd4d9 100644 --- a/src/core/review/document.test.ts +++ b/src/core/review/document.test.ts @@ -5,7 +5,7 @@ import { lines, } from "../../../test/helpers/diff-helpers"; import { projectReviewDocument, reviewEmptyDiffReason } from "./document"; -import type { DiffFile } from "../types"; +import type { DiffFile } from "../changeset/model"; /** Build one small parsed file, optionally with expandable source. */ function testFile( diff --git a/src/core/review/document.ts b/src/core/review/document.ts index 29dc87743..d9147d89c 100644 --- a/src/core/review/document.ts +++ b/src/core/review/document.ts @@ -10,7 +10,7 @@ * Publication concerns (generations, resource descriptors, byte digests) do not appear: * they belong to the producer runtime that serves a document, not to the document itself. */ -import type { DiffFile } from "../types"; +import type { DiffFile } from "../changeset/model"; import { reviewFileContentIdentity, reviewFileKey, diff --git a/src/core/review/types.ts b/src/core/review/types.ts index 0e5804841..3503e8bb2 100644 --- a/src/core/review/types.ts +++ b/src/core/review/types.ts @@ -9,7 +9,7 @@ * resource descriptors, digests — belong to the producer runtime and are absent here, so * nothing in this file implies a transport. */ -import type { ReviewNoteSource } from "../types"; +import type { ReviewNoteSource } from "../invocation/commandInputs"; export type ReviewSide = "old" | "new"; export type ReviewLineRange = readonly [number, number]; diff --git a/src/core/runtime/terminal.test.ts b/src/core/runtime/terminal.test.ts index d66d61050..f6b041ee5 100644 --- a/src/core/runtime/terminal.test.ts +++ b/src/core/runtime/terminal.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { CliInput } from "../types"; +import type { CliInput } from "../invocation/commandInputs"; import { openControllingTerminal, resolveRuntimeCliInput, diff --git a/src/core/runtime/terminal.ts b/src/core/runtime/terminal.ts index b95e0fdfb..2f32e6bbf 100644 --- a/src/core/runtime/terminal.ts +++ b/src/core/runtime/terminal.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import tty from "node:tty"; -import type { CliInput } from "../types"; +import type { CliInput } from "../invocation/commandInputs"; export interface AppMouseOptions { stdinIsTTY?: boolean; diff --git a/src/core/theme/customThemes.test.ts b/src/core/theme/customThemes.test.ts index b36ca4dd0..72e87dd98 100644 --- a/src/core/theme/customThemes.test.ts +++ b/src/core/theme/customThemes.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { NamedCustomThemeConfig } from "../types"; +import type { NamedCustomThemeConfig } from "../../extension-api/types"; import type { RegisteredCustomTheme } from "./customThemes"; import { collectSessionCustomThemes, describeCustomThemeIdIssue } from "./customThemes"; diff --git a/src/core/theme/customThemes.ts b/src/core/theme/customThemes.ts index 3c47eb195..37a2bdde0 100644 --- a/src/core/theme/customThemes.ts +++ b/src/core/theme/customThemes.ts @@ -1,5 +1,5 @@ import type { StartupNotice } from "../runtime/startupNotice"; -import type { NamedCustomThemeConfig } from "../types"; +import type { NamedCustomThemeConfig } from "../../extension-api/types"; import { BUNDLED_SHIKI_THEME_IDS, resolveBundledShikiThemeId } from "./catalog"; import { LEGACY_CUSTOM_SYNTAX_COLOR_KEYS } from "./legacySyntaxScopes"; diff --git a/src/core/theme/detection.ts b/src/core/theme/detection.ts index c7a458a36..b6e2d35ad 100644 --- a/src/core/theme/detection.ts +++ b/src/core/theme/detection.ts @@ -1,6 +1,8 @@ -import type { TerminalThemeMode } from "../types"; - -export type { TerminalThemeMode } from "../types"; +/** + * Which of the two terminal backgrounds a session is drawn against. Probing the + * terminal answers it here; the app carries the answer into theme selection. + */ +export type TerminalThemeMode = "light" | "dark"; export interface RgbColor { red: number; diff --git a/src/core/theme/legacySyntaxScopes.ts b/src/core/theme/legacySyntaxScopes.ts index 9f60eb03f..ae182f35a 100644 --- a/src/core/theme/legacySyntaxScopes.ts +++ b/src/core/theme/legacySyntaxScopes.ts @@ -1,4 +1,4 @@ -import type { CustomSyntaxColorsConfig, CustomSyntaxScopesConfig } from "../types"; +import type { CustomSyntaxColorsConfig, CustomSyntaxScopesConfig } from "../../extension-api/types"; /** Deprecated role keys accepted only during the temporary configuration migration window. */ export const LEGACY_CUSTOM_SYNTAX_COLOR_KEYS = [ diff --git a/src/core/types.ts b/src/core/types.ts deleted file mode 100644 index ab0d05d2b..000000000 --- a/src/core/types.ts +++ /dev/null @@ -1,157 +0,0 @@ -import type { NamedCustomThemeConfig } from "../extension-api/types"; -import type { Changeset, DiffFile } from "./changeset/model"; -import type { - CliInput, - CursorLine, - LayoutMode, - SidebarVisibility, -} from "./invocation/commandInputs"; -import type { StartupNotice } from "./runtime/startupNotice"; -import type { VcsCatalog } from "./vcs/types"; - -/** - * Shapes that are simultaneously internal model types and part of the published - * extension contract are declared once in `src/extension-api/types.ts` — the - * module whose declarations ship — and re-exported here so internal code keeps - * importing them from `core/types`. - */ -export type { - AgentAnnotation, - AgentFileContext, - CustomSyntaxColorsConfig, - CustomSyntaxScopesConfig, - CustomThemeConfig, - NamedCustomThemeConfig, -} from "../extension-api/types"; - -/** - * The changeset model and the command-input shapes moved to leaf modules — - * `changeset/model` and `invocation/commandInputs` — so the VCS contract, watch - * planning, and the session surfaces can import them without this module's - * app-facing layer; they are re-exported here to keep one import site. Only the - * names other modules actually reach for are listed; the union members nothing - * imports stay where they are declared. - */ -export type { - Changeset, - DiffFile, - DiffLineMoveKind, - DiffLineMoveKinds, - SidecarContext, -} from "./changeset/model"; -export type { - CliInput, - CommonOptions, - CursorLine, - DiffToolCommandInput, - ExtensionManageCommandInput, - FileCommandInput, - HelpCommandInput, - LayoutMode, - MarkupRenderCommandInput, - PagerCommandInput, - ParsedCliInput, - PatchCommandInput, - ReviewNoteSource, - SessionCommandInput, - SessionCommandOutput, - SessionCommentAddCommandInput, - SessionCommentApplyCommandInput, - SessionCommentApplyItemInput, - SessionCommentClearCommandInput, - SessionCommentListCommandInput, - SessionCommentListType, - SessionCommentRemoveCommandInput, - SessionHighlightAddCommandInput, - SessionHighlightClearCommandInput, - SessionNavigateCommandInput, - SessionReloadCommandInput, - SessionReviewCommandInput, - SessionSelectorInput, - SidebarVisibility, - VcsDiffCommandInput, - VcsMode, - VcsShowCommandInput, - VcsStashShowCommandInput, -} from "./invocation/commandInputs"; - -export type TerminalThemeMode = "light" | "dark"; - -export interface UserNoteLineTarget { - side: "old" | "new"; - line: number; -} - -/** Resolved `[extensions]` and `[extension.]` configuration for one invocation. */ -export interface ExtensionsConfig { - /** - * False when `--no-extensions` or `[extensions] enabled = false` disables loading. - * - * Scoped to user extensions. Hunk's bundled tier — the Jujutsu and Sapling - * backends — always loads: these switches exist to triage extensions you - * installed, not to drop VCS support. - */ - enabled: boolean; - /** Explicit entry paths from the user config layer. */ - paths: string[]; - /** Explicit entry paths contributed by the repo config layer; trust-gated like `.hunk/extensions`. */ - repoPaths: string[]; - /** Per-extension config tables, keyed by extension id. */ - extensionConfigs: Record>; -} - -/** - * One `[keybindings]` entry: the chord(s) to bind a command to, or `false` to unbind it. - * - * Command ids are the ones the dispatch table declares — `"hunk.app.quit"`, - * `"hunk.review.nextHunk"`, or `"."` for an extension - * command. Resolution against each command's defaults lives in - * `src/ui/lib/keymap.ts`. - */ -export type UserKeyBinding = string | readonly string[] | false; - -export interface PersistedViewPreferences { - mode: LayoutMode; - theme?: string; - showLineNumbers: boolean; - wrapLines: boolean; - showHunkHeaders: boolean; - showMenuBar: boolean; - showAgentNotes: boolean; - copyDecorations: boolean; - cursorLine: CursorLine; -} - -export interface ReloadContext { - cwd: string; - repoRoot?: string; - initialWatchSignature?: string; - /** Complete catalog used to load this review, retained for reload and watch. */ - vcsCatalog?: VcsCatalog; -} - -export interface AppBootstrap { - input: CliInput; - reloadContext: ReloadContext; - changeset: Changeset; - initialMode: LayoutMode; - initialTheme?: string; - initialThemeMode?: TerminalThemeMode; - /** Selectable custom themes for this session, in menu order. */ - customThemes?: readonly NamedCustomThemeConfig[]; - initialShowLineNumbers?: boolean; - initialTabWidth?: number; - initialWrapLines?: boolean; - initialShowHunkHeaders?: boolean; - initialShowMenuBar?: boolean; - initialSidebar?: SidebarVisibility; - initialShowAgentNotes?: boolean; - initialCopyDecorations?: boolean; - initialCursorLine?: CursorLine; - startupNotices?: readonly StartupNotice[]; - viewPreferencesConfigPath?: string; - /** The user's `[keybindings]` table, resolved against command defaults in App. */ - keybindings?: Record; - /** App-owned extension state carried without coupling core to the extension host. */ - extensions?: ExtensionState; -} diff --git a/src/core/watch/plan.test.ts b/src/core/watch/plan.test.ts index e8fdffd16..93bf543b7 100644 --- a/src/core/watch/plan.test.ts +++ b/src/core/watch/plan.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { posix, win32 } from "node:path"; import { getBundledVcsCatalog } from "../../app/vcsCatalog"; -import type { CliInput } from "../types"; +import type { CliInput } from "../invocation/commandInputs"; import { createVcsCatalog } from "../vcs"; import type { VcsAdapter } from "../vcs/types"; import { resolveWatchPlan as resolveCoreWatchPlan, type WatchPlanContext } from "./plan"; diff --git a/src/core/watch/signature.test.ts b/src/core/watch/signature.test.ts index c023c25ae..d00e3aa67 100644 --- a/src/core/watch/signature.test.ts +++ b/src/core/watch/signature.test.ts @@ -3,7 +3,7 @@ import { mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { getBundledVcsCatalog } from "../../app/vcsCatalog"; -import type { CliInput } from "../types"; +import type { CliInput } from "../invocation/commandInputs"; import { createVcsCatalog } from "../vcs"; import type { VcsAdapter } from "../vcs/types"; import { diff --git a/src/extensions/apply.test.ts b/src/extensions/apply.test.ts index baebca606..2380bdf61 100644 --- a/src/extensions/apply.test.ts +++ b/src/extensions/apply.test.ts @@ -7,7 +7,7 @@ import { HUNK_CORE_VCS_DETECTION_PRIORITY, HUNK_DEFAULT_VCS_DETECTION_PRIORITY, } from "../extension-api/types"; -import type { Changeset, DiffFile } from "../core/types"; +import type { Changeset, DiffFile } from "../core/changeset/model"; import { extendVcsCatalog } from "../core/vcs"; import type { VcsAdapter } from "../core/vcs/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; diff --git a/src/extensions/apply.ts b/src/extensions/apply.ts index 6b3872ef5..6e5415206 100644 --- a/src/extensions/apply.ts +++ b/src/extensions/apply.ts @@ -3,7 +3,7 @@ import { registerFileLanguage, } from "../core/changeset/fileLanguage"; import type { StartupNotice } from "../core/runtime/startupNotice"; -import type { Changeset } from "../core/types"; +import type { Changeset } from "../core/changeset/model"; import { detectVcs, extendVcsCatalog, getDefaultVcsAdapter } from "../core/vcs"; import type { VcsAdapter, VcsCatalog } from "../core/vcs/types"; import { sanitizeTerminalLine } from "../lib/terminalText"; diff --git a/src/extensions/host.test.ts b/src/extensions/host.test.ts index bfdbedf8d..9eb55bce9 100644 --- a/src/extensions/host.test.ts +++ b/src/extensions/host.test.ts @@ -2,7 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import type { Changeset } from "../core/types"; +import type { Changeset } from "../core/changeset/model"; import { getVcsOperation } from "../core/vcs"; import type { VcsAdapter } from "../core/vcs/types"; import { discoverExtensions } from "./discovery"; diff --git a/src/extensions/manage/cli.ts b/src/extensions/manage/cli.ts index 0744a6661..335afa0c5 100644 --- a/src/extensions/manage/cli.ts +++ b/src/extensions/manage/cli.ts @@ -1,6 +1,6 @@ import { HunkUserError } from "../../core/invocation/errors"; import { resolveInstalledExtensionsRoot } from "../../core/invocation/paths"; -import type { ExtensionManageCommandInput } from "../../core/types"; +import type { ExtensionManageCommandInput } from "../../core/invocation/commandInputs"; import { installExtension, listExtensions, diff --git a/src/extensions/publicApiRobustness.test.ts b/src/extensions/publicApiRobustness.test.ts index 6469d0332..486e634ba 100644 --- a/src/extensions/publicApiRobustness.test.ts +++ b/src/extensions/publicApiRobustness.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; import { collectSessionCustomThemes } from "../core/theme/customThemes"; -import type { Changeset } from "../core/types"; +import type { Changeset } from "../core/changeset/model"; import { detectVcs, extendVcsCatalog } from "../core/vcs"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; import { createTestDiffFile } from "../../test/helpers/diff-helpers"; diff --git a/src/extensions/startup.test.ts b/src/extensions/startup.test.ts index 10fb9b205..cefa17cec 100644 --- a/src/extensions/startup.test.ts +++ b/src/extensions/startup.test.ts @@ -2,7 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import type { ExtensionsConfig } from "../core/types"; +import type { ExtensionsConfig } from "../core/invocation/config"; import { createExtensionLoadNotices, loadStartupExtensions, mergeStartupNotices } from "./startup"; import { createEmptyExtensionLoadResult } from "./types"; diff --git a/src/extensions/startup.ts b/src/extensions/startup.ts index cc4b75626..a1a6b3a72 100644 --- a/src/extensions/startup.ts +++ b/src/extensions/startup.ts @@ -1,6 +1,6 @@ import { isDeepStrictEqual } from "node:util"; import type { StartupNotice } from "../core/runtime/startupNotice"; -import type { ExtensionsConfig } from "../core/types"; +import type { ExtensionsConfig } from "../core/invocation/config"; import { sanitizeTerminalText } from "../lib/terminalText"; import { discoverExtensions } from "./discovery"; import { retireExtensionLoadResult } from "./events"; diff --git a/src/extensions/vcsPatchResult.ts b/src/extensions/vcsPatchResult.ts index d17a392f4..540697358 100644 --- a/src/extensions/vcsPatchResult.ts +++ b/src/extensions/vcsPatchResult.ts @@ -9,7 +9,7 @@ import { SourceTextTooLargeError, type FileSourceSide, } from "../core/changeset/fileSource"; -import type { DiffFile } from "../core/types"; +import type { DiffFile } from "../core/changeset/model"; import type { VcsPatchResult } from "../core/vcs/types"; import type { ExtensionVcsExtraFile, diff --git a/src/opentui/model.ts b/src/opentui/model.ts index 5a6dfc69b..533c1ad34 100644 --- a/src/opentui/model.ts +++ b/src/opentui/model.ts @@ -4,7 +4,7 @@ import { normalizeDiffMetadataPaths, normalizeDiffPath } from "../core/changeset import { countDiffStats } from "../core/changeset/diffFile"; import { splitPatchIntoFileChunks, findPatchChunk } from "../core/patch/chunks"; import { sanitizePatch } from "../core/patch/sanitize"; -import type { DiffFile } from "../core/types"; +import type { DiffFile } from "../core/changeset/model"; import type { HunkDiffFile, HunkDiffFileInput } from "./types"; const NORMALIZED_HUNK_DIFF_FILES = new WeakSet(); diff --git a/src/session/agent/cliClient.test.ts b/src/session/agent/cliClient.test.ts index f3f026dbe..3e95c02b1 100644 --- a/src/session/agent/cliClient.test.ts +++ b/src/session/agent/cliClient.test.ts @@ -9,7 +9,7 @@ import { createTestSessionReviewHunk, createTestSessionSnapshot, } from "../../../test/helpers/session-daemon-fixtures"; -import type { SessionSelectorInput } from "../../core/types"; +import type { SessionSelectorInput } from "../../core/invocation/commandInputs"; import { HUNK_SESSION_API_PATH, HUNK_SESSION_API_VERSION, diff --git a/src/session/agent/cliClient.ts b/src/session/agent/cliClient.ts index 998971b8a..1b6fe1df8 100644 --- a/src/session/agent/cliClient.ts +++ b/src/session/agent/cliClient.ts @@ -38,7 +38,7 @@ import type { SessionReloadCommandInput, SessionReviewCommandInput, SessionSelectorInput, -} from "../../core/types"; +} from "../../core/invocation/commandInputs"; import { describeSessionSelector } from "@hunk/session-broker-core"; export interface HunkSessionCliClient { diff --git a/src/session/agent/commands.daemon.test.ts b/src/session/agent/commands.daemon.test.ts index a067f7d85..c795e56fe 100644 --- a/src/session/agent/commands.daemon.test.ts +++ b/src/session/agent/commands.daemon.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { createServer } from "node:net"; import { platform } from "node:os"; -import type { SessionCommandInput } from "../../core/types"; +import type { SessionCommandInput } from "../../core/invocation/commandInputs"; import { createTestListedSession } from "../../../test/helpers/session-daemon-fixtures"; import { runSessionCommand, diff --git a/src/session/agent/commands.test.ts b/src/session/agent/commands.test.ts index 44b6c7297..94560a939 100644 --- a/src/session/agent/commands.test.ts +++ b/src/session/agent/commands.test.ts @@ -7,7 +7,10 @@ import { createTestSessionReview as buildTestSessionReview, createTestSessionSnapshot, } from "../../../test/helpers/session-daemon-fixtures"; -import type { SessionCommandInput, SessionSelectorInput } from "../../core/types"; +import type { + SessionCommandInput, + SessionSelectorInput, +} from "../../core/invocation/commandInputs"; import { runSessionCommand, setSessionCommandTestHooks, diff --git a/src/session/agent/commands.ts b/src/session/agent/commands.ts index 6e8011e59..29414eed1 100644 --- a/src/session/agent/commands.ts +++ b/src/session/agent/commands.ts @@ -2,7 +2,7 @@ import type { SessionCommandInput, SessionCommandOutput, SessionSelectorInput, -} from "../../core/types"; +} from "../../core/invocation/commandInputs"; import type { SessionLiveCommentSummary, SessionReviewNoteSummary } from "../types"; import { NO_ACTIVE_SESSIONS_MESSAGE } from "./errors"; import { diff --git a/src/session/broker/wire.ts b/src/session/broker/wire.ts index 9ae429269..155e4c4c4 100644 --- a/src/session/broker/wire.ts +++ b/src/session/broker/wire.ts @@ -2,7 +2,7 @@ import { EXPERIMENTAL_FEATURES, type ExperimentalFeature, } from "../../core/invocation/experimental"; -import type { CliInput } from "../../core/types"; +import type { CliInput } from "../../core/invocation/commandInputs"; import { MAX_REGISTRATION_FILES, MAX_REGISTRATION_HUNKS_PER_FILE, diff --git a/src/session/protocol.ts b/src/session/protocol.ts index f20ade4ce..73f02e7ee 100644 --- a/src/session/protocol.ts +++ b/src/session/protocol.ts @@ -10,7 +10,7 @@ import type { SessionReloadCommandInput, SessionReviewCommandInput, SessionSelectorInput, -} from "../core/types"; +} from "../core/invocation/commandInputs"; import type { AppliedCommentBatchResult, AppliedCommentResult, diff --git a/src/session/protocolSchemas.ts b/src/session/protocolSchemas.ts index f4eea82a9..452eb6047 100644 --- a/src/session/protocolSchemas.ts +++ b/src/session/protocolSchemas.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import type { CliInput } from "../core/types"; +import type { CliInput } from "../core/invocation/commandInputs"; import type { SessionDaemonRequest } from "./protocol"; /** diff --git a/src/session/types.ts b/src/session/types.ts index a6d54a1df..89cd1fb87 100644 --- a/src/session/types.ts +++ b/src/session/types.ts @@ -2,7 +2,7 @@ import type { ExperimentalFeature } from "../core/invocation/experimental"; import type { ExtensionLineHighlightTone, SessionReloadReason } from "../extension-api/types"; import type { CommentTargetInput, DiffSide } from "../core/liveComments"; import type { ReviewPublicationAddress } from "../core/review/generationOrder"; -import type { CliInput, ReviewNoteSource } from "../core/types"; +import type { CliInput, ReviewNoteSource } from "../core/invocation/commandInputs"; import type { HunkReviewActionEnvelopeV1, HunkReviewResourceCatalogV1, diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 18bef4949..4ed9f2228 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -19,6 +19,7 @@ import { diffPersistedViewPreferences, saveGlobalViewPreferences, saveViewPreferencesPromptPreference, + type PersistedViewPreferences, } from "../core/invocation/config"; import { experimentalFeatureEnabled, @@ -26,14 +27,9 @@ import { } from "../core/invocation/experimental"; import { DEFAULT_TAB_WIDTH } from "../core/invocation/tabWidth"; import { isVcsReviewInput } from "../core/vcs"; -import type { - AppBootstrap, - CliInput, - CursorLine, - LayoutMode, - PersistedViewPreferences, - UserNoteLineTarget, -} from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; +import type { CliInput, CursorLine, LayoutMode } from "../core/invocation/commandInputs"; +import type { UserNoteLineTarget } from "../core/liveComments"; import { canReloadInput } from "../core/invocation/inputReload"; import { sanitizeTerminalLine } from "../lib/terminalText"; import { diff --git a/src/ui/AppHost.cursor-line.test.tsx b/src/ui/AppHost.cursor-line.test.tsx index d5c7d8ef5..283224dde 100644 --- a/src/ui/AppHost.cursor-line.test.tsx +++ b/src/ui/AppHost.cursor-line.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; -import type { CursorLine } from "../core/types"; +import type { CursorLine } from "../core/invocation/commandInputs"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile, lines } from "../../test/helpers/diff-helpers"; import { AppHost } from "./AppHost"; diff --git a/src/ui/AppHost.edit-in-editor.test.tsx b/src/ui/AppHost.edit-in-editor.test.tsx index b36cadbe0..d4f5a3d91 100644 --- a/src/ui/AppHost.edit-in-editor.test.tsx +++ b/src/ui/AppHost.edit-in-editor.test.tsx @@ -4,7 +4,7 @@ import { mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { act } from "react"; -import type { AppBootstrap } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile, lines } from "../../test/helpers/diff-helpers"; diff --git a/src/ui/AppHost.extension-dialogs.test.tsx b/src/ui/AppHost.extension-dialogs.test.tsx index 370c78e5b..0a303e79c 100644 --- a/src/ui/AppHost.extension-dialogs.test.tsx +++ b/src/ui/AppHost.extension-dialogs.test.tsx @@ -10,7 +10,7 @@ import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/load import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import type { CliInput } from "../core/types"; +import type { CliInput } from "../core/invocation/commandInputs"; import type { HunkSessionBrokerClient } from "../session/broker/brokerClient"; import { loadStartupExtensions } from "../extensions/startup"; import { AppHost } from "./AppHost"; diff --git a/src/ui/AppHost.extensions.test.tsx b/src/ui/AppHost.extensions.test.tsx index bb4d8b144..9e299b0a7 100644 --- a/src/ui/AppHost.extensions.test.tsx +++ b/src/ui/AppHost.extensions.test.tsx @@ -17,7 +17,7 @@ import { ReviewProducer } from "../app/review/producer"; import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/loaders"; -import type { CliInput } from "../core/types"; +import type { CliInput } from "../core/invocation/commandInputs"; import type { HunkSessionBrokerClient } from "../session/broker/brokerClient"; import { diff --git a/src/ui/AppHost.interactions.test.tsx b/src/ui/AppHost.interactions.test.tsx index bb799f21a..499a5a5aa 100644 --- a/src/ui/AppHost.interactions.test.tsx +++ b/src/ui/AppHost.interactions.test.tsx @@ -12,7 +12,8 @@ import type { HunkSessionSnapshot, } from "../session/types"; import { LEGACY_CUSTOM_SYNTAX_NOTICE } from "../core/runtime/startupNotice"; -import type { AppBootstrap, LayoutMode } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; +import type { LayoutMode } from "../core/invocation/commandInputs"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { capturedTestColorToHex } from "../../test/helpers/test-color-helpers"; import { createTestDiffFile as buildTestDiffFile, lines } from "../../test/helpers/diff-helpers"; diff --git a/src/ui/AppHost.key-routing.test.tsx b/src/ui/AppHost.key-routing.test.tsx index ec5a7be9c..3cc571e23 100644 --- a/src/ui/AppHost.key-routing.test.tsx +++ b/src/ui/AppHost.key-routing.test.tsx @@ -5,7 +5,7 @@ import { describe, expect, mock, test } from "bun:test"; import { ScrollBoxRenderable, type Renderable } from "@opentui/core"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; -import type { AppBootstrap } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile } from "../../test/helpers/diff-helpers"; import { loadStartupExtensions } from "../extensions/startup"; diff --git a/src/ui/AppHost.keybindings.test.tsx b/src/ui/AppHost.keybindings.test.tsx index ad6ff613e..dbc86b69a 100644 --- a/src/ui/AppHost.keybindings.test.tsx +++ b/src/ui/AppHost.keybindings.test.tsx @@ -9,7 +9,7 @@ import { removeTestDirectory } from "../../test/helpers/filesystem"; import { resolveConfiguredCliInput } from "../core/invocation/config"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; import { loadAppBootstrap } from "../core/changeset/loaders"; -import type { AppBootstrap } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; import { createEmptyExtensionLoadResult } from "../extensions/types"; import { AppHost } from "./AppHost"; diff --git a/src/ui/AppHost.responsive.test.tsx b/src/ui/AppHost.responsive.test.tsx index 2958da6aa..1f0f79144 100644 --- a/src/ui/AppHost.responsive.test.tsx +++ b/src/ui/AppHost.responsive.test.tsx @@ -1,7 +1,8 @@ import { describe, expect, mock, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; -import type { AppBootstrap, LayoutMode } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; +import type { LayoutMode } from "../core/invocation/commandInputs"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile } from "../../test/helpers/diff-helpers"; diff --git a/src/ui/AppHost.scroll-regression.test.tsx b/src/ui/AppHost.scroll-regression.test.tsx index a39e7dcbd..bb0e7f99b 100644 --- a/src/ui/AppHost.scroll-regression.test.tsx +++ b/src/ui/AppHost.scroll-regression.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, mock, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; -import type { AppBootstrap } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile } from "../../test/helpers/diff-helpers"; diff --git a/src/ui/AppHost.selection.test.tsx b/src/ui/AppHost.selection.test.tsx index 416b6fb66..b73054c97 100644 --- a/src/ui/AppHost.selection.test.tsx +++ b/src/ui/AppHost.selection.test.tsx @@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { MouseButtons } from "@opentui/core/testing"; import { act } from "react"; -import type { AppBootstrap } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile, lines } from "../../test/helpers/diff-helpers"; import { measureTextWidth } from "./lib/text"; diff --git a/src/ui/AppHost.sidebar-resize.test.tsx b/src/ui/AppHost.sidebar-resize.test.tsx index 856a7a368..808d00ab0 100644 --- a/src/ui/AppHost.sidebar-resize.test.tsx +++ b/src/ui/AppHost.sidebar-resize.test.tsx @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; -import type { AppBootstrap } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile as buildTestDiffFile, lines } from "../../test/helpers/diff-helpers"; import { createEmptyExtensionLoadResult } from "../extensions/types"; diff --git a/src/ui/AppHost.sidebar-visibility.test.tsx b/src/ui/AppHost.sidebar-visibility.test.tsx index a37ab88d8..6c8fb99fa 100644 --- a/src/ui/AppHost.sidebar-visibility.test.tsx +++ b/src/ui/AppHost.sidebar-visibility.test.tsx @@ -1,7 +1,8 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; -import type { AppBootstrap, SidebarVisibility } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; +import type { SidebarVisibility } from "../core/invocation/commandInputs"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile as buildTestDiffFile, lines } from "../../test/helpers/diff-helpers"; import { HUNK_FILES_PANE_KEY } from "../extensions/extensionIds"; diff --git a/src/ui/AppHost.tsx b/src/ui/AppHost.tsx index 9eb71f05c..feba7b085 100644 --- a/src/ui/AppHost.tsx +++ b/src/ui/AppHost.tsx @@ -6,7 +6,8 @@ import { getBundledVcsCatalog } from "../app/vcsCatalog"; import { resolveConfiguredCliInput } from "../core/invocation/config"; import { resolveRuntimeCliInput } from "../core/runtime/terminal"; import type { StartupNotice } from "../core/runtime/startupNotice"; -import type { AppBootstrap, CliInput } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; +import type { CliInput } from "../core/invocation/commandInputs"; import type { ExtensionLoadResult } from "../extensions/types"; import { createUnknownVcsNotice, diff --git a/src/ui/AppHost.workspace.test.tsx b/src/ui/AppHost.workspace.test.tsx index c2ca73357..7ab62bc08 100644 --- a/src/ui/AppHost.workspace.test.tsx +++ b/src/ui/AppHost.workspace.test.tsx @@ -17,7 +17,7 @@ import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/load import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import type { CliInput } from "../core/types"; +import type { CliInput } from "../core/invocation/commandInputs"; import { loadStartupExtensions } from "../extensions/startup"; import type { HunkSessionBrokerClient } from "../session/broker/brokerClient"; import type { WorkspaceFileWriter } from "./App"; diff --git a/src/ui/components/panes/AgentInlineNote.tsx b/src/ui/components/panes/AgentInlineNote.tsx index ae72488e3..e7305c2d1 100644 --- a/src/ui/components/panes/AgentInlineNote.tsx +++ b/src/ui/components/panes/AgentInlineNote.tsx @@ -5,7 +5,9 @@ import { type TextareaRenderable, } from "@opentui/core"; import { useLayoutEffect, useRef, type ReactNode } from "react"; -import type { AgentAnnotation, DiffFile, LayoutMode } from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; +import type { LayoutMode } from "../../../core/invocation/commandInputs"; +import type { AgentAnnotation } from "../../../extension-api/types"; import { agentNoteBoxLayout } from "../../lib/agentNoteGeometry"; import { annotationRangeLabel, reviewNoteSource } from "../../lib/agentAnnotations"; import { wrapText } from "../../lib/text"; diff --git a/src/ui/components/panes/DiffFileHeaderRow.tsx b/src/ui/components/panes/DiffFileHeaderRow.tsx index 80aea2c8c..e563d5e97 100644 --- a/src/ui/components/panes/DiffFileHeaderRow.tsx +++ b/src/ui/components/panes/DiffFileHeaderRow.tsx @@ -1,4 +1,4 @@ -import type { DiffFile } from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; import { fileHeaderStats, fitFileHeaderLabel } from "../../lib/fileHeader"; import type { AppTheme } from "../../themes"; diff --git a/src/ui/components/panes/DiffPane.tsx b/src/ui/components/panes/DiffPane.tsx index 9b242cf53..97b1d0ebe 100644 --- a/src/ui/components/panes/DiffPane.tsx +++ b/src/ui/components/panes/DiffPane.tsx @@ -14,13 +14,10 @@ import { type RefObject, } from "react"; import { DEFAULT_TAB_WIDTH } from "../../../core/invocation/tabWidth"; -import type { - AgentAnnotation, - CursorLine, - DiffFile, - LayoutMode, - UserNoteLineTarget, -} from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; +import type { CursorLine, LayoutMode } from "../../../core/invocation/commandInputs"; +import type { UserNoteLineTarget } from "../../../core/liveComments"; +import type { AgentAnnotation } from "../../../extension-api/types"; import { resolveReviewRevealNoteId } from "../../../core/review/selectors"; import { reviewNoteAnchorLine, diff --git a/src/ui/components/panes/DiffSection.tsx b/src/ui/components/panes/DiffSection.tsx index 8ffb4c9f5..be9412891 100644 --- a/src/ui/components/panes/DiffSection.tsx +++ b/src/ui/components/panes/DiffSection.tsx @@ -1,5 +1,7 @@ import { memo } from "react"; -import type { DiffFile, LayoutMode, UserNoteLineTarget } from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; +import type { LayoutMode } from "../../../core/invocation/commandInputs"; +import type { UserNoteLineTarget } from "../../../core/liveComments"; import type { FileSourceStatus } from "../../diff/expandCollapsedRows"; import { DiffSectionBody, type ActiveAddNoteAffordance } from "../../diff/DiffSectionBody"; import type { CursorHighlight } from "../../diff/renderRows"; diff --git a/src/ui/components/panes/ExtensionPane.tsx b/src/ui/components/panes/ExtensionPane.tsx index 3689fd34c..b4911ef0e 100644 --- a/src/ui/components/panes/ExtensionPane.tsx +++ b/src/ui/components/panes/ExtensionPane.tsx @@ -7,7 +7,7 @@ import type { ExtensionPaneProps, ExtensionCurrentLinePaint, } from "../../../extension-api/types"; -import type { DiffFile } from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; import { paneKey } from "../../../extensions/apply"; import { BuiltInSidebarView } from "../../../extensions/default/ui/sidebar"; import { HUNK_FILES_PANE_KEY } from "../../../extensions/extensionIds"; diff --git a/src/ui/components/panes/FileView.tsx b/src/ui/components/panes/FileView.tsx index 771027dbc..39601e231 100644 --- a/src/ui/components/panes/FileView.tsx +++ b/src/ui/components/panes/FileView.tsx @@ -1,6 +1,6 @@ import { TextAttributes } from "@opentui/core"; import { Component, memo, useMemo, type ReactNode } from "react"; -import type { DiffFile } from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; import type { ExtensionFileViewLayout, ExtensionFileViewRow, diff --git a/src/ui/components/panes/copySelection.test.ts b/src/ui/components/panes/copySelection.test.ts index b6114b370..88f8d516b 100644 --- a/src/ui/components/panes/copySelection.test.ts +++ b/src/ui/components/panes/copySelection.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; import { parseDiffFromFile } from "@pierre/diffs"; -import type { DiffFile } from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; import { resolveTheme } from "../../themes"; import { measureDiffSectionGeometry } from "../../diff/diffSectionGeometry"; import { buildFileSectionLayouts } from "../../lib/fileSectionLayout"; diff --git a/src/ui/components/panes/copySelection.ts b/src/ui/components/panes/copySelection.ts index 9e2a31c01..f3e2b0352 100644 --- a/src/ui/components/panes/copySelection.ts +++ b/src/ui/components/panes/copySelection.ts @@ -1,4 +1,5 @@ -import type { DiffFile, LayoutMode } from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; +import type { LayoutMode } from "../../../core/invocation/commandInputs"; import { DIFF_RAIL_PREFIX_WIDTH, resolveSplitCellGeometry, diff --git a/src/ui/components/scrollbar/VerticalScrollbar.test.tsx b/src/ui/components/scrollbar/VerticalScrollbar.test.tsx index 12eadd314..702b535d4 100644 --- a/src/ui/components/scrollbar/VerticalScrollbar.test.tsx +++ b/src/ui/components/scrollbar/VerticalScrollbar.test.tsx @@ -3,7 +3,8 @@ import { testRender } from "@opentui/react/test-utils"; import { parseDiffFromFile } from "@pierre/diffs"; import { act, createRef } from "react"; import { capturedTestColorToHex } from "../../../../test/helpers/test-color-helpers"; -import type { AppBootstrap, DiffFile } from "../../../core/types"; +import type { AppBootstrap } from "../../../core/bootstrap"; +import type { DiffFile } from "../../../core/changeset/model"; import { resolveTheme } from "../../themes"; import { VerticalScrollbar, type VerticalScrollbarHandle } from "./VerticalScrollbar"; diff --git a/src/ui/components/ui-components.test.tsx b/src/ui/components/ui-components.test.tsx index c175ea7de..75bead05f 100644 --- a/src/ui/components/ui-components.test.tsx +++ b/src/ui/components/ui-components.test.tsx @@ -2,7 +2,8 @@ import { describe, expect, mock, spyOn, test } from "bun:test"; import type { ScrollBoxRenderable } from "@opentui/core"; import { testRender } from "@opentui/react/test-utils"; import { act, createRef, useCallback, useEffect, useRef, useState, type ReactNode } from "react"; -import type { AppBootstrap, DiffFile } from "../../core/types"; +import type { AppBootstrap } from "../../core/bootstrap"; +import type { DiffFile } from "../../core/changeset/model"; import { createTestVcsAppBootstrap } from "../../../test/helpers/app-bootstrap"; import { capturedTestColorToHex } from "../../../test/helpers/test-color-helpers"; import { diff --git a/src/ui/diff/DiffSectionBody.tsx b/src/ui/diff/DiffSectionBody.tsx index d060a779a..6d5d61c7d 100644 --- a/src/ui/diff/DiffSectionBody.tsx +++ b/src/ui/diff/DiffSectionBody.tsx @@ -7,7 +7,9 @@ import { useRenderer } from "@opentui/react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; -import type { DiffFile, LayoutMode, UserNoteLineTarget } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { UserNoteLineTarget } from "../../core/liveComments"; import { AgentInlineNote } from "../components/panes/AgentInlineNote"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; import type { CopySelectedRowRange } from "../lib/diffSpatial"; diff --git a/src/ui/diff/codeColumns.test.ts b/src/ui/diff/codeColumns.test.ts index 63ee5963d..9314b1f56 100644 --- a/src/ui/diff/codeColumns.test.ts +++ b/src/ui/diff/codeColumns.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { expandDiffTabs, findMaxLineNumberInRows, diff --git a/src/ui/diff/codeColumns.ts b/src/ui/diff/codeColumns.ts index 04a276968..1a3628784 100644 --- a/src/ui/diff/codeColumns.ts +++ b/src/ui/diff/codeColumns.ts @@ -1,5 +1,6 @@ import { DEFAULT_TAB_WIDTH, validateTabWidth } from "../../core/invocation/tabWidth"; -import type { DiffFile, LayoutMode } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; import { measureTextWidth } from "../lib/text"; import type { DiffRow } from "./diffRowModel"; diff --git a/src/ui/diff/diffRowModel.ts b/src/ui/diff/diffRowModel.ts index c69d32c31..83c23e41d 100644 --- a/src/ui/diff/diffRowModel.ts +++ b/src/ui/diff/diffRowModel.ts @@ -7,7 +7,7 @@ * the builders themselves. */ import type { ReviewGapPosition } from "../../core/review/expansion"; -import type { DiffLineMoveKind } from "../../core/types"; +import type { DiffLineMoveKind } from "../../core/changeset/model"; export interface RenderSpan { text: string; diff --git a/src/ui/diff/diffRows.test.ts b/src/ui/diff/diffRows.test.ts index 1c84c75bc..3707acff8 100644 --- a/src/ui/diff/diffRows.test.ts +++ b/src/ui/diff/diffRows.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { parseDiffFromFile, parsePatchFiles } from "@pierre/diffs"; import { createTwoFilesPatch } from "diff"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { buildSplitRows, buildStackRows, diff --git a/src/ui/diff/diffRows.ts b/src/ui/diff/diffRows.ts index a98187be0..fbcaccc41 100644 --- a/src/ui/diff/diffRows.ts +++ b/src/ui/diff/diffRows.ts @@ -21,7 +21,7 @@ import { type ReviewGapAddress, } from "../../core/review/expansion"; import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; -import type { DiffFile, DiffLineMoveKind } from "../../core/types"; +import type { DiffFile, DiffLineMoveKind } from "../../core/changeset/model"; import { blendHex, hexColorDistance } from "../lib/color"; import { measureTextWidth } from "../lib/text"; import { sanitizeTerminalLine } from "../../lib/terminalText"; diff --git a/src/ui/diff/diffSectionGeometry.ts b/src/ui/diff/diffSectionGeometry.ts index d414074c9..8b34f9e4f 100644 --- a/src/ui/diff/diffSectionGeometry.ts +++ b/src/ui/diff/diffSectionGeometry.ts @@ -1,5 +1,6 @@ import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; -import type { DiffFile, LayoutMode } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; import { measureAgentInlineNoteHeight } from "../components/panes/AgentInlineNote"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; import type { SectionGeometry, VerticalBounds } from "../lib/diffSpatial"; diff --git a/src/ui/diff/diffSectionRowPlan.ts b/src/ui/diff/diffSectionRowPlan.ts index 5de658e4b..6404f00bd 100644 --- a/src/ui/diff/diffSectionRowPlan.ts +++ b/src/ui/diff/diffSectionRowPlan.ts @@ -1,6 +1,7 @@ import { reviewExpansionSide } from "../../core/review/expansion"; import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; -import type { DiffFile, LayoutMode } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; import type { AppTheme } from "../themes"; import { findMaxLineNumber, findMaxLineNumberInRows } from "./codeColumns"; diff --git a/src/ui/diff/lineHighlightPaint.ts b/src/ui/diff/lineHighlightPaint.ts index 6a03fc2a0..afb1e2254 100644 --- a/src/ui/diff/lineHighlightPaint.ts +++ b/src/ui/diff/lineHighlightPaint.ts @@ -19,7 +19,7 @@ import { } from "../../core/review/expansion"; import { normalizedReviewSourceLines } from "../../core/review/geometry"; import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { ExtensionLineHighlightTone } from "../../extension-api/types"; import { sanitizeTerminalLine } from "../../lib/terminalText"; import type { ValidatedLineHighlight } from "../highlights/validate"; diff --git a/src/ui/diff/renderRows.tsx b/src/ui/diff/renderRows.tsx index 191816d1d..b8d786883 100644 --- a/src/ui/diff/renderRows.tsx +++ b/src/ui/diff/renderRows.tsx @@ -1,6 +1,7 @@ import { Fragment, isValidElement, memo, type ReactNode } from "react"; import { parseColor, StyledText, type TextChunk } from "@opentui/core"; -import type { DiffFile, UserNoteLineTarget } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { UserNoteLineTarget } from "../../core/liveComments"; import type { AppTheme } from "../themes"; import { resolveSplitCellGeometry, @@ -46,7 +47,7 @@ import { wrapSanitizedTextByWidth, } from "../lib/text"; import type { CopySelectedRowRange } from "../lib/diffSpatial"; -import type { CursorLine } from "../../core/types"; +import type { CursorLine } from "../../core/invocation/commandInputs"; export interface CursorHighlight { /** The render plan anchor of the row the cursor rests on, shared with reveal lookups. */ diff --git a/src/ui/diff/reviewRenderPlan.test.ts b/src/ui/diff/reviewRenderPlan.test.ts index 99361e22e..68deae23f 100644 --- a/src/ui/diff/reviewRenderPlan.test.ts +++ b/src/ui/diff/reviewRenderPlan.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; import { parseDiffFromFile } from "@pierre/diffs"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { createVisibleAgentNote } from "../lib/agentAnnotations"; import { expandCollapsedRows } from "./expandCollapsedRows"; import { diff --git a/src/ui/diff/reviewRenderPlan.ts b/src/ui/diff/reviewRenderPlan.ts index 7667a0144..71f409377 100644 --- a/src/ui/diff/reviewRenderPlan.ts +++ b/src/ui/diff/reviewRenderPlan.ts @@ -1,6 +1,7 @@ import { reviewNoteAnchorLine, reviewNoteOwnerHunkIndex } from "../../core/review/state"; import type { ReviewRangeAnchorV1 } from "../../core/review/types"; -import type { AgentAnnotation, UserNoteLineTarget } from "../../core/types"; +import type { UserNoteLineTarget } from "../../core/liveComments"; +import type { AgentAnnotation } from "../../extension-api/types"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; import { diffHunkId } from "../lib/ids"; import type { DiffRow } from "./diffRows"; diff --git a/src/ui/diff/reviewRowGeometry.ts b/src/ui/diff/reviewRowGeometry.ts index c70dcf92e..337bb24f0 100644 --- a/src/ui/diff/reviewRowGeometry.ts +++ b/src/ui/diff/reviewRowGeometry.ts @@ -5,7 +5,7 @@ * where each hunk's visible extent falls. Heights resolve before mount, which is why note * markup has to lay out deterministically from `(markup, width)` alone. */ -import type { LayoutMode } from "../../core/types"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; import { measureAgentInlineNoteHeight } from "../components/panes/AgentInlineNote"; import type { SectionGeometry, VerticalBounds } from "../lib/diffSpatial"; import { reviewRowId } from "../lib/ids"; diff --git a/src/ui/diff/useHighlightedDiff.ts b/src/ui/diff/useHighlightedDiff.ts index fac87bdcb..9eee5b7a6 100644 --- a/src/ui/diff/useHighlightedDiff.ts +++ b/src/ui/diff/useHighlightedDiff.ts @@ -1,5 +1,5 @@ import { useLayoutEffect, useState } from "react"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { AppTheme } from "../themes"; import { loadHighlightedDiff, type HighlightedDiffCode } from "./diffRows"; import { createHighlightedDiffCache } from "./highlightedDiffCache"; diff --git a/src/ui/diff/useHighlightedSource.ts b/src/ui/diff/useHighlightedSource.ts index c4cd93ca9..52e7de382 100644 --- a/src/ui/diff/useHighlightedSource.ts +++ b/src/ui/diff/useHighlightedSource.ts @@ -1,5 +1,5 @@ import { useLayoutEffect, useMemo, useState } from "react"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { AppTheme } from "../themes"; import { loadHighlightedSourceLines, type HighlightedSourceCode } from "./diffRows"; import { syntaxHighlightThemeName } from "./syntaxHighlightTheme"; diff --git a/src/ui/diff/worker/highlightCompact.test.ts b/src/ui/diff/worker/highlightCompact.test.ts index 21771f552..fa8d639e1 100644 --- a/src/ui/diff/worker/highlightCompact.test.ts +++ b/src/ui/diff/worker/highlightCompact.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; import { cleanLastNewline, parseDiffFromFile, parsePatchFiles } from "@pierre/diffs"; -import type { DiffFile } from "../../../core/types"; +import type { DiffFile } from "../../../core/changeset/model"; import { loadHighlightedDiff, type HighlightedDiffCode } from "../diffRows"; import { COMPACT_HIGHLIGHT_FLAG_WORD_DIFF, diff --git a/src/ui/fileViews/host.ts b/src/ui/fileViews/host.ts index 8ac817f0a..4ae226d9b 100644 --- a/src/ui/fileViews/host.ts +++ b/src/ui/fileViews/host.ts @@ -1,4 +1,4 @@ -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { ExtensionDiffFile, ExtensionFileChangeRange, diff --git a/src/ui/fileViews/renderPlan.ts b/src/ui/fileViews/renderPlan.ts index 15bc06ee4..52a3f527e 100644 --- a/src/ui/fileViews/renderPlan.ts +++ b/src/ui/fileViews/renderPlan.ts @@ -1,4 +1,4 @@ -import type { AgentAnnotation } from "../../core/types"; +import type { AgentAnnotation } from "../../extension-api/types"; import type { ExtensionFileViewLayout, ExtensionFileViewRow } from "../../extension-api/types"; import { inlineNoteStableKey, lineStableKey } from "../diff/reviewRenderPlan"; import { annotationAnchor, type VisibleAgentNote } from "../lib/agentAnnotations"; diff --git a/src/ui/fileViews/useFilePresentationController.test.tsx b/src/ui/fileViews/useFilePresentationController.test.tsx index c4a783ea3..663979523 100644 --- a/src/ui/fileViews/useFilePresentationController.test.tsx +++ b/src/ui/fileViews/useFilePresentationController.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act, useCallback, useMemo, useRef, useState } from "react"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { toReadOnlyFileViews } from "../../extensions/events"; import type { RegisteredFileView } from "../../extensions/types"; import { createTestDiffFile } from "../../../test/helpers/diff-helpers"; diff --git a/src/ui/fileViews/useFilePresentationController.ts b/src/ui/fileViews/useFilePresentationController.ts index 86689cc98..be9db0c00 100644 --- a/src/ui/fileViews/useFilePresentationController.ts +++ b/src/ui/fileViews/useFilePresentationController.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { ExtensionContext, ExtensionDiffFile, diff --git a/src/ui/fileViews/useFilePresentationRendering.ts b/src/ui/fileViews/useFilePresentationRendering.ts index 9f53235a1..a358cc549 100644 --- a/src/ui/fileViews/useFilePresentationRendering.ts +++ b/src/ui/fileViews/useFilePresentationRendering.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, useRef } from "react"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { RegisteredFileView } from "../../extensions/types"; import type { FileViewEpochState, FileViewSelectionState } from "./state"; import type { FileViewRowFailure } from "./types"; diff --git a/src/ui/fileViews/useFileViews.ts b/src/ui/fileViews/useFileViews.ts index 1e1f93080..07560ca0a 100644 --- a/src/ui/fileViews/useFileViews.ts +++ b/src/ui/fileViews/useFileViews.ts @@ -1,5 +1,5 @@ import { useEffect, useMemo, useRef, useState } from "react"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { RegisteredFileView } from "../../extensions/types"; import { fileViewHunkCount, diff --git a/src/ui/highlights/useLineHighlights.ts b/src/ui/highlights/useLineHighlights.ts index e0f5b2826..5488cdaae 100644 --- a/src/ui/highlights/useLineHighlights.ts +++ b/src/ui/highlights/useLineHighlights.ts @@ -1,5 +1,5 @@ import { useEffect, useMemo, useRef, useState } from "react"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { ExtensionLineHighlightInput } from "../../extension-api/types"; import { toReadOnlyFileViews } from "../../extensions/events"; import type { RegisteredLineHighlighter } from "../../extensions/types"; diff --git a/src/ui/highlights/useLineHighlightsController.test.tsx b/src/ui/highlights/useLineHighlightsController.test.tsx index 2228c0bdd..9ad051580 100644 --- a/src/ui/highlights/useLineHighlightsController.test.tsx +++ b/src/ui/highlights/useLineHighlightsController.test.tsx @@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act, createElement, useState } from "react"; import { createTestDiffFile } from "../../../test/helpers/diff-helpers"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { RegisteredLineHighlighter } from "../../extensions/types"; import { registeredLineHighlighterKey } from "./state"; import { scopedEpoch } from "../lib/scopedEpochs"; diff --git a/src/ui/highlights/useLineHighlightsController.ts b/src/ui/highlights/useLineHighlightsController.ts index dc4f59231..588206e9f 100644 --- a/src/ui/highlights/useLineHighlightsController.ts +++ b/src/ui/highlights/useLineHighlightsController.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import type { ExtensionLineHighlightControls } from "../../extension-api/types"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { RegisteredLineHighlighter } from "../../extensions/types"; import { bumpScopedEpoch, reconcileScopedEpochs } from "../lib/scopedEpochs"; import { diff --git a/src/ui/hooks/useHunkSessionBridge.ts b/src/ui/hooks/useHunkSessionBridge.ts index fdb9daf56..98d364201 100644 --- a/src/ui/hooks/useHunkSessionBridge.ts +++ b/src/ui/hooks/useHunkSessionBridge.ts @@ -1,6 +1,7 @@ import { useEffect, useMemo } from "react"; import type { ReviewProducer } from "../../app/review/producer"; -import type { CliInput, DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { CliInput } from "../../core/invocation/commandInputs"; import { reviewHunkRanges } from "../../core/review/geometry"; import { createHunkSessionBridge } from "../../app/session/bridge"; import type { HunkSessionBrokerClient } from "../../session/broker/brokerClient"; diff --git a/src/ui/hooks/useTerminalReview.test.tsx b/src/ui/hooks/useTerminalReview.test.tsx index aa45818d7..cb78d1374 100644 --- a/src/ui/hooks/useTerminalReview.test.tsx +++ b/src/ui/hooks/useTerminalReview.test.tsx @@ -3,7 +3,7 @@ import { testRender } from "@opentui/react/test-utils"; import { act, StrictMode, useEffect, useRef, useState } from "react"; import { builtinAppCommand } from "../../core/invocation/commandCatalog"; import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { createTestDeferred, createTestDiffFile, diff --git a/src/ui/hooks/useTerminalReview.ts b/src/ui/hooks/useTerminalReview.ts index a95634ac8..42e4a92be 100644 --- a/src/ui/hooks/useTerminalReview.ts +++ b/src/ui/hooks/useTerminalReview.ts @@ -23,6 +23,7 @@ import { buildLiveComment, findDiffFileByPath, resolveCommentTarget, + type UserNoteLineTarget, } from "../../core/liveComments"; import { builtinAppCommand, @@ -49,7 +50,9 @@ import { import { REVIEW_VIEWPORT_ANCHOR_REVEAL, type ReviewRevealRequest } from "../../core/review/state"; import { createReviewStore, type ReviewStore } from "../../core/review/store"; import { noDiffFileMatchesMessage } from "../../session/agent/errors"; -import type { AgentAnnotation, DiffFile, LayoutMode, UserNoteLineTarget } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { AgentAnnotation } from "../../extension-api/types"; import type { AppliedCommentBatchResult, AppliedCommentResult, diff --git a/src/ui/hooks/useWatchedInput.ts b/src/ui/hooks/useWatchedInput.ts index 18db2c5a7..3ace994cc 100644 --- a/src/ui/hooks/useWatchedInput.ts +++ b/src/ui/hooks/useWatchedInput.ts @@ -7,7 +7,8 @@ import { import { createWatchEventSource } from "../../core/watch/observer"; import { resolveWatchPlan, type WatchPlan } from "../../core/watch/plan"; import { computeWatchSignature } from "../../core/watch/signature"; -import type { CliInput, ReloadContext } from "../../core/types"; +import type { ReloadContext } from "../../core/bootstrap"; +import type { CliInput } from "../../core/invocation/commandInputs"; export interface WatchedInputRuntime { clock?: WatchControllerClock; diff --git a/src/ui/lib/agentAnnotations.ts b/src/ui/lib/agentAnnotations.ts index cc7fd634d..3417dd4e2 100644 --- a/src/ui/lib/agentAnnotations.ts +++ b/src/ui/lib/agentAnnotations.ts @@ -1,5 +1,7 @@ import type { Hunk } from "@pierre/diffs"; -import type { AgentAnnotation, DiffFile, ReviewNoteSource } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { ReviewNoteSource } from "../../core/invocation/commandInputs"; +import type { AgentAnnotation } from "../../extension-api/types"; import { reviewAnnotationOverlapsHunk } from "../../core/review/annotations"; import { resolveReviewNoteAnchor, reviewGapOwnerHunkIndex } from "../../core/review/anchors"; import type { ReviewHunkSpan } from "../../core/review/geometry"; diff --git a/src/ui/lib/agentNoteGeometry.ts b/src/ui/lib/agentNoteGeometry.ts index dbb1f3b88..ffcca08b3 100644 --- a/src/ui/lib/agentNoteGeometry.ts +++ b/src/ui/lib/agentNoteGeometry.ts @@ -6,7 +6,7 @@ // width their STML will actually be laid out at — all three must agree or // note heights and agent feedback drift from what the terminal shows. -import type { LayoutMode } from "../../core/types"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; import { resolveSplitPaneWidths } from "../diff/codeColumns"; export interface AgentNoteGeometryInput { diff --git a/src/ui/lib/appCommands.ts b/src/ui/lib/appCommands.ts index fc4ca52be..d86b3aeee 100644 --- a/src/ui/lib/appCommands.ts +++ b/src/ui/lib/appCommands.ts @@ -6,7 +6,7 @@ import { type VerticalCommandDirection, } from "../../core/invocation/commandCatalog"; import type { ReviewSelectionScope } from "../../core/review/navigation"; -import type { CursorLine, LayoutMode } from "../../core/types"; +import type { CursorLine, LayoutMode } from "../../core/invocation/commandInputs"; import type { ExtensionCommandExecutionOptions } from "../../extension-api/types"; import { matchesAnyKeyChord, diff --git a/src/ui/lib/appMenus.ts b/src/ui/lib/appMenus.ts index 0a9e5498e..4f636450c 100644 --- a/src/ui/lib/appMenus.ts +++ b/src/ui/lib/appMenus.ts @@ -1,4 +1,4 @@ -import type { CursorLine, LayoutMode } from "../../core/types"; +import type { CursorLine, LayoutMode } from "../../core/invocation/commandInputs"; import type { AppMenus, MenuEntry, MenuId } from "../components/chrome/menu"; import { executeAppCommand, isCommandEnabled, type AppCommand } from "./appCommands"; diff --git a/src/ui/lib/extensionDocumentReader.ts b/src/ui/lib/extensionDocumentReader.ts index 508432c44..cc2bab539 100644 --- a/src/ui/lib/extensionDocumentReader.ts +++ b/src/ui/lib/extensionDocumentReader.ts @@ -1,4 +1,4 @@ -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { ExtensionFileSide } from "../../extension-api/types"; /** Abort one caller's wait without cancelling the host's shared source read. */ diff --git a/src/ui/lib/extensionWorkspace.test.ts b/src/ui/lib/extensionWorkspace.test.ts index 1bc49f1e9..d2ebc6ec9 100644 --- a/src/ui/lib/extensionWorkspace.test.ts +++ b/src/ui/lib/extensionWorkspace.test.ts @@ -1,6 +1,6 @@ import { join, resolve, sep } from "node:path"; import { describe, expect, test } from "bun:test"; -import type { CliInput, CommonOptions } from "../../core/types"; +import type { CliInput, CommonOptions } from "../../core/invocation/commandInputs"; import { normalizeWorkspaceWriteRequest, resolveExtensionWorkspaceRead, diff --git a/src/ui/lib/extensionWorkspace.ts b/src/ui/lib/extensionWorkspace.ts index 0e7cb8e6b..aa7f455c9 100644 --- a/src/ui/lib/extensionWorkspace.ts +++ b/src/ui/lib/extensionWorkspace.ts @@ -21,7 +21,7 @@ import { isAbsolute, relative, resolve, sep } from "node:path"; import { normalizeDiffPath } from "../../core/changeset/diffPaths"; import type { FileSourceSide } from "../../core/changeset/fileSource"; import { canReloadInput } from "../../core/invocation/inputReload"; -import type { CliInput } from "../../core/types"; +import type { CliInput } from "../../core/invocation/commandInputs"; import { readMetadataChangeType } from "../../extensions/events"; /** diff --git a/src/ui/lib/fileHeader.ts b/src/ui/lib/fileHeader.ts index bde64defc..9f04b5e68 100644 --- a/src/ui/lib/fileHeader.ts +++ b/src/ui/lib/fileHeader.ts @@ -1,4 +1,4 @@ -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { fileLabelParts } from "./files"; import { fitText, measureTextWidth } from "./text"; diff --git a/src/ui/lib/fileRenderWindow.test.ts b/src/ui/lib/fileRenderWindow.test.ts index da0a9a167..edf18c5dd 100644 --- a/src/ui/lib/fileRenderWindow.test.ts +++ b/src/ui/lib/fileRenderWindow.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { buildFileSectionLayouts } from "./fileSectionLayout"; import { buildFileRenderWindow, type FileRenderWindowItem } from "./fileRenderWindow"; diff --git a/src/ui/lib/fileSectionLayout.ts b/src/ui/lib/fileSectionLayout.ts index 7d5979484..f248a534d 100644 --- a/src/ui/lib/fileSectionLayout.ts +++ b/src/ui/lib/fileSectionLayout.ts @@ -1,4 +1,4 @@ -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; /** Stream geometry for one file section in the main review pane. */ export interface FileSectionLayout { diff --git a/src/ui/lib/files.ts b/src/ui/lib/files.ts index ff2b64308..e6be07480 100644 --- a/src/ui/lib/files.ts +++ b/src/ui/lib/files.ts @@ -1,7 +1,8 @@ import { basename, dirname } from "node:path/posix"; import type { FileDiffMetadata } from "@pierre/diffs"; import { normalizeDiffPath } from "../../core/changeset/diffPaths"; -import type { AgentAnnotation, DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { AgentAnnotation } from "../../extension-api/types"; import { readMetadataChangeType } from "../../extensions/events"; import { formatTerminalPath } from "../../lib/terminalText"; diff --git a/src/ui/lib/keymap.ts b/src/ui/lib/keymap.ts index b0fbb2fdf..811b25cb1 100644 --- a/src/ui/lib/keymap.ts +++ b/src/ui/lib/keymap.ts @@ -1,4 +1,4 @@ -import type { UserKeyBinding } from "../../core/types"; +import type { UserKeyBinding } from "../../core/invocation/config"; import type { ExtensionPaneKeybindings } from "../../extension-api/types"; import { HUNK_VENDOR_EXTENSION_ID } from "../../extensions/extensionIds"; import { matchesKeyChord, parseKeyChord, type ParsedKeyChord } from "../../lib/commandKeys"; diff --git a/src/ui/lib/lineCursors.test.ts b/src/ui/lib/lineCursors.test.ts index 6a44b858e..66b5ccdb5 100644 --- a/src/ui/lib/lineCursors.test.ts +++ b/src/ui/lib/lineCursors.test.ts @@ -4,7 +4,8 @@ import { createTestHeaderOnlyDiffFile, lines, } from "../../../test/helpers/diff-helpers"; -import type { DiffFile, LayoutMode } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; import { reviewGapId } from "../../core/review/expansion"; import { measureDiffSectionGeometry } from "../diff/diffSectionGeometry"; import { resolveTheme } from "../themes"; diff --git a/src/ui/lib/lineCursors.ts b/src/ui/lib/lineCursors.ts index 9329dce0a..510c576c9 100644 --- a/src/ui/lib/lineCursors.ts +++ b/src/ui/lib/lineCursors.ts @@ -5,7 +5,8 @@ * active layout draws and carry the plan anchor rendering, reveal, and note placement already use. */ -import type { DiffFile, UserNoteLineTarget } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { UserNoteLineTarget } from "../../core/liveComments"; import type { DiffSectionGeometry, DiffSectionRowBounds } from "../diff/diffSectionGeometry"; import { contextLineStableKeySides, diff --git a/src/ui/lib/openInEditor.ts b/src/ui/lib/openInEditor.ts index 4b9f1ef29..21f0ed2dc 100644 --- a/src/ui/lib/openInEditor.ts +++ b/src/ui/lib/openInEditor.ts @@ -1,7 +1,7 @@ import { existsSync } from "node:fs"; import { basename, resolve, win32 } from "node:path"; import type { CliRenderer } from "@opentui/core"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { LineCursor } from "./lineCursors"; export interface EditorCommand { diff --git a/src/ui/lib/responsive.ts b/src/ui/lib/responsive.ts index 5422c70e6..8cbd1da61 100644 --- a/src/ui/lib/responsive.ts +++ b/src/ui/lib/responsive.ts @@ -1,4 +1,4 @@ -import type { LayoutMode } from "../../core/types"; +import type { LayoutMode } from "../../core/invocation/commandInputs"; export type ResponsiveViewport = "full" | "medium" | "tight"; diff --git a/src/ui/lib/reviewNoteMapping.ts b/src/ui/lib/reviewNoteMapping.ts index d64c313f5..2f762e0bd 100644 --- a/src/ui/lib/reviewNoteMapping.ts +++ b/src/ui/lib/reviewNoteMapping.ts @@ -21,7 +21,8 @@ import { type ReviewStoredNote, } from "../../core/review/state"; import type { ReviewNoteV1 } from "../../core/review/types"; -import type { AgentAnnotation, DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { AgentAnnotation } from "../../extension-api/types"; import { reviewNoteSource } from "./agentAnnotations"; /** One reviewer-authored note as the terminal review stream renders it. */ diff --git a/src/ui/lib/reviewState.ts b/src/ui/lib/reviewState.ts index 96a9c7790..5ab8129b9 100644 --- a/src/ui/lib/reviewState.ts +++ b/src/ui/lib/reviewState.ts @@ -16,7 +16,8 @@ import { reviewHunkRanges } from "../../core/review/geometry"; import { reviewFileMatchesFilter, selectNormalizedSelection } from "../../core/review/selectors"; import type { ReviewState } from "../../core/review/state"; import { noDiffFileMatchesMessage } from "../../session/agent/errors"; -import type { AgentAnnotation, DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; +import type { AgentAnnotation } from "../../extension-api/types"; import type { NavigateToHunkToolInput, SelectedHunkSummary } from "../../session/types"; import { mergeFileAnnotationsByFileId } from "./files"; diff --git a/src/ui/lib/stml/cli.ts b/src/ui/lib/stml/cli.ts index 54541e0ef..0a7374d9f 100644 --- a/src/ui/lib/stml/cli.ts +++ b/src/ui/lib/stml/cli.ts @@ -2,7 +2,7 @@ // main.tsx so the command behavior is directly testable. import { resolve as resolvePath } from "node:path"; -import type { MarkupRenderCommandInput } from "../../../core/types"; +import type { MarkupRenderCommandInput } from "../../../core/invocation/commandInputs"; import { resolveTheme } from "../../themes"; import { STML_GUIDE } from "./guide"; import { renderStmlToAnsi, renderStmlToText } from "./render"; diff --git a/src/ui/lib/ui-lib.test.ts b/src/ui/lib/ui-lib.test.ts index 6cb0b02f7..acca7ca2d 100644 --- a/src/ui/lib/ui-lib.test.ts +++ b/src/ui/lib/ui-lib.test.ts @@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test"; import { parseDiffFromFile } from "@pierre/diffs"; import type { KeyEvent } from "@opentui/core"; import stringWidth from "string-width"; -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import { buildMenuSpecs, menuBarTitleWidth, diff --git a/src/ui/lib/viewportAnchor.ts b/src/ui/lib/viewportAnchor.ts index 72875a219..4e39884cd 100644 --- a/src/ui/lib/viewportAnchor.ts +++ b/src/ui/lib/viewportAnchor.ts @@ -1,4 +1,4 @@ -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { DiffSectionGeometry, DiffSectionRowBounds } from "../diff/diffSectionGeometry"; import { buildFileSectionLayouts } from "./fileSectionLayout"; diff --git a/src/ui/lib/viewportSelection.ts b/src/ui/lib/viewportSelection.ts index 750abb1c8..ae790c639 100644 --- a/src/ui/lib/viewportSelection.ts +++ b/src/ui/lib/viewportSelection.ts @@ -1,4 +1,4 @@ -import type { DiffFile } from "../../core/types"; +import type { DiffFile } from "../../core/changeset/model"; import type { DiffSectionGeometry } from "../diff/diffSectionGeometry"; import { findFileSectionAtOffset, type FileSectionLayout } from "./fileSectionLayout"; diff --git a/src/ui/runInteractiveApp.tsx b/src/ui/runInteractiveApp.tsx index 48769d895..8656189c0 100644 --- a/src/ui/runInteractiveApp.tsx +++ b/src/ui/runInteractiveApp.tsx @@ -8,7 +8,7 @@ import { } from "../core/runtime/jobControl"; import { shutdownSession } from "../core/runtime/shutdown"; import { shouldUseMouseForApp, type ControllingTerminal } from "../core/runtime/terminal"; -import type { AppBootstrap } from "../core/types"; +import type { AppBootstrap } from "../core/bootstrap"; import { resolveStartupUpdateNotice } from "../core/runtime/updateNotice"; import { ReviewProducer } from "../app/review/producer"; import { diff --git a/src/ui/staticDiffPager.ts b/src/ui/staticDiffPager.ts index 6b0d99969..8450175a8 100644 --- a/src/ui/staticDiffPager.ts +++ b/src/ui/staticDiffPager.ts @@ -17,7 +17,9 @@ import { loadAppBootstrap } from "../core/changeset/loaders"; import { reviewEmptyDiffReason, type ReviewEmptyDiffReason } from "../core/review/document"; import { DEFAULT_TAB_WIDTH } from "../core/invocation/tabWidth"; -import type { CommonOptions, DiffFile, NamedCustomThemeConfig } from "../core/types"; +import type { DiffFile } from "../core/changeset/model"; +import type { CommonOptions } from "../core/invocation/commandInputs"; +import type { NamedCustomThemeConfig } from "../extension-api/types"; import { buildSplitRows, buildStackRows, diff --git a/src/ui/themes.ts b/src/ui/themes.ts index de1475c01..28df368ff 100644 --- a/src/ui/themes.ts +++ b/src/ui/themes.ts @@ -1,7 +1,7 @@ import type { ThemeMode } from "@opentui/core"; import { LEGACY_CUSTOM_THEME_ID } from "../core/theme/customThemes"; import { resolveSyntaxScopeOverrides } from "../core/theme/legacySyntaxScopes"; -import type { NamedCustomThemeConfig } from "../core/types"; +import type { NamedCustomThemeConfig } from "../extension-api/types"; import { blendHex, contrastRatio, relativeLuminance } from "./lib/color"; import { BUNDLED_SHIKI_THEME_IDS, diff --git a/test/helpers/app-bootstrap.ts b/test/helpers/app-bootstrap.ts index e5397280a..b602b264d 100644 --- a/test/helpers/app-bootstrap.ts +++ b/test/helpers/app-bootstrap.ts @@ -1,4 +1,6 @@ -import type { AppBootstrap, DiffFile, VcsDiffCommandInput, LayoutMode } from "../../src/core/types"; +import type { AppBootstrap } from "../../src/core/bootstrap"; +import type { DiffFile } from "../../src/core/changeset/model"; +import type { VcsDiffCommandInput, LayoutMode } from "../../src/core/invocation/commandInputs"; export function createTestVcsAppBootstrap({ agentSummary, diff --git a/test/helpers/diff-helpers.ts b/test/helpers/diff-helpers.ts index e8e8b2808..93b626de8 100644 --- a/test/helpers/diff-helpers.ts +++ b/test/helpers/diff-helpers.ts @@ -1,6 +1,7 @@ import { parseDiffFromFile } from "@pierre/diffs"; import type { FileSourceFetcher, FileSourceSide } from "../../src/core/changeset/fileSource"; -import type { AgentAnnotation, AgentFileContext, DiffFile } from "../../src/core/types"; +import type { DiffFile } from "../../src/core/changeset/model"; +import type { AgentAnnotation, AgentFileContext } from "../../src/extension-api/types"; function collectChangeStats(metadata: DiffFile["metadata"]) { let additions = 0; diff --git a/test/helpers/review-session-harness.ts b/test/helpers/review-session-harness.ts index af930cb70..61c2c8994 100644 --- a/test/helpers/review-session-harness.ts +++ b/test/helpers/review-session-harness.ts @@ -19,7 +19,8 @@ import { } from "../../src/app/session/registration"; import { HunkSessionBrokerState } from "../../src/session/broker/state"; import { ReviewResourceCache } from "../../src/session/broker/reviewResourceCache"; -import type { AppBootstrap, DiffFile } from "../../src/core/types"; +import type { AppBootstrap } from "../../src/core/bootstrap"; +import type { DiffFile } from "../../src/core/changeset/model"; import type { HunkSessionRegistration, HunkSessionServerMessage } from "../../src/session/types"; import { createTestDiffFile } from "./diff-helpers"; diff --git a/test/helpers/theme-helpers.ts b/test/helpers/theme-helpers.ts index d9f9c1289..c3d44104e 100644 --- a/test/helpers/theme-helpers.ts +++ b/test/helpers/theme-helpers.ts @@ -1,4 +1,4 @@ -import type { CustomThemeConfig, NamedCustomThemeConfig } from "../../src/core/types"; +import type { CustomThemeConfig, NamedCustomThemeConfig } from "../../src/extension-api/types"; /** * Name one custom palette so it can be passed to the theme APIs, which take the diff --git a/test/review-conformance/consumers/terminalRenderPlan.ts b/test/review-conformance/consumers/terminalRenderPlan.ts index 257c5c7ac..8d9247d13 100644 --- a/test/review-conformance/consumers/terminalRenderPlan.ts +++ b/test/review-conformance/consumers/terminalRenderPlan.ts @@ -9,7 +9,7 @@ */ import { resolveCommentTarget } from "../../../src/core/liveComments"; import { reviewGapId } from "../../../src/core/review/expansion"; -import type { DiffFile } from "../../../src/core/types"; +import type { DiffFile } from "../../../src/core/changeset/model"; import { buildDiffSectionRowPlan } from "../../../src/ui/diff/diffSectionRowPlan"; import { DIFF_MESSAGES, diffMessage } from "../../../src/ui/diff/renderRows"; import type { DiffRow } from "../../../src/ui/diff/diffRows"; diff --git a/test/review-conformance/geometryFixtures.ts b/test/review-conformance/geometryFixtures.ts index e90ed0013..bd0c21e32 100644 --- a/test/review-conformance/geometryFixtures.ts +++ b/test/review-conformance/geometryFixtures.ts @@ -7,7 +7,7 @@ * they are the inputs the deleted copies got wrong. */ import { createTestDiffFile, lines } from "../helpers/diff-helpers"; -import type { DiffFile } from "../../src/core/types"; +import type { DiffFile } from "../../src/core/changeset/model"; import type { ReviewGeometryFixture } from "./types"; /** Twelve numbered lines, the base every geometry fixture edits. */ diff --git a/test/review-conformance/navigationFixtures.ts b/test/review-conformance/navigationFixtures.ts index b1b417aa6..e84d242d5 100644 --- a/test/review-conformance/navigationFixtures.ts +++ b/test/review-conformance/navigationFixtures.ts @@ -8,7 +8,7 @@ * disagreed about, so a captured expectation would preserve the disagreement. */ import { createTestDiffFile, lines } from "../helpers/diff-helpers"; -import type { DiffFile } from "../../src/core/types"; +import type { DiffFile } from "../../src/core/changeset/model"; import type { ReviewNavigationFixture } from "./types"; /** Twelve numbered lines, the base every navigation fixture edits. */ diff --git a/test/review-conformance/types.ts b/test/review-conformance/types.ts index 7a7e97cc1..77ed4b26f 100644 --- a/test/review-conformance/types.ts +++ b/test/review-conformance/types.ts @@ -24,7 +24,7 @@ import type { ReviewIntent } from "../../src/core/review/intents"; import type { ReviewSelectionScope } from "../../src/core/review/navigation"; import type { ReviewNoteV1 } from "../../src/core/review/types"; import type { HunkReviewPublicationBodyV1 } from "../../src/session/reviewHttpProtocol"; -import type { DiffFile } from "../../src/core/types"; +import type { DiffFile } from "../../src/core/changeset/model"; export interface ConformanceGap { gapId: string; From 084f785e7046ad43d3ebd334d85a3a31dea1c623 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 11:36:58 +0000 Subject: [PATCH 6/8] refactor(core): rename invocation/ to run/ and runtime/ to process/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pair now tells one story in the repo's own vocabulary: core/run/ is what a Hunk run was asked to be (inputs, config, catalog, invocation errors), and core/process/ is the OS process and terminal it executes in (terminal, pager, job control, shutdown, notices). "invocation" was formal, and "runtime" one letter from colliding with "run"; renaming both keeps the distinction memorable. Directory rename only — no file or symbol renamed, boundary rules repointed. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XcuayyxJrwQd9EHpuxNef1 --- .dependency-cruiser.cjs | 2 +- docs/browser-review-seam-audit.md | 2 +- docs/changelog-on-hunk-dev.md | 2 +- docs/extension-architecture.md | 2 +- docs/extension-system-exploration.md | 2 +- docs/module-boundaries.md | 12 ++++++------ docs/source-architecture.md | 4 ++-- scripts/build-prebuilt-artifact.test.ts | 2 +- scripts/build-prebuilt-artifact.ts | 2 +- scripts/generate-docs.test.ts | 2 +- scripts/generate-docs.ts | 4 ++-- src/app/cli.test.ts | 2 +- src/app/cli.ts | 8 ++++---- src/app/extensionBootstrap.test.ts | 4 ++-- src/app/extensionBootstrap.ts | 6 +++--- src/app/session/registration.ts | 2 +- src/app/session/reloadBounds.test.ts | 2 +- src/app/session/reloadBounds.ts | 6 +++--- src/app/sessionBootstrap.test.ts | 4 ++-- src/app/sessionBootstrap.ts | 4 ++-- src/app/sessionSelector.ts | 4 ++-- src/app/startup.test.ts | 6 +++--- src/app/startup.ts | 12 ++++++------ src/app/startup.vcsExtensions.test.ts | 4 ++-- src/core/bootstrap.ts | 11 +++-------- src/core/changeset/loaders.test.ts | 2 +- src/core/changeset/loaders.ts | 4 ++-- src/core/{runtime => process}/appStateFile.test.ts | 0 src/core/{runtime => process}/appStateFile.ts | 0 src/core/{runtime => process}/jobControl.test.ts | 0 src/core/{runtime => process}/jobControl.ts | 0 src/core/{runtime => process}/pager.test.ts | 0 src/core/{runtime => process}/pager.ts | 0 src/core/{runtime => process}/projectRoot.test.ts | 0 src/core/{runtime => process}/projectRoot.ts | 0 src/core/{runtime => process}/shutdown.test.ts | 0 src/core/{runtime => process}/shutdown.ts | 0 src/core/{runtime => process}/startupNotice.ts | 0 src/core/{runtime => process}/terminal.test.ts | 2 +- src/core/{runtime => process}/terminal.ts | 2 +- src/core/{runtime => process}/updateNotice.test.ts | 0 src/core/{runtime => process}/updateNotice.ts | 4 ++-- src/core/review/types.ts | 2 +- src/core/{invocation => run}/commandCatalog.test.ts | 0 src/core/{invocation => run}/commandCatalog.ts | 0 src/core/{invocation => run}/commandInputs.ts | 0 src/core/{invocation => run}/config.test.ts | 2 +- src/core/{invocation => run}/config.ts | 4 ++-- src/core/{invocation => run}/errors.test.ts | 0 src/core/{invocation => run}/errors.ts | 0 src/core/{invocation => run}/experimental.test.ts | 0 src/core/{invocation => run}/experimental.ts | 0 src/core/{invocation => run}/inputReload.ts | 0 src/core/{invocation => run}/paths.test.ts | 0 src/core/{invocation => run}/paths.ts | 0 src/core/{invocation => run}/tabWidth.ts | 0 src/core/{invocation => run}/version.ts | 0 src/core/theme/customThemes.ts | 2 +- src/core/vcs/index.test.ts | 2 +- src/core/vcs/index.ts | 4 ++-- src/core/vcs/types.ts | 2 +- src/core/watch/plan.test.ts | 2 +- src/core/watch/plan.ts | 2 +- src/core/watch/signature.test.ts | 2 +- src/core/watch/signature.ts | 2 +- src/extensions/apply.ts | 2 +- src/extensions/discovery.ts | 7 ++----- src/extensions/host.ts | 2 +- src/extensions/manage/cli.ts | 6 +++--- src/extensions/manage/install.ts | 2 +- src/extensions/manage/records.ts | 2 +- src/extensions/runExtension.ts | 2 +- src/extensions/startup.test.ts | 2 +- src/extensions/startup.ts | 4 ++-- src/extensions/trust.test.ts | 2 +- src/extensions/trust.ts | 4 ++-- src/extensions/vcsPatchResult.test.ts | 2 +- src/main.tsx | 4 ++-- src/opentui/HunkDiffBody.tsx | 2 +- src/session/agent/cliClient.test.ts | 2 +- src/session/agent/cliClient.ts | 2 +- src/session/agent/commands.daemon.test.ts | 2 +- src/session/agent/commands.test.ts | 5 +---- src/session/agent/commands.ts | 2 +- src/session/broker/wire.ts | 7 ++----- src/session/client/daemonHttp.ts | 2 +- src/session/protocol.ts | 2 +- src/session/protocolSchemas.ts | 2 +- src/session/types.ts | 4 ++-- src/ui/App.tsx | 13 +++++-------- src/ui/AppHost.cursor-line.test.tsx | 2 +- src/ui/AppHost.extension-dialogs.test.tsx | 2 +- src/ui/AppHost.extensions.test.tsx | 2 +- src/ui/AppHost.interactions.test.tsx | 4 ++-- src/ui/AppHost.keybindings.test.tsx | 2 +- src/ui/AppHost.responsive.test.tsx | 2 +- src/ui/AppHost.sidebar-visibility.test.tsx | 2 +- src/ui/AppHost.tsx | 8 ++++---- src/ui/AppHost.workspace.test.tsx | 2 +- src/ui/components/panes/AgentInlineNote.tsx | 2 +- src/ui/components/panes/DiffPane.tsx | 4 ++-- src/ui/components/panes/DiffSection.tsx | 2 +- src/ui/components/panes/copySelection.ts | 2 +- src/ui/diff/DiffSectionBody.tsx | 4 ++-- src/ui/diff/codeColumns.ts | 4 ++-- src/ui/diff/diffRows.ts | 2 +- src/ui/diff/diffSectionGeometry.ts | 4 ++-- src/ui/diff/diffSectionRowPlan.ts | 4 ++-- src/ui/diff/expandCollapsedRows.ts | 2 +- src/ui/diff/lineHighlightPaint.test.ts | 2 +- src/ui/diff/lineHighlightPaint.ts | 2 +- src/ui/diff/renderRows.tsx | 2 +- src/ui/diff/reviewRowGeometry.ts | 2 +- src/ui/hooks/useHunkSessionBridge.ts | 2 +- src/ui/hooks/useStartupNotices.ts | 2 +- src/ui/hooks/useTerminalReview.test.tsx | 2 +- src/ui/hooks/useTerminalReview.ts | 4 ++-- src/ui/hooks/useWatchedInput.ts | 2 +- src/ui/lib/agentAnnotations.ts | 2 +- src/ui/lib/agentNoteGeometry.ts | 2 +- src/ui/lib/appCommands.test.ts | 2 +- src/ui/lib/appCommands.ts | 4 ++-- src/ui/lib/appMenus.ts | 2 +- src/ui/lib/extensionWorkspace.test.ts | 2 +- src/ui/lib/extensionWorkspace.ts | 4 ++-- src/ui/lib/keymap.ts | 2 +- src/ui/lib/lineCursors.test.ts | 2 +- src/ui/lib/responsive.ts | 2 +- src/ui/lib/stml/cli.ts | 2 +- src/ui/runInteractiveApp.tsx | 8 ++++---- src/ui/staticDiffPager.ts | 4 ++-- test/helpers/app-bootstrap.ts | 2 +- website/src/content/docs/docs/reference/config.md | 2 +- 133 files changed, 169 insertions(+), 186 deletions(-) rename src/core/{runtime => process}/appStateFile.test.ts (100%) rename src/core/{runtime => process}/appStateFile.ts (100%) rename src/core/{runtime => process}/jobControl.test.ts (100%) rename src/core/{runtime => process}/jobControl.ts (100%) rename src/core/{runtime => process}/pager.test.ts (100%) rename src/core/{runtime => process}/pager.ts (100%) rename src/core/{runtime => process}/projectRoot.test.ts (100%) rename src/core/{runtime => process}/projectRoot.ts (100%) rename src/core/{runtime => process}/shutdown.test.ts (100%) rename src/core/{runtime => process}/shutdown.ts (100%) rename src/core/{runtime => process}/startupNotice.ts (100%) rename src/core/{runtime => process}/terminal.test.ts (98%) rename src/core/{runtime => process}/terminal.ts (97%) rename src/core/{runtime => process}/updateNotice.test.ts (100%) rename src/core/{runtime => process}/updateNotice.ts (98%) rename src/core/{invocation => run}/commandCatalog.test.ts (100%) rename src/core/{invocation => run}/commandCatalog.ts (100%) rename src/core/{invocation => run}/commandInputs.ts (100%) rename src/core/{invocation => run}/config.test.ts (99%) rename src/core/{invocation => run}/config.ts (99%) rename src/core/{invocation => run}/errors.test.ts (100%) rename src/core/{invocation => run}/errors.ts (100%) rename src/core/{invocation => run}/experimental.test.ts (100%) rename src/core/{invocation => run}/experimental.ts (100%) rename src/core/{invocation => run}/inputReload.ts (100%) rename src/core/{invocation => run}/paths.test.ts (100%) rename src/core/{invocation => run}/paths.ts (100%) rename src/core/{invocation => run}/tabWidth.ts (100%) rename src/core/{invocation => run}/version.ts (100%) diff --git a/.dependency-cruiser.cjs b/.dependency-cruiser.cjs index 249581c8a..9d12579a0 100644 --- a/.dependency-cruiser.cjs +++ b/.dependency-cruiser.cjs @@ -137,7 +137,7 @@ module.exports = { "core/bootstrap.ts composes the leaves: it names the changeset, the parsed input, the resolved preferences, and the detected theme mode to describe one launch. A module directory importing it back would invert that layering and rebuild the grab-bag cycle the 2026-08 phases dismantled. core/changeset/loaders.ts is the single exception — loadAppBootstrap assembles the value, so it names the shape it returns; its natural home is the app tier, and moving it there retires this exception.", severity: "error", from: { - path: "^src/core/(changeset|invocation|runtime|review|vcs|watch|patch|theme)/", + path: "^src/core/(changeset|run|process|review|vcs|watch|patch|theme)/", pathNot: "^src/core/changeset/loaders\\.ts$", }, to: { path: "^src/core/bootstrap\\.ts$" }, diff --git a/docs/browser-review-seam-audit.md b/docs/browser-review-seam-audit.md index 3a8c100de..ba63fdd05 100644 --- a/docs/browser-review-seam-audit.md +++ b/docs/browser-review-seam-audit.md @@ -515,7 +515,7 @@ here so the extraction happens before the duplication exists. Design detail in Fix: extract a renderer-neutral catalog (id, title, category, default chords, resolution locus — semantic / client-local / host-only); terminal keeps matchers and handlers, browser adds its own, both render menus/help/palette from the catalog. - _Repaid (Phase 1 PR 3)_: `src/core/invocation/commandCatalog.ts` carries id, title, category, default + _Repaid (Phase 1 PR 3)_: `src/core/run/commandCatalog.ts` carries id, title, category, default chords, resolution locus, extension visibility, and menu-closing behavior for all 44 built-ins. `ui/lib/appCommands.ts` builds its dispatch table from it — the handler map is keyed by `AppCommandId`, so a catalogued command with no terminal handler fails to typecheck — and diff --git a/docs/changelog-on-hunk-dev.md b/docs/changelog-on-hunk-dev.md index ab8a19ad6..82b464d27 100644 --- a/docs/changelog-on-hunk-dev.md +++ b/docs/changelog-on-hunk-dev.md @@ -106,6 +106,6 @@ path list, or release commits will not trigger a deploy. launch-video pipeline keeps generated media out of Git. - **Contributor lists.** The GitHub release bodies name first-time contributors, which is community goodwill and organic links. `CHANGELOG.md` does not carry authors, so this needs a second input. -- **The in-app update notice.** `src/core/runtime/updateNotice.ts` tells users a new version exists without +- **The in-app update notice.** `src/core/process/updateNotice.ts` tells users a new version exists without linking what changed. Appending `hunk.dev/changelog/` is the highest-intent entry point available and is deliberately left as a separate change. diff --git a/docs/extension-architecture.md b/docs/extension-architecture.md index 6cf0c38f1..e7f6c778c 100644 --- a/docs/extension-architecture.md +++ b/docs/extension-architecture.md @@ -300,7 +300,7 @@ and exact-source reading — live entirely under `src/extensions/default/vcs//`. `src/extensions/vcsPatchResult.ts` is the one conversion boundary where a published `ExtensionVcsPatchResult` becomes Hunk's internal diff model, including structural `too-large` source -results. `src/core/runtime/projectRoot.ts` treats `.hunk` as a provider-independent +results. `src/core/process/projectRoot.ts` treats `.hunk` as a provider-independent bootstrap marker and also consults the available catalog; startup performs a second root/config pass when a global, config-path, or CLI adapter recognizes a repository unavailable to the bundled catalog. diff --git a/docs/extension-system-exploration.md b/docs/extension-system-exploration.md index 02f9dcba9..f660f5b18 100644 --- a/docs/extension-system-exploration.md +++ b/docs/extension-system-exploration.md @@ -171,7 +171,7 @@ export default function (hunk: HunkExtensionAPI) { ```` - Discovery: `~/.config/hunk/extensions/*.ts` and `*/index.ts` (global, follows - our existing XDG path logic in `src/core/invocation/paths.ts`), `.hunk/extensions/` + our existing XDG path logic in `src/core/run/paths.ts`), `.hunk/extensions/` (repo-local, **trust-gated**, same posture as pi's project trust), explicit `[extensions] paths = [...]` in `config.toml`, and a `--extension ` dev flag. `--no-extensions` for a clean run and for bug triage. diff --git a/docs/module-boundaries.md b/docs/module-boundaries.md index 3600449e4..fe871880c 100644 --- a/docs/module-boundaries.md +++ b/docs/module-boundaries.md @@ -90,7 +90,7 @@ sidecar shapes for legacy import sites (since phase 4: those sites name `changes directly); it names `changeset/model`, which is public, so the interior rule needs no exception. `core/patch/` stayed where it is: it was already coherent. -Phase 2 (2026-08-17) grouped **how a run is asked for** into `core/invocation/`: the command +Phase 2 (2026-08-17) grouped **how a run is asked for** into `core/run/`: the command inputs (`commandInputs`), the layered config resolver (`config`), the app command catalog (`commandCatalog`), the invocation errors (`errors` — "a failure Hunk raises because of how it was invoked"), launch-scoped experimental features (`experimental`), XDG/app paths (`paths`), @@ -100,7 +100,7 @@ tab-width validation (`tabWidth`), reload eligibility (`inputReload`), and the C Every one of the nine is **public**: each has production importers outside the module, so this phase adds no `invocation-internals-stay-in-module` rule. Its value is the grouping plus extending the freeze: `core-leaves-never-reimport-types` now names -`core/invocation/commandInputs.ts` in place of the old root path. Only `commandInputs` is a +`core/run/commandInputs.ts` in place of the old root path. Only `commandInputs` is a types-leaf — `config`, `experimental`, and `inputReload` import `core/types` legally, since `core/types` re-exports from `commandInputs` and never the other way round. (Since phase 4 there is no shell to import: those three name `commandInputs` directly, and `config` declares @@ -116,7 +116,7 @@ those inputs name them and the leaf may not import `core/types` back: all of them, so no import site changed at the time; phase 4 moved the import sites onto `commandInputs` and deleted the re-exports. -Phase 3 (2026-08-17) grouped **the process and terminal a run lives in** into `core/runtime/`: +Phase 3 (2026-08-17) grouped **the process and terminal a run lives in** into `core/process/`: TTY capability detection and runtime CLI-input resolution (`terminal`), the external pager and its plain-text fallback (`pager`), SIGTSTP/SIGINT job control (`jobControl`), ordered session teardown (`shutdown`), `.hunk`/VCS project-root discovery (`projectRoot`), the atomically @@ -149,7 +149,7 @@ module that owns their behaviour, one home each: - `TerminalThemeMode` → `core/theme/detection.ts`, which probes the terminal for it and had been re-exporting the name from the shell. -- `ExtensionsConfig`, `UserKeyBinding`, `PersistedViewPreferences` → `core/invocation/config.ts`, +- `ExtensionsConfig`, `UserKeyBinding`, `PersistedViewPreferences` → `core/run/config.ts`, which resolves `[extensions]`, `[keybindings]`, and the persisted view options. - `UserNoteLineTarget` → `core/liveComments.ts`, beside `DiffSide` and `CommentTargetInput`: it is the line a user note hangs on, and every consumer reaches it through note code. @@ -188,7 +188,7 @@ rules: - **Cycles.** Each cycle was a type-only back-edge from a lower module into a grab-bag above it. The cuts: `core/types.ts` gave its changeset model to `core/changeset.ts` (since phase 1, `core/changeset/model.ts`) and its command-input model to `core/commandInputs.ts` (since phase - 2, `core/invocation/commandInputs.ts`; re-exported from `core/types` so import sites kept + 2, `core/run/commandInputs.ts`; re-exported from `core/types` so import sites kept working, until phase 4 melted that shell into `core/bootstrap.ts` and moved the sites onto the declaring modules); the diff row model moved to `ui/diff/diffRowModel.ts`; the worker's @@ -228,7 +228,7 @@ The tier rules now hold with no exceptions. Two follow-ups are worth doing next: because every file in them has an outside importer today. Two named follow-ups: move `loadAppBootstrap` out of `core/changeset/loaders.ts` into `src/app` (it is composition, and it is the one exception `core-leaves-stay-below-bootstrap` has to carve out), and split - `core/invocation/config.ts`, whose readers reach it for three unrelated reasons — the + `core/run/config.ts`, whose readers reach it for three unrelated reasons — the resolved `HunkConfigResolution`, the persisted view preferences, and the extension/keybinding tables. The review seam's named modules (`document`, `geometry`, `state`, …) stay public; their helpers become internal. diff --git a/docs/source-architecture.md b/docs/source-architecture.md index ede6100c0..20cbc37ea 100644 --- a/docs/source-architecture.md +++ b/docs/source-architecture.md @@ -13,9 +13,9 @@ src/core/ review model, patch handling, VCS contracts, configuration, runtime primitives src/core/changeset/ the changeset model and the pipeline that acquires one: loaders, per-file construction, sidecar/source reads, and hunk formatting -src/core/invocation/ how a run is asked for: command inputs, layered configuration, the +src/core/run/ how a run is asked for: command inputs, layered configuration, the command catalog, user-facing errors, paths, and version -src/core/runtime/ the process and terminal a run lives in: TTY capabilities, the pager, +src/core/process/ the process and terminal a run lives in: TTY capabilities, the pager, job control, shutdown, project-root discovery, persisted app state, and startup/update notices src/core/theme/ bundled theme metadata, custom-theme rules, and terminal theme detection diff --git a/scripts/build-prebuilt-artifact.test.ts b/scripts/build-prebuilt-artifact.test.ts index c23a7f4b5..847c61b4f 100644 --- a/scripts/build-prebuilt-artifact.test.ts +++ b/scripts/build-prebuilt-artifact.test.ts @@ -2,7 +2,7 @@ import { existsSync, mkdtempSync, mkdirSync, rmSync, statSync, writeFileSync } f import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, test } from "bun:test"; -import { BUNDLED_SKILL_NAMES } from "../src/core/invocation/paths"; +import { BUNDLED_SKILL_NAMES } from "../src/core/run/paths"; import { stagePrebuiltArtifact } from "./build-prebuilt-artifact"; import { binaryFilenameForSpec, getHostPlatformPackageSpec } from "./prebuilt-package-helpers"; diff --git a/scripts/build-prebuilt-artifact.ts b/scripts/build-prebuilt-artifact.ts index 39638f45f..c5a109831 100644 --- a/scripts/build-prebuilt-artifact.ts +++ b/scripts/build-prebuilt-artifact.ts @@ -2,7 +2,7 @@ import { chmodSync, cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; import path from "node:path"; -import { BUNDLED_SKILL_NAMES } from "../src/core/invocation/paths"; +import { BUNDLED_SKILL_NAMES } from "../src/core/run/paths"; import { binaryFilenameForSpec, getHostPlatformPackageSpec, diff --git a/scripts/generate-docs.test.ts b/scripts/generate-docs.test.ts index 1aa75ca74..2a0c0793a 100644 --- a/scripts/generate-docs.test.ts +++ b/scripts/generate-docs.test.ts @@ -2,7 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; -import { CONFIG_REFERENCE_OPTIONS } from "../src/core/invocation/config"; +import { CONFIG_REFERENCE_OPTIONS } from "../src/core/run/config"; import { renderHunkReviewSkill } from "../src/hunk-review/skillDocument"; import { SESSION_AGENT_COMMAND_LIST } from "../src/session/agent/surface"; import { diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts index 76604dc88..8832d4ae8 100644 --- a/scripts/generate-docs.ts +++ b/scripts/generate-docs.ts @@ -13,7 +13,7 @@ import { CONFIG_REFERENCE_CUSTOM_THEME, CONFIG_REFERENCE_EXTENSIONS, CONFIG_REFERENCE_OPTIONS, -} from "../src/core/invocation/config"; +} from "../src/core/run/config"; import { renderHunkReviewSkill } from "../src/hunk-review/skillDocument"; import { type AgentCommandOption, SESSION_AGENT_COMMAND_LIST } from "../src/session/agent/surface"; import { @@ -276,7 +276,7 @@ description: Exhaustive generated reference for Hunk TOML keys, defaults, aliase ${GENERATED_NOTICE} -Hunk reads TOML preferences from the user config and an optional repository config. This reference is generated from the same catalog that \`src/core/invocation/config.ts\` uses to parse preference keys. +Hunk reads TOML preferences from the user config and an optional repository config. This reference is generated from the same catalog that \`src/core/run/config.ts\` uses to parse preference keys. ## Resolution and scope diff --git a/src/app/cli.test.ts b/src/app/cli.test.ts index b0eaf3fbc..c3f3dcf53 100644 --- a/src/app/cli.test.ts +++ b/src/app/cli.test.ts @@ -9,7 +9,7 @@ import { parseCli, WATCH_OPTION, } from "./cli"; -import { resolveCliVersion } from "../core/invocation/version"; +import { resolveCliVersion } from "../core/run/version"; const tempDirs: string[] = []; diff --git a/src/app/cli.ts b/src/app/cli.ts index 837f46416..43b6a8252 100644 --- a/src/app/cli.ts +++ b/src/app/cli.ts @@ -12,13 +12,13 @@ import type { ParsedCliInput, SessionCommentListType, SessionCommentApplyItemInput, -} from "../core/invocation/commandInputs"; +} from "../core/run/commandInputs"; import { BUNDLED_SKILL_NAMES, resolveBundledSkillName, resolveBundledSkillPath, type BundledSkillName, -} from "../core/invocation/paths"; +} from "../core/run/paths"; import { type AgentCommandConstraint, type AgentCommandSpec, @@ -42,8 +42,8 @@ import { HIGHLIGHT_RANGE_MESSAGE, RELOAD_SEPARATOR_MESSAGE, } from "../session/agent/errors"; -import { DEFAULT_TAB_WIDTH, parseTabWidth } from "../core/invocation/tabWidth"; -import { resolveCliVersion } from "../core/invocation/version"; +import { DEFAULT_TAB_WIDTH, parseTabWidth } from "../core/run/tabWidth"; +import { resolveCliVersion } from "../core/run/version"; /** Structured option metadata shared by Commander registration and generated CLI docs. */ export interface CliReferenceOption { diff --git a/src/app/extensionBootstrap.test.ts b/src/app/extensionBootstrap.test.ts index 36a6d3bc5..692d87fa7 100644 --- a/src/app/extensionBootstrap.test.ts +++ b/src/app/extensionBootstrap.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; -import type { HunkConfigResolution } from "../core/invocation/config"; -import type { CliInput } from "../core/invocation/commandInputs"; +import type { HunkConfigResolution } from "../core/run/config"; +import type { CliInput } from "../core/run/commandInputs"; import { createEmptyExtensionLoadResult } from "../extensions/types"; import { resolveConfiguredExtensions } from "./extensionBootstrap"; import { getBundledVcsCatalog } from "./vcsCatalog"; diff --git a/src/app/extensionBootstrap.ts b/src/app/extensionBootstrap.ts index ae4c37e5d..1a10fc502 100644 --- a/src/app/extensionBootstrap.ts +++ b/src/app/extensionBootstrap.ts @@ -1,6 +1,6 @@ -import { resolveConfiguredCliInput, type HunkConfigResolution } from "../core/invocation/config"; -import { findProjectRootCandidate } from "../core/runtime/projectRoot"; -import type { CliInput } from "../core/invocation/commandInputs"; +import { resolveConfiguredCliInput, type HunkConfigResolution } from "../core/run/config"; +import { findProjectRootCandidate } from "../core/process/projectRoot"; +import type { CliInput } from "../core/run/commandInputs"; import { extendVcsCatalog } from "../core/vcs"; import type { VcsCatalog } from "../core/vcs/types"; import { resolveExtensionVcsAdapters } from "../extensions/apply"; diff --git a/src/app/session/registration.ts b/src/app/session/registration.ts index 6327ee21a..1460d69a8 100644 --- a/src/app/session/registration.ts +++ b/src/app/session/registration.ts @@ -1,6 +1,6 @@ import { randomUUID } from "node:crypto"; import { spawnSync } from "node:child_process"; -import { resolveExperimentalFeatures } from "../../core/invocation/experimental"; +import { resolveExperimentalFeatures } from "../../core/run/experimental"; import { isVcsReviewInput } from "../../core/vcs"; import { summarizeHunk } from "../../core/changeset/hunkSummary"; import { reviewHunkRanges } from "../../core/review/geometry"; diff --git a/src/app/session/reloadBounds.test.ts b/src/app/session/reloadBounds.test.ts index 8329b7546..d3caa2ec7 100644 --- a/src/app/session/reloadBounds.test.ts +++ b/src/app/session/reloadBounds.test.ts @@ -4,7 +4,7 @@ import { join, resolve } from "node:path"; import { describe, expect, test } from "bun:test"; import { getBundledVcsCatalog } from "../vcsCatalog"; import type { AppBootstrap } from "../../core/bootstrap"; -import type { CliInput } from "../../core/invocation/commandInputs"; +import type { CliInput } from "../../core/run/commandInputs"; import { createSessionReloadBounds, validateSessionReloadWithinBounds } from "./reloadBounds"; /** Resolve expected paths the same way production bounds do, including Windows long names. */ diff --git a/src/app/session/reloadBounds.ts b/src/app/session/reloadBounds.ts index 587ffa96f..73ed4dc52 100644 --- a/src/app/session/reloadBounds.ts +++ b/src/app/session/reloadBounds.ts @@ -1,8 +1,8 @@ import { isAbsolute, relative, resolve } from "node:path"; -import { resolveCanonicalPath } from "../../core/invocation/paths"; -import { findProjectRootCandidate } from "../../core/runtime/projectRoot"; +import { resolveCanonicalPath } from "../../core/run/paths"; +import { findProjectRootCandidate } from "../../core/process/projectRoot"; import type { AppBootstrap } from "../../core/bootstrap"; -import type { CliInput, CommonOptions } from "../../core/invocation/commandInputs"; +import type { CliInput, CommonOptions } from "../../core/run/commandInputs"; import type { VcsCatalog } from "../../core/vcs/types"; /** diff --git a/src/app/sessionBootstrap.test.ts b/src/app/sessionBootstrap.test.ts index 8651ef32e..06035ce98 100644 --- a/src/app/sessionBootstrap.test.ts +++ b/src/app/sessionBootstrap.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; -import type { HunkConfigResolution } from "../core/invocation/config"; +import type { HunkConfigResolution } from "../core/run/config"; import type { AppBootstrap } from "../core/bootstrap"; -import type { CliInput } from "../core/invocation/commandInputs"; +import type { CliInput } from "../core/run/commandInputs"; import { createEmptyExtensionLoadResult } from "../extensions/types"; import { loadConfiguredSessionBootstrap } from "./sessionBootstrap"; diff --git a/src/app/sessionBootstrap.ts b/src/app/sessionBootstrap.ts index 15ceaf620..2c998dbed 100644 --- a/src/app/sessionBootstrap.ts +++ b/src/app/sessionBootstrap.ts @@ -1,10 +1,10 @@ -import type { HunkConfigResolution } from "../core/invocation/config"; +import type { HunkConfigResolution } from "../core/run/config"; import { isVcsReviewInput } from "../core/vcs"; import type { VcsCatalog } from "../core/vcs/types"; import { getBundledVcsCatalog } from "./vcsCatalog"; import { collectSessionCustomThemes } from "../core/theme/customThemes"; import { loadAppBootstrap } from "../core/changeset/loaders"; -import type { CliInput } from "../core/invocation/commandInputs"; +import type { CliInput } from "../core/run/commandInputs"; import type { AppBootstrap } from "./types"; import { applyExtensionChangesetTransforms, diff --git a/src/app/sessionSelector.ts b/src/app/sessionSelector.ts index e2d9cf5b4..9d660d7f0 100644 --- a/src/app/sessionSelector.ts +++ b/src/app/sessionSelector.ts @@ -1,5 +1,5 @@ -import { findProjectRootCandidate } from "../core/runtime/projectRoot"; -import type { SessionSelectorInput } from "../core/invocation/commandInputs"; +import { findProjectRootCandidate } from "../core/process/projectRoot"; +import type { SessionSelectorInput } from "../core/run/commandInputs"; import type { VcsCatalog } from "../core/vcs/types"; /** Attach the nearest known project boundary to one repo-path session selector. */ diff --git a/src/app/startup.test.ts b/src/app/startup.test.ts index 73a8bc0f6..608499117 100644 --- a/src/app/startup.test.ts +++ b/src/app/startup.test.ts @@ -1,10 +1,10 @@ import { describe, expect, test } from "bun:test"; import { createEmptyExtensionLoadResult } from "../extensions/types"; -import type { HunkConfigResolution } from "../core/invocation/config"; -import { HunkUserError } from "../core/invocation/errors"; +import type { HunkConfigResolution } from "../core/run/config"; +import { HunkUserError } from "../core/run/errors"; import { prepareStartupPlan } from "./startup"; import type { AppBootstrap } from "../core/bootstrap"; -import type { CliInput, ParsedCliInput } from "../core/invocation/commandInputs"; +import type { CliInput, ParsedCliInput } from "../core/run/commandInputs"; import type { NamedCustomThemeConfig } from "../extension-api/types"; /** diff --git a/src/app/startup.ts b/src/app/startup.ts index 4e813bbea..3303bb45d 100644 --- a/src/app/startup.ts +++ b/src/app/startup.ts @@ -1,17 +1,17 @@ import type { SessionBootstrapResult } from "./sessionBootstrap"; import { createExtensionApplyNotices, createUnknownVcsNotice } from "../extensions/apply"; import type { loadStartupExtensions } from "../extensions/startup"; -import { resolveConfiguredCliInput } from "../core/invocation/config"; -import { HunkUserError } from "../core/invocation/errors"; +import { resolveConfiguredCliInput } from "../core/run/config"; +import { HunkUserError } from "../core/run/errors"; import type { loadAppBootstrap } from "../core/changeset/loaders"; -import { looksLikePatchInput } from "../core/runtime/pager"; +import { looksLikePatchInput } from "../core/process/pager"; import { detectTerminalThemeModeFromBackground } from "../core/theme/detection"; import { openControllingTerminal, resolveRuntimeCliInput, usesPipedPatchInput, type ControllingTerminal, -} from "../core/runtime/terminal"; +} from "../core/process/terminal"; import type { AppBootstrap } from "./types"; import type { CliInput, @@ -19,8 +19,8 @@ import type { MarkupRenderCommandInput, ParsedCliInput, SessionCommandInput, -} from "../core/invocation/commandInputs"; -import { canReloadInput } from "../core/invocation/inputReload"; +} from "../core/run/commandInputs"; +import { canReloadInput } from "../core/run/inputReload"; import { parseCli } from "./cli"; import { resolveSessionSelectorBoundary } from "./sessionSelector"; import type { VcsCatalog } from "../core/vcs/types"; diff --git a/src/app/startup.vcsExtensions.test.ts b/src/app/startup.vcsExtensions.test.ts index cc265ddfc..099b2e0d1 100644 --- a/src/app/startup.vcsExtensions.test.ts +++ b/src/app/startup.vcsExtensions.test.ts @@ -3,8 +3,8 @@ import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSy import { tmpdir } from "node:os"; import { join } from "node:path"; import { prepareStartupPlan } from "./startup"; -import { resolveConfiguredCliInput } from "../core/invocation/config"; -import type { CliInput, ParsedCliInput } from "../core/invocation/commandInputs"; +import { resolveConfiguredCliInput } from "../core/run/config"; +import type { CliInput, ParsedCliInput } from "../core/run/commandInputs"; const tempDirs: string[] = []; const initialCwd = process.cwd(); diff --git a/src/core/bootstrap.ts b/src/core/bootstrap.ts index a8c04dee7..bb54be443 100644 --- a/src/core/bootstrap.ts +++ b/src/core/bootstrap.ts @@ -13,14 +13,9 @@ */ import type { NamedCustomThemeConfig } from "../extension-api/types"; import type { Changeset } from "./changeset/model"; -import type { - CliInput, - CursorLine, - LayoutMode, - SidebarVisibility, -} from "./invocation/commandInputs"; -import type { UserKeyBinding } from "./invocation/config"; -import type { StartupNotice } from "./runtime/startupNotice"; +import type { CliInput, CursorLine, LayoutMode, SidebarVisibility } from "./run/commandInputs"; +import type { UserKeyBinding } from "./run/config"; +import type { StartupNotice } from "./process/startupNotice"; import type { TerminalThemeMode } from "./theme/detection"; import type { VcsCatalog } from "./vcs/types"; diff --git a/src/core/changeset/loaders.test.ts b/src/core/changeset/loaders.test.ts index f18e30568..f09a7249d 100644 --- a/src/core/changeset/loaders.test.ts +++ b/src/core/changeset/loaders.test.ts @@ -16,7 +16,7 @@ import { createGitVcsAdapter } from "../../extensions/default/vcs/git"; import { toInternalVcsAdapter } from "../../extensions/runExtension"; import { createVcsCatalog } from "../vcs"; import { loadAppBootstrap as loadCoreAppBootstrap, type LoadAppBootstrapOptions } from "./loaders"; -import type { CliInput } from "../invocation/commandInputs"; +import type { CliInput } from "../run/commandInputs"; import type { VcsAdapter } from "../vcs/types"; import { computeWatchSignature } from "../watch/signature"; diff --git a/src/core/changeset/loaders.ts b/src/core/changeset/loaders.ts index 37002372e..e979d3d0c 100644 --- a/src/core/changeset/loaders.ts +++ b/src/core/changeset/loaders.ts @@ -15,7 +15,7 @@ import { buildDiffFile, type BuildDiffFileOptions, type DiffFileSourceContext } import { createFileSourceFetcher, type FileSourceSpec } from "./fileSource"; import { changesetFromPatch } from "./fromPatch"; -import { DEFAULT_TAB_WIDTH } from "../invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../run/tabWidth"; import { getConfiguredVcsAdapter, isVcsReviewInput, @@ -35,7 +35,7 @@ import type { VcsShowCommandInput, VcsDiffCommandInput, VcsStashShowCommandInput, -} from "../invocation/commandInputs"; +} from "../run/commandInputs"; import type { SidecarContext, Changeset, DiffFile } from "./model"; export interface LoadAppBootstrapOptions { diff --git a/src/core/runtime/appStateFile.test.ts b/src/core/process/appStateFile.test.ts similarity index 100% rename from src/core/runtime/appStateFile.test.ts rename to src/core/process/appStateFile.test.ts diff --git a/src/core/runtime/appStateFile.ts b/src/core/process/appStateFile.ts similarity index 100% rename from src/core/runtime/appStateFile.ts rename to src/core/process/appStateFile.ts diff --git a/src/core/runtime/jobControl.test.ts b/src/core/process/jobControl.test.ts similarity index 100% rename from src/core/runtime/jobControl.test.ts rename to src/core/process/jobControl.test.ts diff --git a/src/core/runtime/jobControl.ts b/src/core/process/jobControl.ts similarity index 100% rename from src/core/runtime/jobControl.ts rename to src/core/process/jobControl.ts diff --git a/src/core/runtime/pager.test.ts b/src/core/process/pager.test.ts similarity index 100% rename from src/core/runtime/pager.test.ts rename to src/core/process/pager.test.ts diff --git a/src/core/runtime/pager.ts b/src/core/process/pager.ts similarity index 100% rename from src/core/runtime/pager.ts rename to src/core/process/pager.ts diff --git a/src/core/runtime/projectRoot.test.ts b/src/core/process/projectRoot.test.ts similarity index 100% rename from src/core/runtime/projectRoot.test.ts rename to src/core/process/projectRoot.test.ts diff --git a/src/core/runtime/projectRoot.ts b/src/core/process/projectRoot.ts similarity index 100% rename from src/core/runtime/projectRoot.ts rename to src/core/process/projectRoot.ts diff --git a/src/core/runtime/shutdown.test.ts b/src/core/process/shutdown.test.ts similarity index 100% rename from src/core/runtime/shutdown.test.ts rename to src/core/process/shutdown.test.ts diff --git a/src/core/runtime/shutdown.ts b/src/core/process/shutdown.ts similarity index 100% rename from src/core/runtime/shutdown.ts rename to src/core/process/shutdown.ts diff --git a/src/core/runtime/startupNotice.ts b/src/core/process/startupNotice.ts similarity index 100% rename from src/core/runtime/startupNotice.ts rename to src/core/process/startupNotice.ts diff --git a/src/core/runtime/terminal.test.ts b/src/core/process/terminal.test.ts similarity index 98% rename from src/core/runtime/terminal.test.ts rename to src/core/process/terminal.test.ts index f6b041ee5..f916d2e18 100644 --- a/src/core/runtime/terminal.test.ts +++ b/src/core/process/terminal.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import type { CliInput } from "../invocation/commandInputs"; +import type { CliInput } from "../run/commandInputs"; import { openControllingTerminal, resolveRuntimeCliInput, diff --git a/src/core/runtime/terminal.ts b/src/core/process/terminal.ts similarity index 97% rename from src/core/runtime/terminal.ts rename to src/core/process/terminal.ts index 2f32e6bbf..24986f2f8 100644 --- a/src/core/runtime/terminal.ts +++ b/src/core/process/terminal.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import tty from "node:tty"; -import type { CliInput } from "../invocation/commandInputs"; +import type { CliInput } from "../run/commandInputs"; export interface AppMouseOptions { stdinIsTTY?: boolean; diff --git a/src/core/runtime/updateNotice.test.ts b/src/core/process/updateNotice.test.ts similarity index 100% rename from src/core/runtime/updateNotice.test.ts rename to src/core/process/updateNotice.test.ts diff --git a/src/core/runtime/updateNotice.ts b/src/core/process/updateNotice.ts similarity index 98% rename from src/core/runtime/updateNotice.ts rename to src/core/process/updateNotice.ts index 78d97949f..1c5b98203 100644 --- a/src/core/runtime/updateNotice.ts +++ b/src/core/process/updateNotice.ts @@ -1,8 +1,8 @@ import { posix, win32 } from "node:path"; import { readAppStateRecord, updateAppStateRecord } from "./appStateFile"; -import { resolveAppStatePath } from "../invocation/paths"; +import { resolveAppStatePath } from "../run/paths"; import type { StartupNotice } from "./startupNotice"; -import { resolveCliVersion, UNKNOWN_CLI_VERSION } from "../invocation/version"; +import { resolveCliVersion, UNKNOWN_CLI_VERSION } from "../run/version"; const DIST_TAGS_URL = "https://registry.npmjs.org/-/package/hunkdiff/dist-tags"; const STABLE_SEMVER_PATTERN = /^\d+\.\d+\.\d+$/; diff --git a/src/core/review/types.ts b/src/core/review/types.ts index 3503e8bb2..ab8735310 100644 --- a/src/core/review/types.ts +++ b/src/core/review/types.ts @@ -9,7 +9,7 @@ * resource descriptors, digests — belong to the producer runtime and are absent here, so * nothing in this file implies a transport. */ -import type { ReviewNoteSource } from "../invocation/commandInputs"; +import type { ReviewNoteSource } from "../run/commandInputs"; export type ReviewSide = "old" | "new"; export type ReviewLineRange = readonly [number, number]; diff --git a/src/core/invocation/commandCatalog.test.ts b/src/core/run/commandCatalog.test.ts similarity index 100% rename from src/core/invocation/commandCatalog.test.ts rename to src/core/run/commandCatalog.test.ts diff --git a/src/core/invocation/commandCatalog.ts b/src/core/run/commandCatalog.ts similarity index 100% rename from src/core/invocation/commandCatalog.ts rename to src/core/run/commandCatalog.ts diff --git a/src/core/invocation/commandInputs.ts b/src/core/run/commandInputs.ts similarity index 100% rename from src/core/invocation/commandInputs.ts rename to src/core/run/commandInputs.ts diff --git a/src/core/invocation/config.test.ts b/src/core/run/config.test.ts similarity index 99% rename from src/core/invocation/config.test.ts rename to src/core/run/config.test.ts index d57c93a6e..5ebe1adc0 100644 --- a/src/core/invocation/config.test.ts +++ b/src/core/run/config.test.ts @@ -14,7 +14,7 @@ import { loadAppBootstrap } from "../changeset/loaders"; import { LEGACY_CUSTOM_SYNTAX_NOTICE, LEGACY_CUSTOM_SYNTAX_NOTICES, -} from "../runtime/startupNotice"; +} from "../process/startupNotice"; const tempDirs: string[] = []; diff --git a/src/core/invocation/config.ts b/src/core/run/config.ts similarity index 99% rename from src/core/invocation/config.ts rename to src/core/run/config.ts index a02b71378..d04fc614d 100644 --- a/src/core/invocation/config.ts +++ b/src/core/run/config.ts @@ -17,9 +17,9 @@ import { resolveSyntaxScopeOverrides, } from "../theme/legacySyntaxScopes"; import { resolveGlobalConfigPath } from "./paths"; -import { LEGACY_CUSTOM_SYNTAX_NOTICES, type StartupNotice } from "../runtime/startupNotice"; +import { LEGACY_CUSTOM_SYNTAX_NOTICES, type StartupNotice } from "../process/startupNotice"; import { DEFAULT_TAB_WIDTH, validateTabWidth } from "./tabWidth"; -import { findProjectRootCandidate } from "../runtime/projectRoot"; +import { findProjectRootCandidate } from "../process/projectRoot"; import { createVcsCatalog, detectVcs } from "../vcs"; import type { VcsCatalog } from "../vcs/types"; import type { diff --git a/src/core/invocation/errors.test.ts b/src/core/run/errors.test.ts similarity index 100% rename from src/core/invocation/errors.test.ts rename to src/core/run/errors.test.ts diff --git a/src/core/invocation/errors.ts b/src/core/run/errors.ts similarity index 100% rename from src/core/invocation/errors.ts rename to src/core/run/errors.ts diff --git a/src/core/invocation/experimental.test.ts b/src/core/run/experimental.test.ts similarity index 100% rename from src/core/invocation/experimental.test.ts rename to src/core/run/experimental.test.ts diff --git a/src/core/invocation/experimental.ts b/src/core/run/experimental.ts similarity index 100% rename from src/core/invocation/experimental.ts rename to src/core/run/experimental.ts diff --git a/src/core/invocation/inputReload.ts b/src/core/run/inputReload.ts similarity index 100% rename from src/core/invocation/inputReload.ts rename to src/core/run/inputReload.ts diff --git a/src/core/invocation/paths.test.ts b/src/core/run/paths.test.ts similarity index 100% rename from src/core/invocation/paths.test.ts rename to src/core/run/paths.test.ts diff --git a/src/core/invocation/paths.ts b/src/core/run/paths.ts similarity index 100% rename from src/core/invocation/paths.ts rename to src/core/run/paths.ts diff --git a/src/core/invocation/tabWidth.ts b/src/core/run/tabWidth.ts similarity index 100% rename from src/core/invocation/tabWidth.ts rename to src/core/run/tabWidth.ts diff --git a/src/core/invocation/version.ts b/src/core/run/version.ts similarity index 100% rename from src/core/invocation/version.ts rename to src/core/run/version.ts diff --git a/src/core/theme/customThemes.ts b/src/core/theme/customThemes.ts index 37a2bdde0..0cfb1ab70 100644 --- a/src/core/theme/customThemes.ts +++ b/src/core/theme/customThemes.ts @@ -1,4 +1,4 @@ -import type { StartupNotice } from "../runtime/startupNotice"; +import type { StartupNotice } from "../process/startupNotice"; import type { NamedCustomThemeConfig } from "../../extension-api/types"; import { BUNDLED_SHIKI_THEME_IDS, resolveBundledShikiThemeId } from "./catalog"; import { LEGACY_CUSTOM_SYNTAX_COLOR_KEYS } from "./legacySyntaxScopes"; diff --git a/src/core/vcs/index.test.ts b/src/core/vcs/index.test.ts index 4abf50083..b1d337c45 100644 --- a/src/core/vcs/index.test.ts +++ b/src/core/vcs/index.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { HunkUserError } from "../invocation/errors"; +import { HunkUserError } from "../run/errors"; import { createUnsupportedVcsOperationError, createVcsCatalog, diff --git a/src/core/vcs/index.ts b/src/core/vcs/index.ts index 59ff89805..53113bc91 100644 --- a/src/core/vcs/index.ts +++ b/src/core/vcs/index.ts @@ -1,7 +1,7 @@ import { relative, resolve } from "node:path"; import { HUNK_DEFAULT_VCS_DETECTION_PRIORITY } from "../../extension-api/types"; -import { HunkUserError } from "../invocation/errors"; -import type { CliInput } from "../invocation/commandInputs"; +import { HunkUserError } from "../run/errors"; +import type { CliInput } from "../run/commandInputs"; import type { VcsAdapter, VcsCatalog, diff --git a/src/core/vcs/types.ts b/src/core/vcs/types.ts index 8944ae090..bb056911c 100644 --- a/src/core/vcs/types.ts +++ b/src/core/vcs/types.ts @@ -4,7 +4,7 @@ import type { VcsDiffCommandInput, VcsShowCommandInput, VcsStashShowCommandInput, -} from "../invocation/commandInputs"; +} from "../run/commandInputs"; import type { BuildDiffFileOptions } from "../changeset/diffFile"; export type VcsId = string; diff --git a/src/core/watch/plan.test.ts b/src/core/watch/plan.test.ts index 93bf543b7..d894cdad6 100644 --- a/src/core/watch/plan.test.ts +++ b/src/core/watch/plan.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { posix, win32 } from "node:path"; import { getBundledVcsCatalog } from "../../app/vcsCatalog"; -import type { CliInput } from "../invocation/commandInputs"; +import type { CliInput } from "../run/commandInputs"; import { createVcsCatalog } from "../vcs"; import type { VcsAdapter } from "../vcs/types"; import { resolveWatchPlan as resolveCoreWatchPlan, type WatchPlanContext } from "./plan"; diff --git a/src/core/watch/plan.ts b/src/core/watch/plan.ts index c46820029..902dd869c 100644 --- a/src/core/watch/plan.ts +++ b/src/core/watch/plan.ts @@ -7,7 +7,7 @@ import type { ExtensionVcsWatchTargetSource, } from "../../extension-api/types"; import { normalizePathForOS } from "../../lib/osPath"; -import type { CliInput } from "../invocation/commandInputs"; +import type { CliInput } from "../run/commandInputs"; import { createVcsWatchPlan, getConfiguredVcsAdapter, operationFromInput } from "../vcs"; import type { VcsCatalog } from "../vcs/types"; diff --git a/src/core/watch/signature.test.ts b/src/core/watch/signature.test.ts index d00e3aa67..0d68a22be 100644 --- a/src/core/watch/signature.test.ts +++ b/src/core/watch/signature.test.ts @@ -3,7 +3,7 @@ import { mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { getBundledVcsCatalog } from "../../app/vcsCatalog"; -import type { CliInput } from "../invocation/commandInputs"; +import type { CliInput } from "../run/commandInputs"; import { createVcsCatalog } from "../vcs"; import type { VcsAdapter } from "../vcs/types"; import { diff --git a/src/core/watch/signature.ts b/src/core/watch/signature.ts index 6384ee703..bea1c3a87 100644 --- a/src/core/watch/signature.ts +++ b/src/core/watch/signature.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import { resolve } from "node:path"; import { createVcsWatchSignature, getConfiguredVcsAdapter, operationFromInput } from "../vcs"; -import type { CliInput } from "../invocation/commandInputs"; +import type { CliInput } from "../run/commandInputs"; import type { VcsCatalog } from "../vcs/types"; /** Format one file stat into a stable signature fragment, or mark the path missing. */ diff --git a/src/extensions/apply.ts b/src/extensions/apply.ts index 6e5415206..3542ed889 100644 --- a/src/extensions/apply.ts +++ b/src/extensions/apply.ts @@ -2,7 +2,7 @@ import { BUILT_IN_FILE_LANGUAGE_EXTENSIONS, registerFileLanguage, } from "../core/changeset/fileLanguage"; -import type { StartupNotice } from "../core/runtime/startupNotice"; +import type { StartupNotice } from "../core/process/startupNotice"; import type { Changeset } from "../core/changeset/model"; import { detectVcs, extendVcsCatalog, getDefaultVcsAdapter } from "../core/vcs"; import type { VcsAdapter, VcsCatalog } from "../core/vcs/types"; diff --git a/src/extensions/discovery.ts b/src/extensions/discovery.ts index 610e5a7b2..7806ec6ab 100644 --- a/src/extensions/discovery.ts +++ b/src/extensions/discovery.ts @@ -1,11 +1,8 @@ import fs from "node:fs"; import { homedir } from "node:os"; import { basename, isAbsolute, join, resolve } from "node:path"; -import { - INSTALLED_EXTENSIONS_DIR_NAME, - resolveGlobalExtensionsDir, -} from "../core/invocation/paths"; -import { findProjectRootCandidate } from "../core/runtime/projectRoot"; +import { INSTALLED_EXTENSIONS_DIR_NAME, resolveGlobalExtensionsDir } from "../core/run/paths"; +import { findProjectRootCandidate } from "../core/process/projectRoot"; import { deriveExtensionId, type ExtensionCandidate, type ExtensionOrigin } from "./types"; /** Entry-file suffixes Hunk will import directly, in preference order. */ diff --git a/src/extensions/host.ts b/src/extensions/host.ts index ded756342..b2197b5bf 100644 --- a/src/extensions/host.ts +++ b/src/extensions/host.ts @@ -1,5 +1,5 @@ import { pathToFileURL } from "node:url"; -import { findProjectRootCandidate } from "../core/runtime/projectRoot"; +import { findProjectRootCandidate } from "../core/process/projectRoot"; import { EXTENSION_ID_RULE, HUNK_VENDOR_EXTENSION_ID, isValidExtensionId } from "./extensionIds"; import { bindExtensionEventBus } from "./events"; import { registerHostRuntimeModules } from "./hostRuntimeModules"; diff --git a/src/extensions/manage/cli.ts b/src/extensions/manage/cli.ts index 335afa0c5..1bc9728af 100644 --- a/src/extensions/manage/cli.ts +++ b/src/extensions/manage/cli.ts @@ -1,6 +1,6 @@ -import { HunkUserError } from "../../core/invocation/errors"; -import { resolveInstalledExtensionsRoot } from "../../core/invocation/paths"; -import type { ExtensionManageCommandInput } from "../../core/invocation/commandInputs"; +import { HunkUserError } from "../../core/run/errors"; +import { resolveInstalledExtensionsRoot } from "../../core/run/paths"; +import type { ExtensionManageCommandInput } from "../../core/run/commandInputs"; import { installExtension, listExtensions, diff --git a/src/extensions/manage/install.ts b/src/extensions/manage/install.ts index 18392787c..08beb135f 100644 --- a/src/extensions/manage/install.ts +++ b/src/extensions/manage/install.ts @@ -1,6 +1,6 @@ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync } from "node:fs"; import { basename, dirname, join } from "node:path"; -import { HunkUserError } from "../../core/invocation/errors"; +import { HunkUserError } from "../../core/run/errors"; import { directoryContainsExtensionEntries } from "../discovery"; import { readInstallRecords, writeInstallRecords, type ExtensionInstallRecord } from "./records"; import type { ExtensionInstallSource } from "./source"; diff --git a/src/extensions/manage/records.ts b/src/extensions/manage/records.ts index f31f838b2..015bc2990 100644 --- a/src/extensions/manage/records.ts +++ b/src/extensions/manage/records.ts @@ -1,5 +1,5 @@ import { join } from "node:path"; -import { readAppStateRecord, writeAppStateRecord } from "../../core/runtime/appStateFile"; +import { readAppStateRecord, writeAppStateRecord } from "../../core/process/appStateFile"; /** * What `hunk extension install` remembers about one managed install. diff --git a/src/extensions/runExtension.ts b/src/extensions/runExtension.ts index 3bec8a738..3fdb00b58 100644 --- a/src/extensions/runExtension.ts +++ b/src/extensions/runExtension.ts @@ -22,7 +22,7 @@ import { type HunkExtensionAPI, } from "./types"; import { parseKeyChord, toKeyChordList } from "../lib/commandKeys"; -import { toUserFacingError } from "../core/invocation/errors"; +import { toUserFacingError } from "../core/run/errors"; import { toInternalVcsPatchResult } from "./vcsPatchResult"; import type { ExtensionVcsOperation } from "../extension-api/types"; import type { VcsAdapter, VcsOperation, VcsReviewInput } from "../core/vcs/types"; diff --git a/src/extensions/startup.test.ts b/src/extensions/startup.test.ts index cefa17cec..1e12af04c 100644 --- a/src/extensions/startup.test.ts +++ b/src/extensions/startup.test.ts @@ -2,7 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import type { ExtensionsConfig } from "../core/invocation/config"; +import type { ExtensionsConfig } from "../core/run/config"; import { createExtensionLoadNotices, loadStartupExtensions, mergeStartupNotices } from "./startup"; import { createEmptyExtensionLoadResult } from "./types"; diff --git a/src/extensions/startup.ts b/src/extensions/startup.ts index a1a6b3a72..c46d8e19b 100644 --- a/src/extensions/startup.ts +++ b/src/extensions/startup.ts @@ -1,6 +1,6 @@ import { isDeepStrictEqual } from "node:util"; -import type { StartupNotice } from "../core/runtime/startupNotice"; -import type { ExtensionsConfig } from "../core/invocation/config"; +import type { StartupNotice } from "../core/process/startupNotice"; +import type { ExtensionsConfig } from "../core/run/config"; import { sanitizeTerminalText } from "../lib/terminalText"; import { discoverExtensions } from "./discovery"; import { retireExtensionLoadResult } from "./events"; diff --git a/src/extensions/trust.test.ts b/src/extensions/trust.test.ts index aaa972d6a..f0a90f330 100644 --- a/src/extensions/trust.test.ts +++ b/src/extensions/trust.test.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; -import { resolveCanonicalPath } from "../core/invocation/paths"; +import { resolveCanonicalPath } from "../core/run/paths"; import { join, resolve } from "node:path"; import { loadExtensions } from "./host"; import { readExtensionTrust, resolveRepoTrust, writeExtensionTrust } from "./trust"; diff --git a/src/extensions/trust.ts b/src/extensions/trust.ts index d807a8935..9d7421d75 100644 --- a/src/extensions/trust.ts +++ b/src/extensions/trust.ts @@ -1,6 +1,6 @@ import { resolve } from "node:path"; -import { readAppStateRecord, updateAppStateRecord } from "../core/runtime/appStateFile"; -import { resolveCanonicalPath, resolveAppStatePath } from "../core/invocation/paths"; +import { readAppStateRecord, updateAppStateRecord } from "../core/process/appStateFile"; +import { resolveCanonicalPath, resolveAppStatePath } from "../core/run/paths"; /** * Repo-local extensions run arbitrary code from the repository under review, diff --git a/src/extensions/vcsPatchResult.test.ts b/src/extensions/vcsPatchResult.test.ts index 0b2d3201e..fa22cc56a 100644 --- a/src/extensions/vcsPatchResult.test.ts +++ b/src/extensions/vcsPatchResult.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { toInternalVcsPatchResult } from "./vcsPatchResult"; import { HunkExtensionUserError } from "../extension-api/types"; -import { HunkUserError, toUserFacingError } from "../core/invocation/errors"; +import { HunkUserError, toUserFacingError } from "../core/run/errors"; import { SourceTextTooLargeError } from "../core/changeset/fileSource"; import { toInternalVcsAdapter } from "./runExtension"; import type { diff --git a/src/main.tsx b/src/main.tsx index e3996392b..be09e1146 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,7 +1,7 @@ #!/usr/bin/env bun -import { formatCliError } from "./core/invocation/errors"; -import { pagePlainText } from "./core/runtime/pager"; +import { formatCliError } from "./core/run/errors"; +import { pagePlainText } from "./core/process/pager"; import { prepareStartupPlan } from "./app/startup"; import { sanitizeTerminalText } from "./lib/terminalText"; import { serveSessionBrokerDaemon } from "./session/broker/brokerServer"; diff --git a/src/opentui/HunkDiffBody.tsx b/src/opentui/HunkDiffBody.tsx index 4a238b6d6..b21bca762 100644 --- a/src/opentui/HunkDiffBody.tsx +++ b/src/opentui/HunkDiffBody.tsx @@ -1,5 +1,5 @@ import { useMemo } from "react"; -import { DEFAULT_TAB_WIDTH } from "../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../core/run/tabWidth"; import { findMaxLineNumber } from "../ui/diff/codeColumns"; import { buildSplitRows, buildStackRows } from "../ui/diff/diffRows"; import { diffMessage, DiffRowView, fitText } from "../ui/diff/renderRows"; diff --git a/src/session/agent/cliClient.test.ts b/src/session/agent/cliClient.test.ts index 3e95c02b1..b0b1f7b45 100644 --- a/src/session/agent/cliClient.test.ts +++ b/src/session/agent/cliClient.test.ts @@ -9,7 +9,7 @@ import { createTestSessionReviewHunk, createTestSessionSnapshot, } from "../../../test/helpers/session-daemon-fixtures"; -import type { SessionSelectorInput } from "../../core/invocation/commandInputs"; +import type { SessionSelectorInput } from "../../core/run/commandInputs"; import { HUNK_SESSION_API_PATH, HUNK_SESSION_API_VERSION, diff --git a/src/session/agent/cliClient.ts b/src/session/agent/cliClient.ts index 1b6fe1df8..62c8d14b6 100644 --- a/src/session/agent/cliClient.ts +++ b/src/session/agent/cliClient.ts @@ -38,7 +38,7 @@ import type { SessionReloadCommandInput, SessionReviewCommandInput, SessionSelectorInput, -} from "../../core/invocation/commandInputs"; +} from "../../core/run/commandInputs"; import { describeSessionSelector } from "@hunk/session-broker-core"; export interface HunkSessionCliClient { diff --git a/src/session/agent/commands.daemon.test.ts b/src/session/agent/commands.daemon.test.ts index c795e56fe..f5c240a4c 100644 --- a/src/session/agent/commands.daemon.test.ts +++ b/src/session/agent/commands.daemon.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { createServer } from "node:net"; import { platform } from "node:os"; -import type { SessionCommandInput } from "../../core/invocation/commandInputs"; +import type { SessionCommandInput } from "../../core/run/commandInputs"; import { createTestListedSession } from "../../../test/helpers/session-daemon-fixtures"; import { runSessionCommand, diff --git a/src/session/agent/commands.test.ts b/src/session/agent/commands.test.ts index 94560a939..6eda84832 100644 --- a/src/session/agent/commands.test.ts +++ b/src/session/agent/commands.test.ts @@ -7,10 +7,7 @@ import { createTestSessionReview as buildTestSessionReview, createTestSessionSnapshot, } from "../../../test/helpers/session-daemon-fixtures"; -import type { - SessionCommandInput, - SessionSelectorInput, -} from "../../core/invocation/commandInputs"; +import type { SessionCommandInput, SessionSelectorInput } from "../../core/run/commandInputs"; import { runSessionCommand, setSessionCommandTestHooks, diff --git a/src/session/agent/commands.ts b/src/session/agent/commands.ts index 29414eed1..e5cfca35f 100644 --- a/src/session/agent/commands.ts +++ b/src/session/agent/commands.ts @@ -2,7 +2,7 @@ import type { SessionCommandInput, SessionCommandOutput, SessionSelectorInput, -} from "../../core/invocation/commandInputs"; +} from "../../core/run/commandInputs"; import type { SessionLiveCommentSummary, SessionReviewNoteSummary } from "../types"; import { NO_ACTIVE_SESSIONS_MESSAGE } from "./errors"; import { diff --git a/src/session/broker/wire.ts b/src/session/broker/wire.ts index 155e4c4c4..4ff45ce24 100644 --- a/src/session/broker/wire.ts +++ b/src/session/broker/wire.ts @@ -1,8 +1,5 @@ -import { - EXPERIMENTAL_FEATURES, - type ExperimentalFeature, -} from "../../core/invocation/experimental"; -import type { CliInput } from "../../core/invocation/commandInputs"; +import { EXPERIMENTAL_FEATURES, type ExperimentalFeature } from "../../core/run/experimental"; +import type { CliInput } from "../../core/run/commandInputs"; import { MAX_REGISTRATION_FILES, MAX_REGISTRATION_HUNKS_PER_FILE, diff --git a/src/session/client/daemonHttp.ts b/src/session/client/daemonHttp.ts index 7dee703c2..854425050 100644 --- a/src/session/client/daemonHttp.ts +++ b/src/session/client/daemonHttp.ts @@ -1,4 +1,4 @@ -import { HunkUserError } from "../../core/invocation/errors"; +import { HunkUserError } from "../../core/run/errors"; import { resolveSessionBrokerConfig, type ResolvedSessionBrokerConfig, diff --git a/src/session/protocol.ts b/src/session/protocol.ts index 73f02e7ee..bdc3a9c52 100644 --- a/src/session/protocol.ts +++ b/src/session/protocol.ts @@ -10,7 +10,7 @@ import type { SessionReloadCommandInput, SessionReviewCommandInput, SessionSelectorInput, -} from "../core/invocation/commandInputs"; +} from "../core/run/commandInputs"; import type { AppliedCommentBatchResult, AppliedCommentResult, diff --git a/src/session/protocolSchemas.ts b/src/session/protocolSchemas.ts index 452eb6047..2de226cc9 100644 --- a/src/session/protocolSchemas.ts +++ b/src/session/protocolSchemas.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import type { CliInput } from "../core/invocation/commandInputs"; +import type { CliInput } from "../core/run/commandInputs"; import type { SessionDaemonRequest } from "./protocol"; /** diff --git a/src/session/types.ts b/src/session/types.ts index 89cd1fb87..2bda421db 100644 --- a/src/session/types.ts +++ b/src/session/types.ts @@ -1,8 +1,8 @@ -import type { ExperimentalFeature } from "../core/invocation/experimental"; +import type { ExperimentalFeature } from "../core/run/experimental"; import type { ExtensionLineHighlightTone, SessionReloadReason } from "../extension-api/types"; import type { CommentTargetInput, DiffSide } from "../core/liveComments"; import type { ReviewPublicationAddress } from "../core/review/generationOrder"; -import type { CliInput, ReviewNoteSource } from "../core/invocation/commandInputs"; +import type { CliInput, ReviewNoteSource } from "../core/run/commandInputs"; import type { HunkReviewActionEnvelopeV1, HunkReviewResourceCatalogV1, diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 4ed9f2228..811aae0b4 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -20,17 +20,14 @@ import { saveGlobalViewPreferences, saveViewPreferencesPromptPreference, type PersistedViewPreferences, -} from "../core/invocation/config"; -import { - experimentalFeatureEnabled, - resolveExperimentalDiffFiles, -} from "../core/invocation/experimental"; -import { DEFAULT_TAB_WIDTH } from "../core/invocation/tabWidth"; +} from "../core/run/config"; +import { experimentalFeatureEnabled, resolveExperimentalDiffFiles } from "../core/run/experimental"; +import { DEFAULT_TAB_WIDTH } from "../core/run/tabWidth"; import { isVcsReviewInput } from "../core/vcs"; import type { AppBootstrap } from "../core/bootstrap"; -import type { CliInput, CursorLine, LayoutMode } from "../core/invocation/commandInputs"; +import type { CliInput, CursorLine, LayoutMode } from "../core/run/commandInputs"; import type { UserNoteLineTarget } from "../core/liveComments"; -import { canReloadInput } from "../core/invocation/inputReload"; +import { canReloadInput } from "../core/run/inputReload"; import { sanitizeTerminalLine } from "../lib/terminalText"; import { resolveExtensionCommands, diff --git a/src/ui/AppHost.cursor-line.test.tsx b/src/ui/AppHost.cursor-line.test.tsx index 283224dde..7de451afc 100644 --- a/src/ui/AppHost.cursor-line.test.tsx +++ b/src/ui/AppHost.cursor-line.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; -import type { CursorLine } from "../core/invocation/commandInputs"; +import type { CursorLine } from "../core/run/commandInputs"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile, lines } from "../../test/helpers/diff-helpers"; import { AppHost } from "./AppHost"; diff --git a/src/ui/AppHost.extension-dialogs.test.tsx b/src/ui/AppHost.extension-dialogs.test.tsx index 0a303e79c..7df60410d 100644 --- a/src/ui/AppHost.extension-dialogs.test.tsx +++ b/src/ui/AppHost.extension-dialogs.test.tsx @@ -10,7 +10,7 @@ import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/load import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import type { CliInput } from "../core/invocation/commandInputs"; +import type { CliInput } from "../core/run/commandInputs"; import type { HunkSessionBrokerClient } from "../session/broker/brokerClient"; import { loadStartupExtensions } from "../extensions/startup"; import { AppHost } from "./AppHost"; diff --git a/src/ui/AppHost.extensions.test.tsx b/src/ui/AppHost.extensions.test.tsx index 9e299b0a7..124afab5f 100644 --- a/src/ui/AppHost.extensions.test.tsx +++ b/src/ui/AppHost.extensions.test.tsx @@ -17,7 +17,7 @@ import { ReviewProducer } from "../app/review/producer"; import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/loaders"; -import type { CliInput } from "../core/invocation/commandInputs"; +import type { CliInput } from "../core/run/commandInputs"; import type { HunkSessionBrokerClient } from "../session/broker/brokerClient"; import { diff --git a/src/ui/AppHost.interactions.test.tsx b/src/ui/AppHost.interactions.test.tsx index 499a5a5aa..3b62c08fb 100644 --- a/src/ui/AppHost.interactions.test.tsx +++ b/src/ui/AppHost.interactions.test.tsx @@ -11,9 +11,9 @@ import type { HunkSessionServerMessage, HunkSessionSnapshot, } from "../session/types"; -import { LEGACY_CUSTOM_SYNTAX_NOTICE } from "../core/runtime/startupNotice"; +import { LEGACY_CUSTOM_SYNTAX_NOTICE } from "../core/process/startupNotice"; import type { AppBootstrap } from "../core/bootstrap"; -import type { LayoutMode } from "../core/invocation/commandInputs"; +import type { LayoutMode } from "../core/run/commandInputs"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { capturedTestColorToHex } from "../../test/helpers/test-color-helpers"; import { createTestDiffFile as buildTestDiffFile, lines } from "../../test/helpers/diff-helpers"; diff --git a/src/ui/AppHost.keybindings.test.tsx b/src/ui/AppHost.keybindings.test.tsx index dbc86b69a..1416daf55 100644 --- a/src/ui/AppHost.keybindings.test.tsx +++ b/src/ui/AppHost.keybindings.test.tsx @@ -6,7 +6,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import { removeTestDirectory } from "../../test/helpers/filesystem"; -import { resolveConfiguredCliInput } from "../core/invocation/config"; +import { resolveConfiguredCliInput } from "../core/run/config"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; import { loadAppBootstrap } from "../core/changeset/loaders"; import type { AppBootstrap } from "../core/bootstrap"; diff --git a/src/ui/AppHost.responsive.test.tsx b/src/ui/AppHost.responsive.test.tsx index 1f0f79144..a344d5a62 100644 --- a/src/ui/AppHost.responsive.test.tsx +++ b/src/ui/AppHost.responsive.test.tsx @@ -2,7 +2,7 @@ import { describe, expect, mock, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import type { AppBootstrap } from "../core/bootstrap"; -import type { LayoutMode } from "../core/invocation/commandInputs"; +import type { LayoutMode } from "../core/run/commandInputs"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile } from "../../test/helpers/diff-helpers"; diff --git a/src/ui/AppHost.sidebar-visibility.test.tsx b/src/ui/AppHost.sidebar-visibility.test.tsx index 6c8fb99fa..13a71d019 100644 --- a/src/ui/AppHost.sidebar-visibility.test.tsx +++ b/src/ui/AppHost.sidebar-visibility.test.tsx @@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act } from "react"; import type { AppBootstrap } from "../core/bootstrap"; -import type { SidebarVisibility } from "../core/invocation/commandInputs"; +import type { SidebarVisibility } from "../core/run/commandInputs"; import { createTestVcsAppBootstrap } from "../../test/helpers/app-bootstrap"; import { createTestDiffFile as buildTestDiffFile, lines } from "../../test/helpers/diff-helpers"; import { HUNK_FILES_PANE_KEY } from "../extensions/extensionIds"; diff --git a/src/ui/AppHost.tsx b/src/ui/AppHost.tsx index feba7b085..e2359fc8c 100644 --- a/src/ui/AppHost.tsx +++ b/src/ui/AppHost.tsx @@ -3,11 +3,11 @@ import { resolveConfiguredExtensions } from "../app/extensionBootstrap"; import { ReviewProducer } from "../app/review/producer"; import { loadConfiguredSessionBootstrap } from "../app/sessionBootstrap"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import { resolveConfiguredCliInput } from "../core/invocation/config"; -import { resolveRuntimeCliInput } from "../core/runtime/terminal"; -import type { StartupNotice } from "../core/runtime/startupNotice"; +import { resolveConfiguredCliInput } from "../core/run/config"; +import { resolveRuntimeCliInput } from "../core/process/terminal"; +import type { StartupNotice } from "../core/process/startupNotice"; import type { AppBootstrap } from "../core/bootstrap"; -import type { CliInput } from "../core/invocation/commandInputs"; +import type { CliInput } from "../core/run/commandInputs"; import type { ExtensionLoadResult } from "../extensions/types"; import { createUnknownVcsNotice, diff --git a/src/ui/AppHost.workspace.test.tsx b/src/ui/AppHost.workspace.test.tsx index 7ab62bc08..f79c70a8d 100644 --- a/src/ui/AppHost.workspace.test.tsx +++ b/src/ui/AppHost.workspace.test.tsx @@ -17,7 +17,7 @@ import { loadAppBootstrap as loadCoreAppBootstrap } from "../core/changeset/load import type { AppBootstrap } from "../app/types"; import { getBundledVcsCatalog } from "../app/vcsCatalog"; -import type { CliInput } from "../core/invocation/commandInputs"; +import type { CliInput } from "../core/run/commandInputs"; import { loadStartupExtensions } from "../extensions/startup"; import type { HunkSessionBrokerClient } from "../session/broker/brokerClient"; import type { WorkspaceFileWriter } from "./App"; diff --git a/src/ui/components/panes/AgentInlineNote.tsx b/src/ui/components/panes/AgentInlineNote.tsx index e7305c2d1..1c1d57b91 100644 --- a/src/ui/components/panes/AgentInlineNote.tsx +++ b/src/ui/components/panes/AgentInlineNote.tsx @@ -6,7 +6,7 @@ import { } from "@opentui/core"; import { useLayoutEffect, useRef, type ReactNode } from "react"; import type { DiffFile } from "../../../core/changeset/model"; -import type { LayoutMode } from "../../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../../core/run/commandInputs"; import type { AgentAnnotation } from "../../../extension-api/types"; import { agentNoteBoxLayout } from "../../lib/agentNoteGeometry"; import { annotationRangeLabel, reviewNoteSource } from "../../lib/agentAnnotations"; diff --git a/src/ui/components/panes/DiffPane.tsx b/src/ui/components/panes/DiffPane.tsx index 97b1d0ebe..af9be9276 100644 --- a/src/ui/components/panes/DiffPane.tsx +++ b/src/ui/components/panes/DiffPane.tsx @@ -13,9 +13,9 @@ import { useState, type RefObject, } from "react"; -import { DEFAULT_TAB_WIDTH } from "../../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../../core/run/tabWidth"; import type { DiffFile } from "../../../core/changeset/model"; -import type { CursorLine, LayoutMode } from "../../../core/invocation/commandInputs"; +import type { CursorLine, LayoutMode } from "../../../core/run/commandInputs"; import type { UserNoteLineTarget } from "../../../core/liveComments"; import type { AgentAnnotation } from "../../../extension-api/types"; import { resolveReviewRevealNoteId } from "../../../core/review/selectors"; diff --git a/src/ui/components/panes/DiffSection.tsx b/src/ui/components/panes/DiffSection.tsx index be9412891..3302365a5 100644 --- a/src/ui/components/panes/DiffSection.tsx +++ b/src/ui/components/panes/DiffSection.tsx @@ -1,6 +1,6 @@ import { memo } from "react"; import type { DiffFile } from "../../../core/changeset/model"; -import type { LayoutMode } from "../../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../../core/run/commandInputs"; import type { UserNoteLineTarget } from "../../../core/liveComments"; import type { FileSourceStatus } from "../../diff/expandCollapsedRows"; import { DiffSectionBody, type ActiveAddNoteAffordance } from "../../diff/DiffSectionBody"; diff --git a/src/ui/components/panes/copySelection.ts b/src/ui/components/panes/copySelection.ts index f3e2b0352..11774f9d8 100644 --- a/src/ui/components/panes/copySelection.ts +++ b/src/ui/components/panes/copySelection.ts @@ -1,5 +1,5 @@ import type { DiffFile } from "../../../core/changeset/model"; -import type { LayoutMode } from "../../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../../core/run/commandInputs"; import { DIFF_RAIL_PREFIX_WIDTH, resolveSplitCellGeometry, diff --git a/src/ui/diff/DiffSectionBody.tsx b/src/ui/diff/DiffSectionBody.tsx index 6d5d61c7d..76291bc39 100644 --- a/src/ui/diff/DiffSectionBody.tsx +++ b/src/ui/diff/DiffSectionBody.tsx @@ -6,9 +6,9 @@ */ import { useRenderer } from "@opentui/react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/run/tabWidth"; import type { DiffFile } from "../../core/changeset/model"; -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; import type { UserNoteLineTarget } from "../../core/liveComments"; import { AgentInlineNote } from "../components/panes/AgentInlineNote"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; diff --git a/src/ui/diff/codeColumns.ts b/src/ui/diff/codeColumns.ts index 1a3628784..c9866a18a 100644 --- a/src/ui/diff/codeColumns.ts +++ b/src/ui/diff/codeColumns.ts @@ -1,6 +1,6 @@ -import { DEFAULT_TAB_WIDTH, validateTabWidth } from "../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH, validateTabWidth } from "../../core/run/tabWidth"; import type { DiffFile } from "../../core/changeset/model"; -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; import { measureTextWidth } from "../lib/text"; import type { DiffRow } from "./diffRowModel"; diff --git a/src/ui/diff/diffRows.ts b/src/ui/diff/diffRows.ts index fbcaccc41..de699a684 100644 --- a/src/ui/diff/diffRows.ts +++ b/src/ui/diff/diffRows.ts @@ -20,7 +20,7 @@ import { reviewTrailingGap, type ReviewGapAddress, } from "../../core/review/expansion"; -import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/run/tabWidth"; import type { DiffFile, DiffLineMoveKind } from "../../core/changeset/model"; import { blendHex, hexColorDistance } from "../lib/color"; import { measureTextWidth } from "../lib/text"; diff --git a/src/ui/diff/diffSectionGeometry.ts b/src/ui/diff/diffSectionGeometry.ts index 8b34f9e4f..3cde94944 100644 --- a/src/ui/diff/diffSectionGeometry.ts +++ b/src/ui/diff/diffSectionGeometry.ts @@ -1,6 +1,6 @@ -import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/run/tabWidth"; import type { DiffFile } from "../../core/changeset/model"; -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; import { measureAgentInlineNoteHeight } from "../components/panes/AgentInlineNote"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; import type { SectionGeometry, VerticalBounds } from "../lib/diffSpatial"; diff --git a/src/ui/diff/diffSectionRowPlan.ts b/src/ui/diff/diffSectionRowPlan.ts index 6404f00bd..53c98ada1 100644 --- a/src/ui/diff/diffSectionRowPlan.ts +++ b/src/ui/diff/diffSectionRowPlan.ts @@ -1,7 +1,7 @@ import { reviewExpansionSide } from "../../core/review/expansion"; -import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/run/tabWidth"; import type { DiffFile } from "../../core/changeset/model"; -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; import type { VisibleAgentNote } from "../lib/agentAnnotations"; import type { AppTheme } from "../themes"; import { findMaxLineNumber, findMaxLineNumberInRows } from "./codeColumns"; diff --git a/src/ui/diff/expandCollapsedRows.ts b/src/ui/diff/expandCollapsedRows.ts index be9d815a8..e4bfc5088 100644 --- a/src/ui/diff/expandCollapsedRows.ts +++ b/src/ui/diff/expandCollapsedRows.ts @@ -1,6 +1,6 @@ import { reviewGapId } from "../../core/review/expansion"; import { normalizedReviewSourceLines } from "../../core/review/geometry"; -import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/run/tabWidth"; import { sanitizeTerminalLine, sanitizeTerminalSpans } from "../../lib/terminalText"; import { expandDiffTabs } from "./codeColumns"; import type { diff --git a/src/ui/diff/lineHighlightPaint.test.ts b/src/ui/diff/lineHighlightPaint.test.ts index 0b955f25e..f3a927a30 100644 --- a/src/ui/diff/lineHighlightPaint.test.ts +++ b/src/ui/diff/lineHighlightPaint.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; import { createTestDiffFile, lines } from "../../../test/helpers/diff-helpers"; -import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/run/tabWidth"; import type { ValidatedLineHighlight } from "../highlights/validate"; import { measureTextWidth } from "../lib/text"; import { expandDiffTabs } from "./codeColumns"; diff --git a/src/ui/diff/lineHighlightPaint.ts b/src/ui/diff/lineHighlightPaint.ts index afb1e2254..446e1a082 100644 --- a/src/ui/diff/lineHighlightPaint.ts +++ b/src/ui/diff/lineHighlightPaint.ts @@ -18,7 +18,7 @@ import { type ReviewGapAddress, } from "../../core/review/expansion"; import { normalizedReviewSourceLines } from "../../core/review/geometry"; -import { DEFAULT_TAB_WIDTH } from "../../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../../core/run/tabWidth"; import type { DiffFile } from "../../core/changeset/model"; import type { ExtensionLineHighlightTone } from "../../extension-api/types"; import { sanitizeTerminalLine } from "../../lib/terminalText"; diff --git a/src/ui/diff/renderRows.tsx b/src/ui/diff/renderRows.tsx index b8d786883..d8433f674 100644 --- a/src/ui/diff/renderRows.tsx +++ b/src/ui/diff/renderRows.tsx @@ -47,7 +47,7 @@ import { wrapSanitizedTextByWidth, } from "../lib/text"; import type { CopySelectedRowRange } from "../lib/diffSpatial"; -import type { CursorLine } from "../../core/invocation/commandInputs"; +import type { CursorLine } from "../../core/run/commandInputs"; export interface CursorHighlight { /** The render plan anchor of the row the cursor rests on, shared with reveal lookups. */ diff --git a/src/ui/diff/reviewRowGeometry.ts b/src/ui/diff/reviewRowGeometry.ts index 337bb24f0..48cdc4b83 100644 --- a/src/ui/diff/reviewRowGeometry.ts +++ b/src/ui/diff/reviewRowGeometry.ts @@ -5,7 +5,7 @@ * where each hunk's visible extent falls. Heights resolve before mount, which is why note * markup has to lay out deterministically from `(markup, width)` alone. */ -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; import { measureAgentInlineNoteHeight } from "../components/panes/AgentInlineNote"; import type { SectionGeometry, VerticalBounds } from "../lib/diffSpatial"; import { reviewRowId } from "../lib/ids"; diff --git a/src/ui/hooks/useHunkSessionBridge.ts b/src/ui/hooks/useHunkSessionBridge.ts index 98d364201..727255d90 100644 --- a/src/ui/hooks/useHunkSessionBridge.ts +++ b/src/ui/hooks/useHunkSessionBridge.ts @@ -1,7 +1,7 @@ import { useEffect, useMemo } from "react"; import type { ReviewProducer } from "../../app/review/producer"; import type { DiffFile } from "../../core/changeset/model"; -import type { CliInput } from "../../core/invocation/commandInputs"; +import type { CliInput } from "../../core/run/commandInputs"; import { reviewHunkRanges } from "../../core/review/geometry"; import { createHunkSessionBridge } from "../../app/session/bridge"; import type { HunkSessionBrokerClient } from "../../session/broker/brokerClient"; diff --git a/src/ui/hooks/useStartupNotices.ts b/src/ui/hooks/useStartupNotices.ts index 60366c109..a1de79291 100644 --- a/src/ui/hooks/useStartupNotices.ts +++ b/src/ui/hooks/useStartupNotices.ts @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from "react"; -import type { StartupNotice } from "../../core/runtime/startupNotice"; +import type { StartupNotice } from "../../core/process/startupNotice"; const DEFAULT_STARTUP_NOTICE_DELAY_MS = 1200; const DEFAULT_STARTUP_NOTICE_DURATION_MS = 7000; diff --git a/src/ui/hooks/useTerminalReview.test.tsx b/src/ui/hooks/useTerminalReview.test.tsx index cb78d1374..e806af6fa 100644 --- a/src/ui/hooks/useTerminalReview.test.tsx +++ b/src/ui/hooks/useTerminalReview.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, spyOn, test } from "bun:test"; import { testRender } from "@opentui/react/test-utils"; import { act, StrictMode, useEffect, useRef, useState } from "react"; -import { builtinAppCommand } from "../../core/invocation/commandCatalog"; +import { builtinAppCommand } from "../../core/run/commandCatalog"; import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; import type { DiffFile } from "../../core/changeset/model"; import { diff --git a/src/ui/hooks/useTerminalReview.ts b/src/ui/hooks/useTerminalReview.ts index 42e4a92be..41dc9e7ea 100644 --- a/src/ui/hooks/useTerminalReview.ts +++ b/src/ui/hooks/useTerminalReview.ts @@ -30,7 +30,7 @@ import { lowerAppCommandToReviewIntent, type AppCommandId, type AppCommandLoweringContext, -} from "../../core/invocation/commandCatalog"; +} from "../../core/run/commandCatalog"; import { SourceTextTooLargeError } from "../../core/changeset/fileSource"; import { applyReviewIntent, @@ -51,7 +51,7 @@ import { REVIEW_VIEWPORT_ANCHOR_REVEAL, type ReviewRevealRequest } from "../../c import { createReviewStore, type ReviewStore } from "../../core/review/store"; import { noDiffFileMatchesMessage } from "../../session/agent/errors"; import type { DiffFile } from "../../core/changeset/model"; -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; import type { AgentAnnotation } from "../../extension-api/types"; import type { AppliedCommentBatchResult, diff --git a/src/ui/hooks/useWatchedInput.ts b/src/ui/hooks/useWatchedInput.ts index 3ace994cc..2f6cb69a6 100644 --- a/src/ui/hooks/useWatchedInput.ts +++ b/src/ui/hooks/useWatchedInput.ts @@ -8,7 +8,7 @@ import { createWatchEventSource } from "../../core/watch/observer"; import { resolveWatchPlan, type WatchPlan } from "../../core/watch/plan"; import { computeWatchSignature } from "../../core/watch/signature"; import type { ReloadContext } from "../../core/bootstrap"; -import type { CliInput } from "../../core/invocation/commandInputs"; +import type { CliInput } from "../../core/run/commandInputs"; export interface WatchedInputRuntime { clock?: WatchControllerClock; diff --git a/src/ui/lib/agentAnnotations.ts b/src/ui/lib/agentAnnotations.ts index 3417dd4e2..b22505d60 100644 --- a/src/ui/lib/agentAnnotations.ts +++ b/src/ui/lib/agentAnnotations.ts @@ -1,6 +1,6 @@ import type { Hunk } from "@pierre/diffs"; import type { DiffFile } from "../../core/changeset/model"; -import type { ReviewNoteSource } from "../../core/invocation/commandInputs"; +import type { ReviewNoteSource } from "../../core/run/commandInputs"; import type { AgentAnnotation } from "../../extension-api/types"; import { reviewAnnotationOverlapsHunk } from "../../core/review/annotations"; import { resolveReviewNoteAnchor, reviewGapOwnerHunkIndex } from "../../core/review/anchors"; diff --git a/src/ui/lib/agentNoteGeometry.ts b/src/ui/lib/agentNoteGeometry.ts index ffcca08b3..5edcfb4de 100644 --- a/src/ui/lib/agentNoteGeometry.ts +++ b/src/ui/lib/agentNoteGeometry.ts @@ -6,7 +6,7 @@ // width their STML will actually be laid out at — all three must agree or // note heights and agent feedback drift from what the terminal shows. -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; import { resolveSplitPaneWidths } from "../diff/codeColumns"; export interface AgentNoteGeometryInput { diff --git a/src/ui/lib/appCommands.test.ts b/src/ui/lib/appCommands.test.ts index 5e27830c4..188538cfa 100644 --- a/src/ui/lib/appCommands.test.ts +++ b/src/ui/lib/appCommands.test.ts @@ -12,7 +12,7 @@ import { type BuildAppCommandsOptions, type ResolvedCommandKeys, } from "./appCommands"; -import { APP_COMMAND_CATALOG } from "../../core/invocation/commandCatalog"; +import { APP_COMMAND_CATALOG } from "../../core/run/commandCatalog"; import { buildAppMenus } from "./appMenus"; import { buildHelpSections, HELP_COMMAND_IDS } from "./helpContent"; import { resolveCommandKeys } from "./keymap"; diff --git a/src/ui/lib/appCommands.ts b/src/ui/lib/appCommands.ts index d86b3aeee..87fed7b70 100644 --- a/src/ui/lib/appCommands.ts +++ b/src/ui/lib/appCommands.ts @@ -4,9 +4,9 @@ import { type AppCommandCatalogEntry, type AppCommandId, type VerticalCommandDirection, -} from "../../core/invocation/commandCatalog"; +} from "../../core/run/commandCatalog"; import type { ReviewSelectionScope } from "../../core/review/navigation"; -import type { CursorLine, LayoutMode } from "../../core/invocation/commandInputs"; +import type { CursorLine, LayoutMode } from "../../core/run/commandInputs"; import type { ExtensionCommandExecutionOptions } from "../../extension-api/types"; import { matchesAnyKeyChord, diff --git a/src/ui/lib/appMenus.ts b/src/ui/lib/appMenus.ts index 4f636450c..0614b6c00 100644 --- a/src/ui/lib/appMenus.ts +++ b/src/ui/lib/appMenus.ts @@ -1,4 +1,4 @@ -import type { CursorLine, LayoutMode } from "../../core/invocation/commandInputs"; +import type { CursorLine, LayoutMode } from "../../core/run/commandInputs"; import type { AppMenus, MenuEntry, MenuId } from "../components/chrome/menu"; import { executeAppCommand, isCommandEnabled, type AppCommand } from "./appCommands"; diff --git a/src/ui/lib/extensionWorkspace.test.ts b/src/ui/lib/extensionWorkspace.test.ts index d2ebc6ec9..c907371fc 100644 --- a/src/ui/lib/extensionWorkspace.test.ts +++ b/src/ui/lib/extensionWorkspace.test.ts @@ -1,6 +1,6 @@ import { join, resolve, sep } from "node:path"; import { describe, expect, test } from "bun:test"; -import type { CliInput, CommonOptions } from "../../core/invocation/commandInputs"; +import type { CliInput, CommonOptions } from "../../core/run/commandInputs"; import { normalizeWorkspaceWriteRequest, resolveExtensionWorkspaceRead, diff --git a/src/ui/lib/extensionWorkspace.ts b/src/ui/lib/extensionWorkspace.ts index aa7f455c9..e2d69b440 100644 --- a/src/ui/lib/extensionWorkspace.ts +++ b/src/ui/lib/extensionWorkspace.ts @@ -20,8 +20,8 @@ import { isAbsolute, relative, resolve, sep } from "node:path"; import { normalizeDiffPath } from "../../core/changeset/diffPaths"; import type { FileSourceSide } from "../../core/changeset/fileSource"; -import { canReloadInput } from "../../core/invocation/inputReload"; -import type { CliInput } from "../../core/invocation/commandInputs"; +import { canReloadInput } from "../../core/run/inputReload"; +import type { CliInput } from "../../core/run/commandInputs"; import { readMetadataChangeType } from "../../extensions/events"; /** diff --git a/src/ui/lib/keymap.ts b/src/ui/lib/keymap.ts index 811b25cb1..6368e9edc 100644 --- a/src/ui/lib/keymap.ts +++ b/src/ui/lib/keymap.ts @@ -1,4 +1,4 @@ -import type { UserKeyBinding } from "../../core/invocation/config"; +import type { UserKeyBinding } from "../../core/run/config"; import type { ExtensionPaneKeybindings } from "../../extension-api/types"; import { HUNK_VENDOR_EXTENSION_ID } from "../../extensions/extensionIds"; import { matchesKeyChord, parseKeyChord, type ParsedKeyChord } from "../../lib/commandKeys"; diff --git a/src/ui/lib/lineCursors.test.ts b/src/ui/lib/lineCursors.test.ts index 66b5ccdb5..f88eda01e 100644 --- a/src/ui/lib/lineCursors.test.ts +++ b/src/ui/lib/lineCursors.test.ts @@ -5,7 +5,7 @@ import { lines, } from "../../../test/helpers/diff-helpers"; import type { DiffFile } from "../../core/changeset/model"; -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; import { reviewGapId } from "../../core/review/expansion"; import { measureDiffSectionGeometry } from "../diff/diffSectionGeometry"; import { resolveTheme } from "../themes"; diff --git a/src/ui/lib/responsive.ts b/src/ui/lib/responsive.ts index 8cbd1da61..a8805c97e 100644 --- a/src/ui/lib/responsive.ts +++ b/src/ui/lib/responsive.ts @@ -1,4 +1,4 @@ -import type { LayoutMode } from "../../core/invocation/commandInputs"; +import type { LayoutMode } from "../../core/run/commandInputs"; export type ResponsiveViewport = "full" | "medium" | "tight"; diff --git a/src/ui/lib/stml/cli.ts b/src/ui/lib/stml/cli.ts index 0a7374d9f..6a9eb0b75 100644 --- a/src/ui/lib/stml/cli.ts +++ b/src/ui/lib/stml/cli.ts @@ -2,7 +2,7 @@ // main.tsx so the command behavior is directly testable. import { resolve as resolvePath } from "node:path"; -import type { MarkupRenderCommandInput } from "../../../core/invocation/commandInputs"; +import type { MarkupRenderCommandInput } from "../../../core/run/commandInputs"; import { resolveTheme } from "../../themes"; import { STML_GUIDE } from "./guide"; import { renderStmlToAnsi, renderStmlToText } from "./render"; diff --git a/src/ui/runInteractiveApp.tsx b/src/ui/runInteractiveApp.tsx index 8656189c0..12aa16c80 100644 --- a/src/ui/runInteractiveApp.tsx +++ b/src/ui/runInteractiveApp.tsx @@ -5,11 +5,11 @@ import { installJobControlSuspendSupport, type JobControlInterruptSupport, type JobControlSuspendSupport, -} from "../core/runtime/jobControl"; -import { shutdownSession } from "../core/runtime/shutdown"; -import { shouldUseMouseForApp, type ControllingTerminal } from "../core/runtime/terminal"; +} from "../core/process/jobControl"; +import { shutdownSession } from "../core/process/shutdown"; +import { shouldUseMouseForApp, type ControllingTerminal } from "../core/process/terminal"; import type { AppBootstrap } from "../core/bootstrap"; -import { resolveStartupUpdateNotice } from "../core/runtime/updateNotice"; +import { resolveStartupUpdateNotice } from "../core/process/updateNotice"; import { ReviewProducer } from "../app/review/producer"; import { createInitialSessionSnapshot, diff --git a/src/ui/staticDiffPager.ts b/src/ui/staticDiffPager.ts index 8450175a8..9b4e00a24 100644 --- a/src/ui/staticDiffPager.ts +++ b/src/ui/staticDiffPager.ts @@ -16,9 +16,9 @@ */ import { loadAppBootstrap } from "../core/changeset/loaders"; import { reviewEmptyDiffReason, type ReviewEmptyDiffReason } from "../core/review/document"; -import { DEFAULT_TAB_WIDTH } from "../core/invocation/tabWidth"; +import { DEFAULT_TAB_WIDTH } from "../core/run/tabWidth"; import type { DiffFile } from "../core/changeset/model"; -import type { CommonOptions } from "../core/invocation/commandInputs"; +import type { CommonOptions } from "../core/run/commandInputs"; import type { NamedCustomThemeConfig } from "../extension-api/types"; import { buildSplitRows, diff --git a/test/helpers/app-bootstrap.ts b/test/helpers/app-bootstrap.ts index b602b264d..b79a3744f 100644 --- a/test/helpers/app-bootstrap.ts +++ b/test/helpers/app-bootstrap.ts @@ -1,6 +1,6 @@ import type { AppBootstrap } from "../../src/core/bootstrap"; import type { DiffFile } from "../../src/core/changeset/model"; -import type { VcsDiffCommandInput, LayoutMode } from "../../src/core/invocation/commandInputs"; +import type { VcsDiffCommandInput, LayoutMode } from "../../src/core/run/commandInputs"; export function createTestVcsAppBootstrap({ agentSummary, diff --git a/website/src/content/docs/docs/reference/config.md b/website/src/content/docs/docs/reference/config.md index 47bf83140..75769e6b1 100644 --- a/website/src/content/docs/docs/reference/config.md +++ b/website/src/content/docs/docs/reference/config.md @@ -5,7 +5,7 @@ description: Exhaustive generated reference for Hunk TOML keys, defaults, aliase -Hunk reads TOML preferences from the user config and an optional repository config. This reference is generated from the same catalog that `src/core/invocation/config.ts` uses to parse preference keys. +Hunk reads TOML preferences from the user config and an optional repository config. This reference is generated from the same catalog that `src/core/run/config.ts` uses to parse preference keys. ## Resolution and scope From d4c9fafb5064c83c97b4243d52aec0e54f27c1e4 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 12:56:14 +0000 Subject: [PATCH 7/8] fix(bench): repoint highlight-cache-layers at the moved changeset model Merges main, whose new cache-layer benchmark (#791) landed importing the core/types shell that this branch melts; DiffFile now comes from its declaring module. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XcuayyxJrwQd9EHpuxNef1 --- benchmarks/highlight-cache-layers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/highlight-cache-layers.ts b/benchmarks/highlight-cache-layers.ts index 502cdc0e4..f77ad098b 100644 --- a/benchmarks/highlight-cache-layers.ts +++ b/benchmarks/highlight-cache-layers.ts @@ -1,7 +1,7 @@ // Compare a resident main-process cache hit with a worker-LRU revisit after main-cache eviction. import { performance } from "node:perf_hooks"; import { parseDiffFromFile } from "@pierre/diffs"; -import type { DiffFile } from "../src/core/types"; +import type { DiffFile } from "../src/core/changeset/model"; import { resolveTheme } from "../src/ui/themes"; import { disposeHighlightWorker } from "../src/ui/diff/worker/highlightWorkerClient"; import { prefetchHighlightedDiff } from "../src/ui/diff/useHighlightedDiff"; From 280c3ba3e80424b318b6c7b360dbe9f2f43b2c49 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 17:49:29 +0000 Subject: [PATCH 8/8] docs: fix module names the run/process rename missed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Greptile caught six references in docs/module-boundaries.md still naming invocation/ and runtime/ — the rename sweep matched path-like forms and skipped these prose mentions. Genuine English uses of "invocation" and "runtime" stay. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XcuayyxJrwQd9EHpuxNef1 --- docs/module-boundaries.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/module-boundaries.md b/docs/module-boundaries.md index fe871880c..732dc52b0 100644 --- a/docs/module-boundaries.md +++ b/docs/module-boundaries.md @@ -98,7 +98,7 @@ tab-width validation (`tabWidth`), reload eligibility (`inputReload`), and the C (`version`). The move is path-only; no exported symbol changed. Every one of the nine is **public**: each has production importers outside the module, so this -phase adds no `invocation-internals-stay-in-module` rule. Its value is the grouping plus +phase adds no `run-internals-stay-in-module` rule. Its value is the grouping plus extending the freeze: `core-leaves-never-reimport-types` now names `core/run/commandInputs.ts` in place of the old root path. Only `commandInputs` is a types-leaf — `config`, `experimental`, and `inputReload` import `core/types` legally, since @@ -123,10 +123,10 @@ teardown (`shutdown`), `.hunk`/VCS project-root discovery (`projectRoot`), the a written app-state file (`appStateFile`), the version-check notice built on it (`updateNotice`), and the startup-notice shape every tier reports through (`startupNotice`). The move is path-only; no exported symbol changed, and `core/types.ts` now re-exports `StartupNotice` from -`runtime/startupNotice` (a re-export nothing ever imported, deleted unused in phase 4). +`process/startupNotice` (a re-export nothing ever imported, deleted unused in phase 4). All eight are **public** — each has production importers outside the module — so this phase adds -no `runtime-internals-stay-in-module` rule; the grouping is its value. The audiences are worth +no `process-internals-stay-in-module` rule; the grouping is its value. The audiences are worth naming, because they are why these files never belonged at `core/*` root together with the review model: `terminal`, `jobControl`, `shutdown`, and `updateNotice` serve the interactive surface; `pager` serves the CLI entry and the startup plan; `projectRoot` and `appStateFile` serve the @@ -165,7 +165,7 @@ seam, since `extension-api-is-import-free` forbids `extension-api/types.ts` any Fan-in tells the story: 147 importing files became 28 (13 outside tests) — the review stream, the diff renderer, and the session surfaces never needed the bootstrap contract, only the changeset and command-input models they now name. `core/bootstrap.ts` imports downward into -`changeset/model`, `invocation/commandInputs`, `invocation/config`, `runtime/startupNotice`, +`changeset/model`, `run/commandInputs`, `run/config`, `process/startupNotice`, `theme/detection`, and `vcs/types`, and `core-leaves-stay-below-bootstrap` forbids the reverse edge from every module directory. One exception is carved out and named in the rule: `core/changeset/loaders.ts` returns an `AppBootstrap` from `loadAppBootstrap`, so it names the @@ -220,11 +220,11 @@ The tier rules now hold with no exceptions. Two follow-ups are worth doing next: 1. **Give `src/core` an interior.** _Done (phases 0–4, see Module interiors)._ Every group is a module directory — `review/`, `vcs/`, `theme/`, `watch/`, `patch/`, `changeset/`, - `invocation/`, `runtime/` — and `core/*` root is down to `bootstrap.ts`, `reviewDigest.ts`, + `run/`, `process/` — and `core/*` root is down to `bootstrap.ts`, `reviewDigest.ts`, and `liveComments.ts`, with no grab-bag left to import. What remains is per-file public surfaces for the modules that never got one: `changeset` has `changeset-internals-stay-in-module` and `review` has `review-reducer-is-module-internal`, - while `invocation`, `runtime`, `theme`, `vcs`, `watch`, and `patch` are still public in full + while `run`, `process`, `theme`, `vcs`, `watch`, and `patch` are still public in full because every file in them has an outside importer today. Two named follow-ups: move `loadAppBootstrap` out of `core/changeset/loaders.ts` into `src/app` (it is composition, and it is the one exception `core-leaves-stay-below-bootstrap` has to carve out), and split