fix(circular): skip type-only imports + break tui ↔ overlay-layout cycle
Some checks are pending
sf self-deploy / build, test, and publish server image (push) Waiting to run
sf self-deploy / upgrade vega source server (push) Blocked by required conditions
sf self-deploy / deploy test and probe (push) Blocked by required conditions
sf self-deploy / promote prod (push) Blocked by required conditions

Two changes (one walker, one real code):

1. scripts/check-circular-deps.mjs — skip type-only imports.
   `import type { X } from "..."` and `export type { X } from "..."`
   are erased by tsc at compile time and cannot cause runtime cycles.
   Walker now drops them, matching the precedent set by skipping
   dynamic `await import(...)`. Net effect on full-repo scan:
     before: 9 cycles
     after:  3 cycles (the 6 that disappeared were all `import type`
       false-positives — none were real runtime cycles).

2. packages/tui — break the last 2-file cycle.
   tui.ts and overlay-layout.ts had a real RUNTIME cycle:
     - tui.ts → overlay-layout.ts:  applyLineResets, compositeOverlays,
       extractCursorPosition, isOverlayVisible (4 fns)
     - overlay-layout.ts → tui.ts:  CURSOR_MARKER (1 const)
   Both files already imported `./overlay-types.ts` (no cycle there).
   Moved CURSOR_MARKER from tui.ts into overlay-types.ts and re-exported
   from tui.ts so existing `from "./tui.js"` call sites keep working.
   No behavior change.

Remaining cycles after both fixes (3 real-runtime ones, separate slices):
  - safety/autonomous-rollback chain (9 files, SF extension)
  - packages/coding-agent core mega-cycle (12 files)
  - (one more, see `npm run check:circular`)

These are foundational refactors worth their own commits, not bundled
into this one.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mikael Hugo 2026-05-18 00:28:53 +02:00
parent 4be963fdd1
commit 66309b235f
3 changed files with 18 additions and 8 deletions

View file

@ -12,7 +12,7 @@ import type {
} from "./overlay-types.js";
import { tryRender } from "./render-guard.js";
import { isImageLine } from "./terminal-image.js";
import { CURSOR_MARKER } from "./tui.js";
import { CURSOR_MARKER } from "./overlay-types.js";
import {
applyBackgroundToLine,
extractSegments,

View file

@ -1,7 +1,19 @@
/**
* Overlay sizing, anchoring, and handle types for layered TUI content.
*
* Also hosts CURSOR_MARKER (moved here from ./tui.ts to break the
* tui overlay-layout circular import both files already import
* this module, so it's the natural shared landing zone).
*/
/**
* Cursor position marker APC (Application Program Command) sequence.
* This is a zero-width escape sequence that terminals ignore.
* Components emit this at the cursor position when focused.
* TUI finds and strips this marker, then positions the hardware cursor there.
*/
export const CURSOR_MARKER = "\x1b_sf:c\x07";
/** Margin configuration for overlays */
export interface OverlayMargin {
top?: number;

View file

@ -83,13 +83,11 @@ export function isFocusable(
return component !== null && "focused" in component;
}
/**
* Cursor position marker - APC (Application Program Command) sequence.
* This is a zero-width escape sequence that terminals ignore.
* Components emit this at the cursor position when focused.
* TUI finds and strips this marker, then positions the hardware cursor there.
*/
export const CURSOR_MARKER = "\x1b_sf:c\x07";
// CURSOR_MARKER moved to ./overlay-types.ts to break the
// tui ↔ overlay-layout circular import. Re-exported here so
// existing call sites that import { CURSOR_MARKER } from "./tui.js"
// keep working.
export { CURSOR_MARKER } from "./overlay-types.js";
export type {
OverlayAnchor,