refactor(ts-migration): Phase 11 batch 6 — agent and skill components

The fifteen files under `src/components/agents/` (including `skills/`)
and `src/components/skills/`. 15/15 erase byte-identically; bundle hash
unchanged.

Renaming raised 43 errors and 29 of them came from one thing: these
files carry 24 `/** @param {any} props */` annotations, one per
component, and JSDoc stops applying at the extension boundary. Without
them TypeScript infers every destructured prop as required, so a call
site passing seven of nine props is an error — which is how a file that
declared its props `any` ended up with fourteen complaints about missing
`className`. Restoring the author's own declaration as `: any` is not
blanket typing; it is the annotation that was already there, in the only
form that still works.

`Workspace` in `AgentCanvas` was the one component in that file its
author left without the hatch. It now matches its siblings.

The rest were five separate things:

  - `React.isValidElement(children)` no longer narrows enough to read
    `children.props.id`: React 19 types `ReactElement`'s props as
    `unknown`. `isValidElement<any>` says what the `cloneElement` call
    beneath it has always assumed. The migration plan predicted this
    site by name.
  - `useSkillSections(page, placement)` is called with one argument by
    `UiEditingProvider`, which its doc comment explicitly permits —
    "called with no placement it returns every section on the page". The
    parameter simply lacked its optional marker. The marker erases, so
    the emitted signature is unchanged.
  - `new Date(b.at) - new Date(a.at)` is valueOf coercion, which
    JavaScript performs and TypeScript refuses to describe. Cast rather
    than rewritten to `.getTime()`: that would change the emitted code,
    and this comparison orders the list.
  - `Object.values<any>` on a tally, the same inference gap as earlier
    batches, which also fixed a `ReactNode` complaint downstream of it.

All fifteen are linted under their new extensions, checked by name.

Measured against `446df7b`:

  typecheck   6 errors, down from 9; no new error anywhere
  lint        exit 0, 0 errors, 289 warnings, 15/15 linted by name
  npm test    1684/1691, the same 7 failures verbatim
  build       exit 0, identical bundle hash 74d17e2d…
  type erasure  72/72 byte-identical across Phase 11 so far

No baseline artifact touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8
This commit is contained in:
2026-09-18 15:32:14 +05:30
parent 446df7b37b
commit dde4ba62c6
15 changed files with 30 additions and 53 deletions

View File

@@ -43,7 +43,6 @@ import { SkillDetails } from './SkillDetails';
const OWLIVER = 'owliver';
const BOARD = 'board';
/** @param {any} props */
export function AgentSkillWorkspace({
fields,
customSkills = [],
@@ -55,7 +54,7 @@ export function AgentSkillWorkspace({
busy = false,
pendingId = null,
dirty = false,
}) {
}: any) {
const [kind, setKind] = React.useState(OWLIVER);
const [query, setQuery] = React.useState('');
const [boardQuery, setBoardQuery] = React.useState('');

View File

@@ -174,7 +174,6 @@ function StaticLeaf({ icon: Icon, label, detail = null }) {
);
}
/** @param {any} props */
export function AgentTree({
agentName,
agentIcon,
@@ -191,7 +190,7 @@ export function AgentTree({
onToggleBranch,
busy = false,
className,
}) {
}: any) {
const Glyph = agentIconFor(agentIcon);
return (

View File

@@ -159,11 +159,10 @@ function BoardCard({ entry, enabled, onToggle, onSurfaces, busy, attached = fals
);
}
/** @param {any} props */
export function BoardSkillList({
entries, agentPages = [], disabledIds, onToggle, busy = false, query, onQueryChange, total,
attachedIds = null, onAttach = null,
}) {
}: any) {
const searchId = React.useId();
const onSurfaces = React.useMemo(() => new Set(agentPages), [agentPages]);

View File

@@ -25,9 +25,9 @@ import { glyphForGroup } from './glyphs';
*/
/** @type {any} */
export const SkillCard = React.memo(/** @param {any} props */ ({
export const SkillCard = React.memo(({
entry, enabled, onOpen, onAddAgent, onTest, canTest = false, busy = false, isPending = false,
}) => {
}: any) => {
const Glyph = glyphForGroup(entry.group);
const samplePrompt = entry.suggestions?.[0]?.label;

View File

@@ -23,8 +23,7 @@ import { SkillCard } from './SkillCard';
* has, at every width, with no media query to get wrong.
*/
/** @param {any} props */
function CategoryFilter({ groups, value, onChange, total }) {
function CategoryFilter({ groups, value, onChange, total }: any) {
return (
<div
role="group"
@@ -60,7 +59,6 @@ function CategoryFilter({ groups, value, onChange, total }) {
);
}
/** @param {any} props */
export function SkillCatalog({
entries,
groups,
@@ -76,7 +74,7 @@ export function SkillCatalog({
testableIds,
busy = false,
pendingId = null,
}) {
}: any) {
const searchId = React.useId();
return (

View File

@@ -82,11 +82,10 @@ function TestState({ test, entryId }) {
* button needs the same `surface` this renders, and two copies of that would be
* two answers to "what am I about to enable".
*/
/** @param {any} props */
export function CapabilityBrief({
entry, attached, surface, onSurfaceChange, question, onQuestionChange,
canTest, target, onTest, test, busy = false, showTest = true,
}) {
}: any) {
const { shapes, described } = entry.capabilities;
return (
@@ -252,11 +251,10 @@ export function CapabilityBrief({
);
}
/** @param {any} props */
export function SkillDetails({
entry, open, onOpenChange, isEnabledOn, onToggle, busy = false,
fields = null, onRunTest = null, test = null,
}) {
}: any) {
/**
* The surface this would run on.
*

View File

@@ -45,8 +45,7 @@ const OPTIONS = [
export const supportedSurfaces = (type) =>
OPTIONS.filter((o) => o.supported(type)).map((o) => o.id);
/** @param {any} props */
export function SurfaceSelect({ type, value, onChange, name }) {
export function SurfaceSelect({ type, value, onChange, name }: any) {
return (
<div role="radiogroup" aria-label={`Run ${name} as`} className="space-y-1.5">
{OPTIONS.map((option) => {