💥 Say where components come from with --include - #631

Merged
taras merged 6 commits into
mainfrom
agent/issue-271-includes
Aug 27, 2026
Merged

💥 Say where components come from with --include#631
taras merged 6 commits into
mainfrom
agent/issue-271-includes

Conversation

@taras

@tarastaras commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes#271.

Why

componentDirs named a thing the rest of the vocabulary already had a better
word for. The configured directories a document resolves components from are now
includes, and the flag that names one is --include.

This is a 💥 clean break, and a total one: nothing has been released that names
the old spelling, so no code in the repository mentions it either.

What changes

RetiredNow
DEFAULT_COMPONENT_DIRSDEFAULT_INCLUDES
componentDirs (programmatic)includes
componentDir (configliere field, CLI-private)include
--component-dir--include

Before:

$ xmd run doc.md --component-dir components

After:

$ xmd run doc.md --include components

The old flag is simply an option xmd does not define, handled exactly as any
other undefined option is. It gets no refusal, no alias and no special case,
because there is no caller to tell — see Intentionally unchanged.

“Component search path” and “component search directory” do not change. They
remain the names of the complete ordered resolution path and of one directory on
it. Includes name only the configured contribution to that path, so
componentSearchPath() keeps its name and the prose was reviewed occurrence by
occurrence rather than replaced.

How it works

argv → --include → config.include → core includes → selectComponent → search path

The CLI keeps two spellings on purpose. runConfig.include,
testConfig.include and DocumentConfig.include are singular because
configliere derives --include from the field name; everything at the
programmatic boundary is plural — ExecuteSettings.includes,
SelectOptions.includes, InspectComponentOptions.includes,
TestingHostSettings.includes. runDocument maps one to the other. No custom
argv parsing was added: configliere's existing array field already gives ordered
repeats that replace the default.

Review guide

Start with:packages/core/src/components/select.ts

Then review:

  1. packages/core/mod.ts, execute.ts, inspect.ts — the public surface
  2. packages/cli/src/cli.ts — the schemas and the singular/plural boundary
  3. packages/core/src/execution-request.ts — the middleware snapshot still
    detaches and freezes
  4. Everything else — a mechanical identifier rename

What must stay true

  • No occurrence of the retired names survives — checked by
    git grep -nE 'componentDirs|componentDir|DEFAULT_COMPONENT_DIRS|--component-dir' -- .
    returning nothing. That grep is the whole of the absence claim; no test
    restates it.
  • Absence uses the defaults; includes: [] uses none — enforced by
    options.includes ?? DEFAULT_INCLUDES, checked by CR37.
  • A workflow's configured contribution stays empty — enforced by
    include: [] at workflow assembly, checked by workflow-component-bundle and
    workflow-bundle.
  • Directory targets keep document directory, target root, configured includes,
    first duplicate wins
    — enforced by componentSearchPath(), checked by DT32.

How to verify it

  • CR36 proves DEFAULT_INCLUDES is ["components", "."] and that mod.ts
    exports it.
  • CR37 proves ?? semantics and that the default array is copied, not
    shared. Fails if || is used or [] is widened to the defaults.
  • IE25 proves repeated --include are searched in caller order and that
    explicit values replace rather than extend the defaults: a same-named
    component sits on the default path and loses.
  • DT32 proves directory-target composition directly, with one duplicate
    spelled exactly and one spelled differently but resolving the same.
  • DT24/DT25 retain end-to-end colocated resolution.
  • The nested-host case proves a child <Execution host="run"> resolves a
    component only through the outer command's --include, with the bare run as
    the negative control.
  • CH2/CH3 prove both help surfaces list --include.

Scope

Included

  • The rename across core, CLI, every package consumer, deno.json tasks, the
    CI/review/repo-analysis workflows, smoke scripts, specs, architecture and site
    copy — one commit's worth of change, because either half alone leaves main
    contradicting its own API or unable to run its own commands.

Intentionally unchanged

  • The CLI's handling of options it does not define. The parser stops at the
    first token it does not recognize rather than rejecting it, so the retired
    flag is dropped in silence like any typo. An earlier revision of this branch
    added a refusal for it; that was removed once it was established there are no
    users to migrate. Refusing unknown options in general is a separate concern
    and not this PR's.
  • Tests asserting the old names are absent. There are none. A rename with no
    deprecation leaves nothing that could still answer to the old spelling, and a
    test naming it — necessarily by assembling the string, since the audit forbids
    the literal — would reintroduce the very name it checks for. The git grep
    audit above is the single place absence is claimed.
  • Resolution tiers, candidate order, precedence, the searched diagnostic, the
    unresolved message, journal shape and replay.
  • componentSearchPath() and the words “component search path” and “component
    search directory”.
  • Richer and embedded default components — still Embed built-in components in the xmd binary #67 and Embed core/components in the xmd binary with a default component search path #83.
  • specs/release-process-spec.md: no release configuration changed.
  • Lockfiles, dependencies and generated package output.

Generated or mechanical changes

  • The bulk of the 62 files is a mechanical identifier rename with no intended
    behavior change. The parts that are not:
    packages/core/src/components/select.ts, execute.ts, inspect.ts,
    execution-request.ts, mod.ts, packages/cli/src/cli.ts,
    packages/cli/src/testing-host.ts, and the regressions in
    component-registration.test.ts, inline-cli.test.ts, test-target.test.ts,
    testing-execution-host.test.ts.

Risks and limitations

  • The principal risk is a missed first-party occurrence rather than behavior.
    The zero-match audit is the controlling evidence and it is clean.
  • Anyone who has the old flag in a script gets no diagnostic — the run searches
    the default path instead. Accepted deliberately: there is no released binary
    naming it.
  • ✨ Compose and certify the supervised adversarial implementation workflow #181 is based on an older main and still adds the old spellings. It is
    not stacked here, and must adopt --include while rebasing after this lands.
  • Recovery: revert. No persisted data, remote state or compatibility state is
    migrated.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Rename the configured component-search-path surface: `includes` at every
programmatic boundary, `--include` as the repeatable CLI flag, and
`DEFAULT_INCLUDES` for the exported `["components", "."]` default.
This is a clean break. No alias, no deprecation, no compatibility parser:
the typed API no longer declares the former member, and an untyped object
carrying it is not read.
"Component search path" and "component search directory" stay the names of
the complete ordered resolution path and of one directory on it. Includes
name only the configured contribution to that path.
Resolution order, diagnostics, the `searched` list, journal shape, the
workflow's empty contribution and directory-target composition are
unchanged.
Refs #271
The argument parser ignores options it does not define rather than
rejecting them, so `--component-dir` was silently dropped: a run searched
the defaults and either failed somewhere unrelated or succeeded while
ignoring where the caller said components come from.
`xmd run` and `xmd test` now refuse it by name, before the run resolves
its props and before a test target is discovered. Both spellings are
refused — the separated value and the `=` form — and tokens after `--`
still belong to the document.
This is a refusal, not an alias: no value is mapped, and no generic
unknown-option policy is introduced. The retired spelling is assembled
from fragments at its one remaining site, so the migration audit stays
empty.
Refs #271
A directory can be named after the retired flag, and naming a directory
is what --include is for. Scanning raw argv read that value as an option
and refused the run — the one caller using the new option correctly.
The finder now reads the parser's leftovers, where a token consumed as a
value no longer appears. The end-of-options separator survives into those
leftovers, so a retired spelling after -- still belongs to the document.
Refs #271
@github-actions

github-actionsBot commented Aug 27, 2026

Copy link
Copy Markdown

PR #631: 💥 Say where components come from with --include

62 files, +320 / -220

Scope

🟡 540 lines changed. PRs under 400 receive more thorough review.

🟡 62 files changed. Are all changes related?

🟡 Changes span 15 directories.

🟡 PR mixes config and source changes.

Structural

Oxlint structural signals:

  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unused-vars ×4: packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
  • no-empty-function ×1: packages/cli/src/cli.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts

Static Analysis

Oxlint: 40 diagnostics across 6 files (12 rules)
Density: 0.125 violations/added-line

no-unsafe-type-assertion (12): packages/cli/src/cli.ts, packages/core/src/invocation-identity.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unused-vars (4): packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
consistent-return (4): packages/core/src/inspect.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts
no-console (3): packages/cli/src/cli.ts
no-shadow (3): packages/core/src/generated-xmd.ts, packages/core/src/execute.ts
no-array-sort (2): packages/web/tests/component-support.ts, packages/core/src/execute.ts
no-unnecessary-type-conversion (2): packages/web/tests/component-support.ts
no-floating-promises (2): packages/cli/src/cli.ts, packages/core/src/execute.ts
no-empty-function (1): packages/cli/src/cli.ts
no-base-to-string (1): packages/web/tests/component-support.ts
unbound-method (1): packages/core/src/execute.ts

Correctness

No extraneous code patterns detected.

`deno fmt` owns `site/`, and the option name lost eight characters, so the
line it was wrapped for now fits differently.
Nothing has been released that names the old flag, so there is no caller
to tell. The refusal existed only to answer one, and it cost a constant
assembled from fragments to keep the migration audit empty — a string the
one place that handled it could not be searched for.
The old spelling is now an option xmd does not define, exactly like any
other typo, and no code in the repository mentions it.
Refs #271
CR35 and CR38 proved the retired option was gone from the typed surface
and unread at runtime, and CR36 proved the retired export was gone. With
the old spelling deleted rather than deprecated there is nothing to be
absent from: the audit already says no source mentions it, and a test
that spells it from fragments only reintroduces the name it checks for.
CR36 keeps what is a claim about the present surface — the default value,
and that core exports it.
Refs #271
@taras
taras marked this pull request as ready for review August 27, 2026 13:16
@taras
taras merged commit 787ebcb into mainAug 27, 2026
30 checks passed
@taras
taras deleted the agent/issue-271-includes branch August 27, 2026 13:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💥 Rename componentDirs to includes

1 participant

@taras
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

💥 Say where components come from with --include - #631

Merged
taras merged 6 commits into
mainfrom
agent/issue-271-includes
Aug 27, 2026
Merged

💥 Say where components come from with --include#631
taras merged 6 commits into
mainfrom
agent/issue-271-includes

Conversation

@taras

@tarastaras commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes#271.

Why

componentDirs named a thing the rest of the vocabulary already had a better
word for. The configured directories a document resolves components from are now
includes, and the flag that names one is --include.

This is a 💥 clean break, and a total one: nothing has been released that names
the old spelling, so no code in the repository mentions it either.

What changes

RetiredNow
DEFAULT_COMPONENT_DIRSDEFAULT_INCLUDES
componentDirs (programmatic)includes
componentDir (configliere field, CLI-private)include
--component-dir--include

Before:

$ xmd run doc.md --component-dir components

After:

$ xmd run doc.md --include components

The old flag is simply an option xmd does not define, handled exactly as any
other undefined option is. It gets no refusal, no alias and no special case,
because there is no caller to tell — see Intentionally unchanged.

“Component search path” and “component search directory” do not change. They
remain the names of the complete ordered resolution path and of one directory on
it. Includes name only the configured contribution to that path, so
componentSearchPath() keeps its name and the prose was reviewed occurrence by
occurrence rather than replaced.

How it works

argv → --include → config.include → core includes → selectComponent → search path

The CLI keeps two spellings on purpose. runConfig.include,
testConfig.include and DocumentConfig.include are singular because
configliere derives --include from the field name; everything at the
programmatic boundary is plural — ExecuteSettings.includes,
SelectOptions.includes, InspectComponentOptions.includes,
TestingHostSettings.includes. runDocument maps one to the other. No custom
argv parsing was added: configliere's existing array field already gives ordered
repeats that replace the default.

Review guide

Start with:packages/core/src/components/select.ts

Then review:

  1. packages/core/mod.ts, execute.ts, inspect.ts — the public surface
  2. packages/cli/src/cli.ts — the schemas and the singular/plural boundary
  3. packages/core/src/execution-request.ts — the middleware snapshot still
    detaches and freezes
  4. Everything else — a mechanical identifier rename

What must stay true

  • No occurrence of the retired names survives — checked by
    git grep -nE 'componentDirs|componentDir|DEFAULT_COMPONENT_DIRS|--component-dir' -- .
    returning nothing. That grep is the whole of the absence claim; no test
    restates it.
  • Absence uses the defaults; includes: [] uses none — enforced by
    options.includes ?? DEFAULT_INCLUDES, checked by CR37.
  • A workflow's configured contribution stays empty — enforced by
    include: [] at workflow assembly, checked by workflow-component-bundle and
    workflow-bundle.
  • Directory targets keep document directory, target root, configured includes,
    first duplicate wins
    — enforced by componentSearchPath(), checked by DT32.

How to verify it

  • CR36 proves DEFAULT_INCLUDES is ["components", "."] and that mod.ts
    exports it.
  • CR37 proves ?? semantics and that the default array is copied, not
    shared. Fails if || is used or [] is widened to the defaults.
  • IE25 proves repeated --include are searched in caller order and that
    explicit values replace rather than extend the defaults: a same-named
    component sits on the default path and loses.
  • DT32 proves directory-target composition directly, with one duplicate
    spelled exactly and one spelled differently but resolving the same.
  • DT24/DT25 retain end-to-end colocated resolution.
  • The nested-host case proves a child <Execution host="run"> resolves a
    component only through the outer command's --include, with the bare run as
    the negative control.
  • CH2/CH3 prove both help surfaces list --include.

Scope

Included

  • The rename across core, CLI, every package consumer, deno.json tasks, the
    CI/review/repo-analysis workflows, smoke scripts, specs, architecture and site
    copy — one commit's worth of change, because either half alone leaves main
    contradicting its own API or unable to run its own commands.

Intentionally unchanged

  • The CLI's handling of options it does not define. The parser stops at the
    first token it does not recognize rather than rejecting it, so the retired
    flag is dropped in silence like any typo. An earlier revision of this branch
    added a refusal for it; that was removed once it was established there are no
    users to migrate. Refusing unknown options in general is a separate concern
    and not this PR's.
  • Tests asserting the old names are absent. There are none. A rename with no
    deprecation leaves nothing that could still answer to the old spelling, and a
    test naming it — necessarily by assembling the string, since the audit forbids
    the literal — would reintroduce the very name it checks for. The git grep
    audit above is the single place absence is claimed.
  • Resolution tiers, candidate order, precedence, the searched diagnostic, the
    unresolved message, journal shape and replay.
  • componentSearchPath() and the words “component search path” and “component
    search directory”.
  • Richer and embedded default components — still Embed built-in components in the xmd binary #67 and Embed core/components in the xmd binary with a default component search path #83.
  • specs/release-process-spec.md: no release configuration changed.
  • Lockfiles, dependencies and generated package output.

Generated or mechanical changes

  • The bulk of the 62 files is a mechanical identifier rename with no intended
    behavior change. The parts that are not:
    packages/core/src/components/select.ts, execute.ts, inspect.ts,
    execution-request.ts, mod.ts, packages/cli/src/cli.ts,
    packages/cli/src/testing-host.ts, and the regressions in
    component-registration.test.ts, inline-cli.test.ts, test-target.test.ts,
    testing-execution-host.test.ts.

Risks and limitations

  • The principal risk is a missed first-party occurrence rather than behavior.
    The zero-match audit is the controlling evidence and it is clean.
  • Anyone who has the old flag in a script gets no diagnostic — the run searches
    the default path instead. Accepted deliberately: there is no released binary
    naming it.
  • ✨ Compose and certify the supervised adversarial implementation workflow #181 is based on an older main and still adds the old spellings. It is
    not stacked here, and must adopt --include while rebasing after this lands.
  • Recovery: revert. No persisted data, remote state or compatibility state is
    migrated.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Rename the configured component-search-path surface: `includes` at every
programmatic boundary, `--include` as the repeatable CLI flag, and
`DEFAULT_INCLUDES` for the exported `["components", "."]` default.
This is a clean break. No alias, no deprecation, no compatibility parser:
the typed API no longer declares the former member, and an untyped object
carrying it is not read.
"Component search path" and "component search directory" stay the names of
the complete ordered resolution path and of one directory on it. Includes
name only the configured contribution to that path.
Resolution order, diagnostics, the `searched` list, journal shape, the
workflow's empty contribution and directory-target composition are
unchanged.
Refs #271
The argument parser ignores options it does not define rather than
rejecting them, so `--component-dir` was silently dropped: a run searched
the defaults and either failed somewhere unrelated or succeeded while
ignoring where the caller said components come from.
`xmd run` and `xmd test` now refuse it by name, before the run resolves
its props and before a test target is discovered. Both spellings are
refused — the separated value and the `=` form — and tokens after `--`
still belong to the document.
This is a refusal, not an alias: no value is mapped, and no generic
unknown-option policy is introduced. The retired spelling is assembled
from fragments at its one remaining site, so the migration audit stays
empty.
Refs #271
A directory can be named after the retired flag, and naming a directory
is what --include is for. Scanning raw argv read that value as an option
and refused the run — the one caller using the new option correctly.
The finder now reads the parser's leftovers, where a token consumed as a
value no longer appears. The end-of-options separator survives into those
leftovers, so a retired spelling after -- still belongs to the document.
Refs #271
@github-actions

github-actionsBot commented Aug 27, 2026

Copy link
Copy Markdown

PR #631: 💥 Say where components come from with --include

62 files, +320 / -220

Scope

🟡 540 lines changed. PRs under 400 receive more thorough review.

🟡 62 files changed. Are all changes related?

🟡 Changes span 15 directories.

🟡 PR mixes config and source changes.

Structural

Oxlint structural signals:

  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unused-vars ×4: packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
  • no-empty-function ×1: packages/cli/src/cli.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts

Static Analysis

Oxlint: 40 diagnostics across 6 files (12 rules)
Density: 0.125 violations/added-line

no-unsafe-type-assertion (12): packages/cli/src/cli.ts, packages/core/src/invocation-identity.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unused-vars (4): packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
consistent-return (4): packages/core/src/inspect.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts
no-console (3): packages/cli/src/cli.ts
no-shadow (3): packages/core/src/generated-xmd.ts, packages/core/src/execute.ts
no-array-sort (2): packages/web/tests/component-support.ts, packages/core/src/execute.ts
no-unnecessary-type-conversion (2): packages/web/tests/component-support.ts
no-floating-promises (2): packages/cli/src/cli.ts, packages/core/src/execute.ts
no-empty-function (1): packages/cli/src/cli.ts
no-base-to-string (1): packages/web/tests/component-support.ts
unbound-method (1): packages/core/src/execute.ts

Correctness

No extraneous code patterns detected.

`deno fmt` owns `site/`, and the option name lost eight characters, so the
line it was wrapped for now fits differently.
Nothing has been released that names the old flag, so there is no caller
to tell. The refusal existed only to answer one, and it cost a constant
assembled from fragments to keep the migration audit empty — a string the
one place that handled it could not be searched for.
The old spelling is now an option xmd does not define, exactly like any
other typo, and no code in the repository mentions it.
Refs #271
CR35 and CR38 proved the retired option was gone from the typed surface
and unread at runtime, and CR36 proved the retired export was gone. With
the old spelling deleted rather than deprecated there is nothing to be
absent from: the audit already says no source mentions it, and a test
that spells it from fragments only reintroduces the name it checks for.
CR36 keeps what is a claim about the present surface — the default value,
and that core exports it.
Refs #271
@taras
taras marked this pull request as ready for review August 27, 2026 13:16
@taras
taras merged commit 787ebcb into mainAug 27, 2026
30 checks passed
@taras
taras deleted the agent/issue-271-includes branch August 27, 2026 13:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💥 Rename componentDirs to includes

1 participant

@taras
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

💥 Say where components come from with --include - #631

Merged
taras merged 6 commits into
mainfrom
agent/issue-271-includes
Aug 27, 2026
Merged

💥 Say where components come from with --include#631
taras merged 6 commits into
mainfrom
agent/issue-271-includes

Conversation

@taras

@tarastaras commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes#271.

Why

componentDirs named a thing the rest of the vocabulary already had a better
word for. The configured directories a document resolves components from are now
includes, and the flag that names one is --include.

This is a 💥 clean break, and a total one: nothing has been released that names
the old spelling, so no code in the repository mentions it either.

What changes

RetiredNow
DEFAULT_COMPONENT_DIRSDEFAULT_INCLUDES
componentDirs (programmatic)includes
componentDir (configliere field, CLI-private)include
--component-dir--include

Before:

$ xmd run doc.md --component-dir components

After:

$ xmd run doc.md --include components

The old flag is simply an option xmd does not define, handled exactly as any
other undefined option is. It gets no refusal, no alias and no special case,
because there is no caller to tell — see Intentionally unchanged.

“Component search path” and “component search directory” do not change. They
remain the names of the complete ordered resolution path and of one directory on
it. Includes name only the configured contribution to that path, so
componentSearchPath() keeps its name and the prose was reviewed occurrence by
occurrence rather than replaced.

How it works

argv → --include → config.include → core includes → selectComponent → search path

The CLI keeps two spellings on purpose. runConfig.include,
testConfig.include and DocumentConfig.include are singular because
configliere derives --include from the field name; everything at the
programmatic boundary is plural — ExecuteSettings.includes,
SelectOptions.includes, InspectComponentOptions.includes,
TestingHostSettings.includes. runDocument maps one to the other. No custom
argv parsing was added: configliere's existing array field already gives ordered
repeats that replace the default.

Review guide

Start with:packages/core/src/components/select.ts

Then review:

  1. packages/core/mod.ts, execute.ts, inspect.ts — the public surface
  2. packages/cli/src/cli.ts — the schemas and the singular/plural boundary
  3. packages/core/src/execution-request.ts — the middleware snapshot still
    detaches and freezes
  4. Everything else — a mechanical identifier rename

What must stay true

  • No occurrence of the retired names survives — checked by
    git grep -nE 'componentDirs|componentDir|DEFAULT_COMPONENT_DIRS|--component-dir' -- .
    returning nothing. That grep is the whole of the absence claim; no test
    restates it.
  • Absence uses the defaults; includes: [] uses none — enforced by
    options.includes ?? DEFAULT_INCLUDES, checked by CR37.
  • A workflow's configured contribution stays empty — enforced by
    include: [] at workflow assembly, checked by workflow-component-bundle and
    workflow-bundle.
  • Directory targets keep document directory, target root, configured includes,
    first duplicate wins
    — enforced by componentSearchPath(), checked by DT32.

How to verify it

  • CR36 proves DEFAULT_INCLUDES is ["components", "."] and that mod.ts
    exports it.
  • CR37 proves ?? semantics and that the default array is copied, not
    shared. Fails if || is used or [] is widened to the defaults.
  • IE25 proves repeated --include are searched in caller order and that
    explicit values replace rather than extend the defaults: a same-named
    component sits on the default path and loses.
  • DT32 proves directory-target composition directly, with one duplicate
    spelled exactly and one spelled differently but resolving the same.
  • DT24/DT25 retain end-to-end colocated resolution.
  • The nested-host case proves a child <Execution host="run"> resolves a
    component only through the outer command's --include, with the bare run as
    the negative control.
  • CH2/CH3 prove both help surfaces list --include.

Scope

Included

  • The rename across core, CLI, every package consumer, deno.json tasks, the
    CI/review/repo-analysis workflows, smoke scripts, specs, architecture and site
    copy — one commit's worth of change, because either half alone leaves main
    contradicting its own API or unable to run its own commands.

Intentionally unchanged

  • The CLI's handling of options it does not define. The parser stops at the
    first token it does not recognize rather than rejecting it, so the retired
    flag is dropped in silence like any typo. An earlier revision of this branch
    added a refusal for it; that was removed once it was established there are no
    users to migrate. Refusing unknown options in general is a separate concern
    and not this PR's.
  • Tests asserting the old names are absent. There are none. A rename with no
    deprecation leaves nothing that could still answer to the old spelling, and a
    test naming it — necessarily by assembling the string, since the audit forbids
    the literal — would reintroduce the very name it checks for. The git grep
    audit above is the single place absence is claimed.
  • Resolution tiers, candidate order, precedence, the searched diagnostic, the
    unresolved message, journal shape and replay.
  • componentSearchPath() and the words “component search path” and “component
    search directory”.
  • Richer and embedded default components — still Embed built-in components in the xmd binary #67 and Embed core/components in the xmd binary with a default component search path #83.
  • specs/release-process-spec.md: no release configuration changed.
  • Lockfiles, dependencies and generated package output.

Generated or mechanical changes

  • The bulk of the 62 files is a mechanical identifier rename with no intended
    behavior change. The parts that are not:
    packages/core/src/components/select.ts, execute.ts, inspect.ts,
    execution-request.ts, mod.ts, packages/cli/src/cli.ts,
    packages/cli/src/testing-host.ts, and the regressions in
    component-registration.test.ts, inline-cli.test.ts, test-target.test.ts,
    testing-execution-host.test.ts.

Risks and limitations

  • The principal risk is a missed first-party occurrence rather than behavior.
    The zero-match audit is the controlling evidence and it is clean.
  • Anyone who has the old flag in a script gets no diagnostic — the run searches
    the default path instead. Accepted deliberately: there is no released binary
    naming it.
  • ✨ Compose and certify the supervised adversarial implementation workflow #181 is based on an older main and still adds the old spellings. It is
    not stacked here, and must adopt --include while rebasing after this lands.
  • Recovery: revert. No persisted data, remote state or compatibility state is
    migrated.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Rename the configured component-search-path surface: `includes` at every
programmatic boundary, `--include` as the repeatable CLI flag, and
`DEFAULT_INCLUDES` for the exported `["components", "."]` default.
This is a clean break. No alias, no deprecation, no compatibility parser:
the typed API no longer declares the former member, and an untyped object
carrying it is not read.
"Component search path" and "component search directory" stay the names of
the complete ordered resolution path and of one directory on it. Includes
name only the configured contribution to that path.
Resolution order, diagnostics, the `searched` list, journal shape, the
workflow's empty contribution and directory-target composition are
unchanged.
Refs #271
The argument parser ignores options it does not define rather than
rejecting them, so `--component-dir` was silently dropped: a run searched
the defaults and either failed somewhere unrelated or succeeded while
ignoring where the caller said components come from.
`xmd run` and `xmd test` now refuse it by name, before the run resolves
its props and before a test target is discovered. Both spellings are
refused — the separated value and the `=` form — and tokens after `--`
still belong to the document.
This is a refusal, not an alias: no value is mapped, and no generic
unknown-option policy is introduced. The retired spelling is assembled
from fragments at its one remaining site, so the migration audit stays
empty.
Refs #271
A directory can be named after the retired flag, and naming a directory
is what --include is for. Scanning raw argv read that value as an option
and refused the run — the one caller using the new option correctly.
The finder now reads the parser's leftovers, where a token consumed as a
value no longer appears. The end-of-options separator survives into those
leftovers, so a retired spelling after -- still belongs to the document.
Refs #271
@github-actions

github-actionsBot commented Aug 27, 2026

Copy link
Copy Markdown

PR #631: 💥 Say where components come from with --include

62 files, +320 / -220

Scope

🟡 540 lines changed. PRs under 400 receive more thorough review.

🟡 62 files changed. Are all changes related?

🟡 Changes span 15 directories.

🟡 PR mixes config and source changes.

Structural

Oxlint structural signals:

  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unused-vars ×4: packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
  • no-empty-function ×1: packages/cli/src/cli.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts

Static Analysis

Oxlint: 40 diagnostics across 6 files (12 rules)
Density: 0.125 violations/added-line

no-unsafe-type-assertion (12): packages/cli/src/cli.ts, packages/core/src/invocation-identity.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unused-vars (4): packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
consistent-return (4): packages/core/src/inspect.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts
no-console (3): packages/cli/src/cli.ts
no-shadow (3): packages/core/src/generated-xmd.ts, packages/core/src/execute.ts
no-array-sort (2): packages/web/tests/component-support.ts, packages/core/src/execute.ts
no-unnecessary-type-conversion (2): packages/web/tests/component-support.ts
no-floating-promises (2): packages/cli/src/cli.ts, packages/core/src/execute.ts
no-empty-function (1): packages/cli/src/cli.ts
no-base-to-string (1): packages/web/tests/component-support.ts
unbound-method (1): packages/core/src/execute.ts

Correctness

No extraneous code patterns detected.

`deno fmt` owns `site/`, and the option name lost eight characters, so the
line it was wrapped for now fits differently.
Nothing has been released that names the old flag, so there is no caller
to tell. The refusal existed only to answer one, and it cost a constant
assembled from fragments to keep the migration audit empty — a string the
one place that handled it could not be searched for.
The old spelling is now an option xmd does not define, exactly like any
other typo, and no code in the repository mentions it.
Refs #271
CR35 and CR38 proved the retired option was gone from the typed surface
and unread at runtime, and CR36 proved the retired export was gone. With
the old spelling deleted rather than deprecated there is nothing to be
absent from: the audit already says no source mentions it, and a test
that spells it from fragments only reintroduces the name it checks for.
CR36 keeps what is a claim about the present surface — the default value,
and that core exports it.
Refs #271
@taras
taras marked this pull request as ready for review August 27, 2026 13:16
@taras
taras merged commit 787ebcb into mainAug 27, 2026
30 checks passed
@taras
taras deleted the agent/issue-271-includes branch August 27, 2026 13:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💥 Rename componentDirs to includes

1 participant

@taras
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

💥 Say where components come from with --include - #631

Merged
taras merged 6 commits into
mainfrom
agent/issue-271-includes
Aug 27, 2026
Merged

💥 Say where components come from with --include#631
taras merged 6 commits into
mainfrom
agent/issue-271-includes

Conversation

@taras

@tarastaras commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes#271.

Why

componentDirs named a thing the rest of the vocabulary already had a better
word for. The configured directories a document resolves components from are now
includes, and the flag that names one is --include.

This is a 💥 clean break, and a total one: nothing has been released that names
the old spelling, so no code in the repository mentions it either.

What changes

RetiredNow
DEFAULT_COMPONENT_DIRSDEFAULT_INCLUDES
componentDirs (programmatic)includes
componentDir (configliere field, CLI-private)include
--component-dir--include

Before:

$ xmd run doc.md --component-dir components

After:

$ xmd run doc.md --include components

The old flag is simply an option xmd does not define, handled exactly as any
other undefined option is. It gets no refusal, no alias and no special case,
because there is no caller to tell — see Intentionally unchanged.

“Component search path” and “component search directory” do not change. They
remain the names of the complete ordered resolution path and of one directory on
it. Includes name only the configured contribution to that path, so
componentSearchPath() keeps its name and the prose was reviewed occurrence by
occurrence rather than replaced.

How it works

argv → --include → config.include → core includes → selectComponent → search path

The CLI keeps two spellings on purpose. runConfig.include,
testConfig.include and DocumentConfig.include are singular because
configliere derives --include from the field name; everything at the
programmatic boundary is plural — ExecuteSettings.includes,
SelectOptions.includes, InspectComponentOptions.includes,
TestingHostSettings.includes. runDocument maps one to the other. No custom
argv parsing was added: configliere's existing array field already gives ordered
repeats that replace the default.

Review guide

Start with:packages/core/src/components/select.ts

Then review:

  1. packages/core/mod.ts, execute.ts, inspect.ts — the public surface
  2. packages/cli/src/cli.ts — the schemas and the singular/plural boundary
  3. packages/core/src/execution-request.ts — the middleware snapshot still
    detaches and freezes
  4. Everything else — a mechanical identifier rename

What must stay true

  • No occurrence of the retired names survives — checked by
    git grep -nE 'componentDirs|componentDir|DEFAULT_COMPONENT_DIRS|--component-dir' -- .
    returning nothing. That grep is the whole of the absence claim; no test
    restates it.
  • Absence uses the defaults; includes: [] uses none — enforced by
    options.includes ?? DEFAULT_INCLUDES, checked by CR37.
  • A workflow's configured contribution stays empty — enforced by
    include: [] at workflow assembly, checked by workflow-component-bundle and
    workflow-bundle.
  • Directory targets keep document directory, target root, configured includes,
    first duplicate wins
    — enforced by componentSearchPath(), checked by DT32.

How to verify it

  • CR36 proves DEFAULT_INCLUDES is ["components", "."] and that mod.ts
    exports it.
  • CR37 proves ?? semantics and that the default array is copied, not
    shared. Fails if || is used or [] is widened to the defaults.
  • IE25 proves repeated --include are searched in caller order and that
    explicit values replace rather than extend the defaults: a same-named
    component sits on the default path and loses.
  • DT32 proves directory-target composition directly, with one duplicate
    spelled exactly and one spelled differently but resolving the same.
  • DT24/DT25 retain end-to-end colocated resolution.
  • The nested-host case proves a child <Execution host="run"> resolves a
    component only through the outer command's --include, with the bare run as
    the negative control.
  • CH2/CH3 prove both help surfaces list --include.

Scope

Included

  • The rename across core, CLI, every package consumer, deno.json tasks, the
    CI/review/repo-analysis workflows, smoke scripts, specs, architecture and site
    copy — one commit's worth of change, because either half alone leaves main
    contradicting its own API or unable to run its own commands.

Intentionally unchanged

  • The CLI's handling of options it does not define. The parser stops at the
    first token it does not recognize rather than rejecting it, so the retired
    flag is dropped in silence like any typo. An earlier revision of this branch
    added a refusal for it; that was removed once it was established there are no
    users to migrate. Refusing unknown options in general is a separate concern
    and not this PR's.
  • Tests asserting the old names are absent. There are none. A rename with no
    deprecation leaves nothing that could still answer to the old spelling, and a
    test naming it — necessarily by assembling the string, since the audit forbids
    the literal — would reintroduce the very name it checks for. The git grep
    audit above is the single place absence is claimed.
  • Resolution tiers, candidate order, precedence, the searched diagnostic, the
    unresolved message, journal shape and replay.
  • componentSearchPath() and the words “component search path” and “component
    search directory”.
  • Richer and embedded default components — still Embed built-in components in the xmd binary #67 and Embed core/components in the xmd binary with a default component search path #83.
  • specs/release-process-spec.md: no release configuration changed.
  • Lockfiles, dependencies and generated package output.

Generated or mechanical changes

  • The bulk of the 62 files is a mechanical identifier rename with no intended
    behavior change. The parts that are not:
    packages/core/src/components/select.ts, execute.ts, inspect.ts,
    execution-request.ts, mod.ts, packages/cli/src/cli.ts,
    packages/cli/src/testing-host.ts, and the regressions in
    component-registration.test.ts, inline-cli.test.ts, test-target.test.ts,
    testing-execution-host.test.ts.

Risks and limitations

  • The principal risk is a missed first-party occurrence rather than behavior.
    The zero-match audit is the controlling evidence and it is clean.
  • Anyone who has the old flag in a script gets no diagnostic — the run searches
    the default path instead. Accepted deliberately: there is no released binary
    naming it.
  • ✨ Compose and certify the supervised adversarial implementation workflow #181 is based on an older main and still adds the old spellings. It is
    not stacked here, and must adopt --include while rebasing after this lands.
  • Recovery: revert. No persisted data, remote state or compatibility state is
    migrated.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Rename the configured component-search-path surface: `includes` at every
programmatic boundary, `--include` as the repeatable CLI flag, and
`DEFAULT_INCLUDES` for the exported `["components", "."]` default.
This is a clean break. No alias, no deprecation, no compatibility parser:
the typed API no longer declares the former member, and an untyped object
carrying it is not read.
"Component search path" and "component search directory" stay the names of
the complete ordered resolution path and of one directory on it. Includes
name only the configured contribution to that path.
Resolution order, diagnostics, the `searched` list, journal shape, the
workflow's empty contribution and directory-target composition are
unchanged.
Refs #271
The argument parser ignores options it does not define rather than
rejecting them, so `--component-dir` was silently dropped: a run searched
the defaults and either failed somewhere unrelated or succeeded while
ignoring where the caller said components come from.
`xmd run` and `xmd test` now refuse it by name, before the run resolves
its props and before a test target is discovered. Both spellings are
refused — the separated value and the `=` form — and tokens after `--`
still belong to the document.
This is a refusal, not an alias: no value is mapped, and no generic
unknown-option policy is introduced. The retired spelling is assembled
from fragments at its one remaining site, so the migration audit stays
empty.
Refs #271
A directory can be named after the retired flag, and naming a directory
is what --include is for. Scanning raw argv read that value as an option
and refused the run — the one caller using the new option correctly.
The finder now reads the parser's leftovers, where a token consumed as a
value no longer appears. The end-of-options separator survives into those
leftovers, so a retired spelling after -- still belongs to the document.
Refs #271
@github-actions

github-actionsBot commented Aug 27, 2026

Copy link
Copy Markdown

PR #631: 💥 Say where components come from with --include

62 files, +320 / -220

Scope

🟡 540 lines changed. PRs under 400 receive more thorough review.

🟡 62 files changed. Are all changes related?

🟡 Changes span 15 directories.

🟡 PR mixes config and source changes.

Structural

Oxlint structural signals:

  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unused-vars ×4: packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
  • no-empty-function ×1: packages/cli/src/cli.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts

Static Analysis

Oxlint: 40 diagnostics across 6 files (12 rules)
Density: 0.125 violations/added-line

no-unsafe-type-assertion (12): packages/cli/src/cli.ts, packages/core/src/invocation-identity.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unused-vars (4): packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
consistent-return (4): packages/core/src/inspect.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts
no-console (3): packages/cli/src/cli.ts
no-shadow (3): packages/core/src/generated-xmd.ts, packages/core/src/execute.ts
no-array-sort (2): packages/web/tests/component-support.ts, packages/core/src/execute.ts
no-unnecessary-type-conversion (2): packages/web/tests/component-support.ts
no-floating-promises (2): packages/cli/src/cli.ts, packages/core/src/execute.ts
no-empty-function (1): packages/cli/src/cli.ts
no-base-to-string (1): packages/web/tests/component-support.ts
unbound-method (1): packages/core/src/execute.ts

Correctness

No extraneous code patterns detected.

`deno fmt` owns `site/`, and the option name lost eight characters, so the
line it was wrapped for now fits differently.
Nothing has been released that names the old flag, so there is no caller
to tell. The refusal existed only to answer one, and it cost a constant
assembled from fragments to keep the migration audit empty — a string the
one place that handled it could not be searched for.
The old spelling is now an option xmd does not define, exactly like any
other typo, and no code in the repository mentions it.
Refs #271
CR35 and CR38 proved the retired option was gone from the typed surface
and unread at runtime, and CR36 proved the retired export was gone. With
the old spelling deleted rather than deprecated there is nothing to be
absent from: the audit already says no source mentions it, and a test
that spells it from fragments only reintroduces the name it checks for.
CR36 keeps what is a claim about the present surface — the default value,
and that core exports it.
Refs #271
@taras
taras marked this pull request as ready for review August 27, 2026 13:16
@taras
taras merged commit 787ebcb into mainAug 27, 2026
30 checks passed
@taras
taras deleted the agent/issue-271-includes branch August 27, 2026 13:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💥 Rename componentDirs to includes

1 participant

@taras
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

💥 Say where components come from with --include - #631

Merged
taras merged 6 commits into
mainfrom
agent/issue-271-includes
Aug 27, 2026
Merged

💥 Say where components come from with --include#631
taras merged 6 commits into
mainfrom
agent/issue-271-includes

Conversation

@taras

@tarastaras commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes#271.

Why

componentDirs named a thing the rest of the vocabulary already had a better
word for. The configured directories a document resolves components from are now
includes, and the flag that names one is --include.

This is a 💥 clean break, and a total one: nothing has been released that names
the old spelling, so no code in the repository mentions it either.

What changes

RetiredNow
DEFAULT_COMPONENT_DIRSDEFAULT_INCLUDES
componentDirs (programmatic)includes
componentDir (configliere field, CLI-private)include
--component-dir--include

Before:

$ xmd run doc.md --component-dir components

After:

$ xmd run doc.md --include components

The old flag is simply an option xmd does not define, handled exactly as any
other undefined option is. It gets no refusal, no alias and no special case,
because there is no caller to tell — see Intentionally unchanged.

“Component search path” and “component search directory” do not change. They
remain the names of the complete ordered resolution path and of one directory on
it. Includes name only the configured contribution to that path, so
componentSearchPath() keeps its name and the prose was reviewed occurrence by
occurrence rather than replaced.

How it works

argv → --include → config.include → core includes → selectComponent → search path

The CLI keeps two spellings on purpose. runConfig.include,
testConfig.include and DocumentConfig.include are singular because
configliere derives --include from the field name; everything at the
programmatic boundary is plural — ExecuteSettings.includes,
SelectOptions.includes, InspectComponentOptions.includes,
TestingHostSettings.includes. runDocument maps one to the other. No custom
argv parsing was added: configliere's existing array field already gives ordered
repeats that replace the default.

Review guide

Start with:packages/core/src/components/select.ts

Then review:

  1. packages/core/mod.ts, execute.ts, inspect.ts — the public surface
  2. packages/cli/src/cli.ts — the schemas and the singular/plural boundary
  3. packages/core/src/execution-request.ts — the middleware snapshot still
    detaches and freezes
  4. Everything else — a mechanical identifier rename

What must stay true

  • No occurrence of the retired names survives — checked by
    git grep -nE 'componentDirs|componentDir|DEFAULT_COMPONENT_DIRS|--component-dir' -- .
    returning nothing. That grep is the whole of the absence claim; no test
    restates it.
  • Absence uses the defaults; includes: [] uses none — enforced by
    options.includes ?? DEFAULT_INCLUDES, checked by CR37.
  • A workflow's configured contribution stays empty — enforced by
    include: [] at workflow assembly, checked by workflow-component-bundle and
    workflow-bundle.
  • Directory targets keep document directory, target root, configured includes,
    first duplicate wins
    — enforced by componentSearchPath(), checked by DT32.

How to verify it

  • CR36 proves DEFAULT_INCLUDES is ["components", "."] and that mod.ts
    exports it.
  • CR37 proves ?? semantics and that the default array is copied, not
    shared. Fails if || is used or [] is widened to the defaults.
  • IE25 proves repeated --include are searched in caller order and that
    explicit values replace rather than extend the defaults: a same-named
    component sits on the default path and loses.
  • DT32 proves directory-target composition directly, with one duplicate
    spelled exactly and one spelled differently but resolving the same.
  • DT24/DT25 retain end-to-end colocated resolution.
  • The nested-host case proves a child <Execution host="run"> resolves a
    component only through the outer command's --include, with the bare run as
    the negative control.
  • CH2/CH3 prove both help surfaces list --include.

Scope

Included

  • The rename across core, CLI, every package consumer, deno.json tasks, the
    CI/review/repo-analysis workflows, smoke scripts, specs, architecture and site
    copy — one commit's worth of change, because either half alone leaves main
    contradicting its own API or unable to run its own commands.

Intentionally unchanged

  • The CLI's handling of options it does not define. The parser stops at the
    first token it does not recognize rather than rejecting it, so the retired
    flag is dropped in silence like any typo. An earlier revision of this branch
    added a refusal for it; that was removed once it was established there are no
    users to migrate. Refusing unknown options in general is a separate concern
    and not this PR's.
  • Tests asserting the old names are absent. There are none. A rename with no
    deprecation leaves nothing that could still answer to the old spelling, and a
    test naming it — necessarily by assembling the string, since the audit forbids
    the literal — would reintroduce the very name it checks for. The git grep
    audit above is the single place absence is claimed.
  • Resolution tiers, candidate order, precedence, the searched diagnostic, the
    unresolved message, journal shape and replay.
  • componentSearchPath() and the words “component search path” and “component
    search directory”.
  • Richer and embedded default components — still Embed built-in components in the xmd binary #67 and Embed core/components in the xmd binary with a default component search path #83.
  • specs/release-process-spec.md: no release configuration changed.
  • Lockfiles, dependencies and generated package output.

Generated or mechanical changes

  • The bulk of the 62 files is a mechanical identifier rename with no intended
    behavior change. The parts that are not:
    packages/core/src/components/select.ts, execute.ts, inspect.ts,
    execution-request.ts, mod.ts, packages/cli/src/cli.ts,
    packages/cli/src/testing-host.ts, and the regressions in
    component-registration.test.ts, inline-cli.test.ts, test-target.test.ts,
    testing-execution-host.test.ts.

Risks and limitations

  • The principal risk is a missed first-party occurrence rather than behavior.
    The zero-match audit is the controlling evidence and it is clean.
  • Anyone who has the old flag in a script gets no diagnostic — the run searches
    the default path instead. Accepted deliberately: there is no released binary
    naming it.
  • ✨ Compose and certify the supervised adversarial implementation workflow #181 is based on an older main and still adds the old spellings. It is
    not stacked here, and must adopt --include while rebasing after this lands.
  • Recovery: revert. No persisted data, remote state or compatibility state is
    migrated.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Rename the configured component-search-path surface: `includes` at every
programmatic boundary, `--include` as the repeatable CLI flag, and
`DEFAULT_INCLUDES` for the exported `["components", "."]` default.
This is a clean break. No alias, no deprecation, no compatibility parser:
the typed API no longer declares the former member, and an untyped object
carrying it is not read.
"Component search path" and "component search directory" stay the names of
the complete ordered resolution path and of one directory on it. Includes
name only the configured contribution to that path.
Resolution order, diagnostics, the `searched` list, journal shape, the
workflow's empty contribution and directory-target composition are
unchanged.
Refs #271
The argument parser ignores options it does not define rather than
rejecting them, so `--component-dir` was silently dropped: a run searched
the defaults and either failed somewhere unrelated or succeeded while
ignoring where the caller said components come from.
`xmd run` and `xmd test` now refuse it by name, before the run resolves
its props and before a test target is discovered. Both spellings are
refused — the separated value and the `=` form — and tokens after `--`
still belong to the document.
This is a refusal, not an alias: no value is mapped, and no generic
unknown-option policy is introduced. The retired spelling is assembled
from fragments at its one remaining site, so the migration audit stays
empty.
Refs #271
A directory can be named after the retired flag, and naming a directory
is what --include is for. Scanning raw argv read that value as an option
and refused the run — the one caller using the new option correctly.
The finder now reads the parser's leftovers, where a token consumed as a
value no longer appears. The end-of-options separator survives into those
leftovers, so a retired spelling after -- still belongs to the document.
Refs #271
@github-actions

github-actionsBot commented Aug 27, 2026

Copy link
Copy Markdown

PR #631: 💥 Say where components come from with --include

62 files, +320 / -220

Scope

🟡 540 lines changed. PRs under 400 receive more thorough review.

🟡 62 files changed. Are all changes related?

🟡 Changes span 15 directories.

🟡 PR mixes config and source changes.

Structural

Oxlint structural signals:

  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unused-vars ×4: packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
  • no-empty-function ×1: packages/cli/src/cli.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts

Static Analysis

Oxlint: 40 diagnostics across 6 files (12 rules)
Density: 0.125 violations/added-line

no-unsafe-type-assertion (12): packages/cli/src/cli.ts, packages/core/src/invocation-identity.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unused-vars (4): packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
consistent-return (4): packages/core/src/inspect.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts
no-console (3): packages/cli/src/cli.ts
no-shadow (3): packages/core/src/generated-xmd.ts, packages/core/src/execute.ts
no-array-sort (2): packages/web/tests/component-support.ts, packages/core/src/execute.ts
no-unnecessary-type-conversion (2): packages/web/tests/component-support.ts
no-floating-promises (2): packages/cli/src/cli.ts, packages/core/src/execute.ts
no-empty-function (1): packages/cli/src/cli.ts
no-base-to-string (1): packages/web/tests/component-support.ts
unbound-method (1): packages/core/src/execute.ts

Correctness

No extraneous code patterns detected.

`deno fmt` owns `site/`, and the option name lost eight characters, so the
line it was wrapped for now fits differently.
Nothing has been released that names the old flag, so there is no caller
to tell. The refusal existed only to answer one, and it cost a constant
assembled from fragments to keep the migration audit empty — a string the
one place that handled it could not be searched for.
The old spelling is now an option xmd does not define, exactly like any
other typo, and no code in the repository mentions it.
Refs #271
CR35 and CR38 proved the retired option was gone from the typed surface
and unread at runtime, and CR36 proved the retired export was gone. With
the old spelling deleted rather than deprecated there is nothing to be
absent from: the audit already says no source mentions it, and a test
that spells it from fragments only reintroduces the name it checks for.
CR36 keeps what is a claim about the present surface — the default value,
and that core exports it.
Refs #271
@taras
taras marked this pull request as ready for review August 27, 2026 13:16
@taras
taras merged commit 787ebcb into mainAug 27, 2026
30 checks passed
@taras
taras deleted the agent/issue-271-includes branch August 27, 2026 13:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💥 Rename componentDirs to includes

1 participant

@taras
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

💥 Say where components come from with --include - #631

Merged
taras merged 6 commits into
mainfrom
agent/issue-271-includes
Aug 27, 2026
Merged

💥 Say where components come from with --include#631
taras merged 6 commits into
mainfrom
agent/issue-271-includes

Conversation

@taras

@tarastaras commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes#271.

Why

componentDirs named a thing the rest of the vocabulary already had a better
word for. The configured directories a document resolves components from are now
includes, and the flag that names one is --include.

This is a 💥 clean break, and a total one: nothing has been released that names
the old spelling, so no code in the repository mentions it either.

What changes

RetiredNow
DEFAULT_COMPONENT_DIRSDEFAULT_INCLUDES
componentDirs (programmatic)includes
componentDir (configliere field, CLI-private)include
--component-dir--include

Before:

$ xmd run doc.md --component-dir components

After:

$ xmd run doc.md --include components

The old flag is simply an option xmd does not define, handled exactly as any
other undefined option is. It gets no refusal, no alias and no special case,
because there is no caller to tell — see Intentionally unchanged.

“Component search path” and “component search directory” do not change. They
remain the names of the complete ordered resolution path and of one directory on
it. Includes name only the configured contribution to that path, so
componentSearchPath() keeps its name and the prose was reviewed occurrence by
occurrence rather than replaced.

How it works

argv → --include → config.include → core includes → selectComponent → search path

The CLI keeps two spellings on purpose. runConfig.include,
testConfig.include and DocumentConfig.include are singular because
configliere derives --include from the field name; everything at the
programmatic boundary is plural — ExecuteSettings.includes,
SelectOptions.includes, InspectComponentOptions.includes,
TestingHostSettings.includes. runDocument maps one to the other. No custom
argv parsing was added: configliere's existing array field already gives ordered
repeats that replace the default.

Review guide

Start with:packages/core/src/components/select.ts

Then review:

  1. packages/core/mod.ts, execute.ts, inspect.ts — the public surface
  2. packages/cli/src/cli.ts — the schemas and the singular/plural boundary
  3. packages/core/src/execution-request.ts — the middleware snapshot still
    detaches and freezes
  4. Everything else — a mechanical identifier rename

What must stay true

  • No occurrence of the retired names survives — checked by
    git grep -nE 'componentDirs|componentDir|DEFAULT_COMPONENT_DIRS|--component-dir' -- .
    returning nothing. That grep is the whole of the absence claim; no test
    restates it.
  • Absence uses the defaults; includes: [] uses none — enforced by
    options.includes ?? DEFAULT_INCLUDES, checked by CR37.
  • A workflow's configured contribution stays empty — enforced by
    include: [] at workflow assembly, checked by workflow-component-bundle and
    workflow-bundle.
  • Directory targets keep document directory, target root, configured includes,
    first duplicate wins
    — enforced by componentSearchPath(), checked by DT32.

How to verify it

  • CR36 proves DEFAULT_INCLUDES is ["components", "."] and that mod.ts
    exports it.
  • CR37 proves ?? semantics and that the default array is copied, not
    shared. Fails if || is used or [] is widened to the defaults.
  • IE25 proves repeated --include are searched in caller order and that
    explicit values replace rather than extend the defaults: a same-named
    component sits on the default path and loses.
  • DT32 proves directory-target composition directly, with one duplicate
    spelled exactly and one spelled differently but resolving the same.
  • DT24/DT25 retain end-to-end colocated resolution.
  • The nested-host case proves a child <Execution host="run"> resolves a
    component only through the outer command's --include, with the bare run as
    the negative control.
  • CH2/CH3 prove both help surfaces list --include.

Scope

Included

  • The rename across core, CLI, every package consumer, deno.json tasks, the
    CI/review/repo-analysis workflows, smoke scripts, specs, architecture and site
    copy — one commit's worth of change, because either half alone leaves main
    contradicting its own API or unable to run its own commands.

Intentionally unchanged

  • The CLI's handling of options it does not define. The parser stops at the
    first token it does not recognize rather than rejecting it, so the retired
    flag is dropped in silence like any typo. An earlier revision of this branch
    added a refusal for it; that was removed once it was established there are no
    users to migrate. Refusing unknown options in general is a separate concern
    and not this PR's.
  • Tests asserting the old names are absent. There are none. A rename with no
    deprecation leaves nothing that could still answer to the old spelling, and a
    test naming it — necessarily by assembling the string, since the audit forbids
    the literal — would reintroduce the very name it checks for. The git grep
    audit above is the single place absence is claimed.
  • Resolution tiers, candidate order, precedence, the searched diagnostic, the
    unresolved message, journal shape and replay.
  • componentSearchPath() and the words “component search path” and “component
    search directory”.
  • Richer and embedded default components — still Embed built-in components in the xmd binary #67 and Embed core/components in the xmd binary with a default component search path #83.
  • specs/release-process-spec.md: no release configuration changed.
  • Lockfiles, dependencies and generated package output.

Generated or mechanical changes

  • The bulk of the 62 files is a mechanical identifier rename with no intended
    behavior change. The parts that are not:
    packages/core/src/components/select.ts, execute.ts, inspect.ts,
    execution-request.ts, mod.ts, packages/cli/src/cli.ts,
    packages/cli/src/testing-host.ts, and the regressions in
    component-registration.test.ts, inline-cli.test.ts, test-target.test.ts,
    testing-execution-host.test.ts.

Risks and limitations

  • The principal risk is a missed first-party occurrence rather than behavior.
    The zero-match audit is the controlling evidence and it is clean.
  • Anyone who has the old flag in a script gets no diagnostic — the run searches
    the default path instead. Accepted deliberately: there is no released binary
    naming it.
  • ✨ Compose and certify the supervised adversarial implementation workflow #181 is based on an older main and still adds the old spellings. It is
    not stacked here, and must adopt --include while rebasing after this lands.
  • Recovery: revert. No persisted data, remote state or compatibility state is
    migrated.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Rename the configured component-search-path surface: `includes` at every
programmatic boundary, `--include` as the repeatable CLI flag, and
`DEFAULT_INCLUDES` for the exported `["components", "."]` default.
This is a clean break. No alias, no deprecation, no compatibility parser:
the typed API no longer declares the former member, and an untyped object
carrying it is not read.
"Component search path" and "component search directory" stay the names of
the complete ordered resolution path and of one directory on it. Includes
name only the configured contribution to that path.
Resolution order, diagnostics, the `searched` list, journal shape, the
workflow's empty contribution and directory-target composition are
unchanged.
Refs #271
The argument parser ignores options it does not define rather than
rejecting them, so `--component-dir` was silently dropped: a run searched
the defaults and either failed somewhere unrelated or succeeded while
ignoring where the caller said components come from.
`xmd run` and `xmd test` now refuse it by name, before the run resolves
its props and before a test target is discovered. Both spellings are
refused — the separated value and the `=` form — and tokens after `--`
still belong to the document.
This is a refusal, not an alias: no value is mapped, and no generic
unknown-option policy is introduced. The retired spelling is assembled
from fragments at its one remaining site, so the migration audit stays
empty.
Refs #271
A directory can be named after the retired flag, and naming a directory
is what --include is for. Scanning raw argv read that value as an option
and refused the run — the one caller using the new option correctly.
The finder now reads the parser's leftovers, where a token consumed as a
value no longer appears. The end-of-options separator survives into those
leftovers, so a retired spelling after -- still belongs to the document.
Refs #271
@github-actions

github-actionsBot commented Aug 27, 2026

Copy link
Copy Markdown

PR #631: 💥 Say where components come from with --include

62 files, +320 / -220

Scope

🟡 540 lines changed. PRs under 400 receive more thorough review.

🟡 62 files changed. Are all changes related?

🟡 Changes span 15 directories.

🟡 PR mixes config and source changes.

Structural

Oxlint structural signals:

  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unused-vars ×4: packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
  • no-empty-function ×1: packages/cli/src/cli.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts

Static Analysis

Oxlint: 40 diagnostics across 6 files (12 rules)
Density: 0.125 violations/added-line

no-unsafe-type-assertion (12): packages/cli/src/cli.ts, packages/core/src/invocation-identity.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unused-vars (4): packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
consistent-return (4): packages/core/src/inspect.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts
no-console (3): packages/cli/src/cli.ts
no-shadow (3): packages/core/src/generated-xmd.ts, packages/core/src/execute.ts
no-array-sort (2): packages/web/tests/component-support.ts, packages/core/src/execute.ts
no-unnecessary-type-conversion (2): packages/web/tests/component-support.ts
no-floating-promises (2): packages/cli/src/cli.ts, packages/core/src/execute.ts
no-empty-function (1): packages/cli/src/cli.ts
no-base-to-string (1): packages/web/tests/component-support.ts
unbound-method (1): packages/core/src/execute.ts

Correctness

No extraneous code patterns detected.

`deno fmt` owns `site/`, and the option name lost eight characters, so the
line it was wrapped for now fits differently.
Nothing has been released that names the old flag, so there is no caller
to tell. The refusal existed only to answer one, and it cost a constant
assembled from fragments to keep the migration audit empty — a string the
one place that handled it could not be searched for.
The old spelling is now an option xmd does not define, exactly like any
other typo, and no code in the repository mentions it.
Refs #271
CR35 and CR38 proved the retired option was gone from the typed surface
and unread at runtime, and CR36 proved the retired export was gone. With
the old spelling deleted rather than deprecated there is nothing to be
absent from: the audit already says no source mentions it, and a test
that spells it from fragments only reintroduces the name it checks for.
CR36 keeps what is a claim about the present surface — the default value,
and that core exports it.
Refs #271
@taras
taras marked this pull request as ready for review August 27, 2026 13:16
@taras
taras merged commit 787ebcb into mainAug 27, 2026
30 checks passed
@taras
taras deleted the agent/issue-271-includes branch August 27, 2026 13:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💥 Rename componentDirs to includes

1 participant

@taras
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

💥 Say where components come from with --include - #631

Merged
taras merged 6 commits into
mainfrom
agent/issue-271-includes
Aug 27, 2026
Merged

💥 Say where components come from with --include#631
taras merged 6 commits into
mainfrom
agent/issue-271-includes

Conversation

@taras

@tarastaras commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes#271.

Why

componentDirs named a thing the rest of the vocabulary already had a better
word for. The configured directories a document resolves components from are now
includes, and the flag that names one is --include.

This is a 💥 clean break, and a total one: nothing has been released that names
the old spelling, so no code in the repository mentions it either.

What changes

RetiredNow
DEFAULT_COMPONENT_DIRSDEFAULT_INCLUDES
componentDirs (programmatic)includes
componentDir (configliere field, CLI-private)include
--component-dir--include

Before:

$ xmd run doc.md --component-dir components

After:

$ xmd run doc.md --include components

The old flag is simply an option xmd does not define, handled exactly as any
other undefined option is. It gets no refusal, no alias and no special case,
because there is no caller to tell — see Intentionally unchanged.

“Component search path” and “component search directory” do not change. They
remain the names of the complete ordered resolution path and of one directory on
it. Includes name only the configured contribution to that path, so
componentSearchPath() keeps its name and the prose was reviewed occurrence by
occurrence rather than replaced.

How it works

argv → --include → config.include → core includes → selectComponent → search path

The CLI keeps two spellings on purpose. runConfig.include,
testConfig.include and DocumentConfig.include are singular because
configliere derives --include from the field name; everything at the
programmatic boundary is plural — ExecuteSettings.includes,
SelectOptions.includes, InspectComponentOptions.includes,
TestingHostSettings.includes. runDocument maps one to the other. No custom
argv parsing was added: configliere's existing array field already gives ordered
repeats that replace the default.

Review guide

Start with:packages/core/src/components/select.ts

Then review:

  1. packages/core/mod.ts, execute.ts, inspect.ts — the public surface
  2. packages/cli/src/cli.ts — the schemas and the singular/plural boundary
  3. packages/core/src/execution-request.ts — the middleware snapshot still
    detaches and freezes
  4. Everything else — a mechanical identifier rename

What must stay true

  • No occurrence of the retired names survives — checked by
    git grep -nE 'componentDirs|componentDir|DEFAULT_COMPONENT_DIRS|--component-dir' -- .
    returning nothing. That grep is the whole of the absence claim; no test
    restates it.
  • Absence uses the defaults; includes: [] uses none — enforced by
    options.includes ?? DEFAULT_INCLUDES, checked by CR37.
  • A workflow's configured contribution stays empty — enforced by
    include: [] at workflow assembly, checked by workflow-component-bundle and
    workflow-bundle.
  • Directory targets keep document directory, target root, configured includes,
    first duplicate wins
    — enforced by componentSearchPath(), checked by DT32.

How to verify it

  • CR36 proves DEFAULT_INCLUDES is ["components", "."] and that mod.ts
    exports it.
  • CR37 proves ?? semantics and that the default array is copied, not
    shared. Fails if || is used or [] is widened to the defaults.
  • IE25 proves repeated --include are searched in caller order and that
    explicit values replace rather than extend the defaults: a same-named
    component sits on the default path and loses.
  • DT32 proves directory-target composition directly, with one duplicate
    spelled exactly and one spelled differently but resolving the same.
  • DT24/DT25 retain end-to-end colocated resolution.
  • The nested-host case proves a child <Execution host="run"> resolves a
    component only through the outer command's --include, with the bare run as
    the negative control.
  • CH2/CH3 prove both help surfaces list --include.

Scope

Included

  • The rename across core, CLI, every package consumer, deno.json tasks, the
    CI/review/repo-analysis workflows, smoke scripts, specs, architecture and site
    copy — one commit's worth of change, because either half alone leaves main
    contradicting its own API or unable to run its own commands.

Intentionally unchanged

  • The CLI's handling of options it does not define. The parser stops at the
    first token it does not recognize rather than rejecting it, so the retired
    flag is dropped in silence like any typo. An earlier revision of this branch
    added a refusal for it; that was removed once it was established there are no
    users to migrate. Refusing unknown options in general is a separate concern
    and not this PR's.
  • Tests asserting the old names are absent. There are none. A rename with no
    deprecation leaves nothing that could still answer to the old spelling, and a
    test naming it — necessarily by assembling the string, since the audit forbids
    the literal — would reintroduce the very name it checks for. The git grep
    audit above is the single place absence is claimed.
  • Resolution tiers, candidate order, precedence, the searched diagnostic, the
    unresolved message, journal shape and replay.
  • componentSearchPath() and the words “component search path” and “component
    search directory”.
  • Richer and embedded default components — still Embed built-in components in the xmd binary #67 and Embed core/components in the xmd binary with a default component search path #83.
  • specs/release-process-spec.md: no release configuration changed.
  • Lockfiles, dependencies and generated package output.

Generated or mechanical changes

  • The bulk of the 62 files is a mechanical identifier rename with no intended
    behavior change. The parts that are not:
    packages/core/src/components/select.ts, execute.ts, inspect.ts,
    execution-request.ts, mod.ts, packages/cli/src/cli.ts,
    packages/cli/src/testing-host.ts, and the regressions in
    component-registration.test.ts, inline-cli.test.ts, test-target.test.ts,
    testing-execution-host.test.ts.

Risks and limitations

  • The principal risk is a missed first-party occurrence rather than behavior.
    The zero-match audit is the controlling evidence and it is clean.
  • Anyone who has the old flag in a script gets no diagnostic — the run searches
    the default path instead. Accepted deliberately: there is no released binary
    naming it.
  • ✨ Compose and certify the supervised adversarial implementation workflow #181 is based on an older main and still adds the old spellings. It is
    not stacked here, and must adopt --include while rebasing after this lands.
  • Recovery: revert. No persisted data, remote state or compatibility state is
    migrated.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Rename the configured component-search-path surface: `includes` at every
programmatic boundary, `--include` as the repeatable CLI flag, and
`DEFAULT_INCLUDES` for the exported `["components", "."]` default.
This is a clean break. No alias, no deprecation, no compatibility parser:
the typed API no longer declares the former member, and an untyped object
carrying it is not read.
"Component search path" and "component search directory" stay the names of
the complete ordered resolution path and of one directory on it. Includes
name only the configured contribution to that path.
Resolution order, diagnostics, the `searched` list, journal shape, the
workflow's empty contribution and directory-target composition are
unchanged.
Refs #271
The argument parser ignores options it does not define rather than
rejecting them, so `--component-dir` was silently dropped: a run searched
the defaults and either failed somewhere unrelated or succeeded while
ignoring where the caller said components come from.
`xmd run` and `xmd test` now refuse it by name, before the run resolves
its props and before a test target is discovered. Both spellings are
refused — the separated value and the `=` form — and tokens after `--`
still belong to the document.
This is a refusal, not an alias: no value is mapped, and no generic
unknown-option policy is introduced. The retired spelling is assembled
from fragments at its one remaining site, so the migration audit stays
empty.
Refs #271
A directory can be named after the retired flag, and naming a directory
is what --include is for. Scanning raw argv read that value as an option
and refused the run — the one caller using the new option correctly.
The finder now reads the parser's leftovers, where a token consumed as a
value no longer appears. The end-of-options separator survives into those
leftovers, so a retired spelling after -- still belongs to the document.
Refs #271
@github-actions

github-actionsBot commented Aug 27, 2026

Copy link
Copy Markdown

PR #631: 💥 Say where components come from with --include

62 files, +320 / -220

Scope

🟡 540 lines changed. PRs under 400 receive more thorough review.

🟡 62 files changed. Are all changes related?

🟡 Changes span 15 directories.

🟡 PR mixes config and source changes.

Structural

Oxlint structural signals:

  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unused-vars ×4: packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
  • no-empty-function ×1: packages/cli/src/cli.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts

Static Analysis

Oxlint: 40 diagnostics across 6 files (12 rules)
Density: 0.125 violations/added-line

no-unsafe-type-assertion (12): packages/cli/src/cli.ts, packages/core/src/invocation-identity.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unused-vars (4): packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
consistent-return (4): packages/core/src/inspect.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts
no-console (3): packages/cli/src/cli.ts
no-shadow (3): packages/core/src/generated-xmd.ts, packages/core/src/execute.ts
no-array-sort (2): packages/web/tests/component-support.ts, packages/core/src/execute.ts
no-unnecessary-type-conversion (2): packages/web/tests/component-support.ts
no-floating-promises (2): packages/cli/src/cli.ts, packages/core/src/execute.ts
no-empty-function (1): packages/cli/src/cli.ts
no-base-to-string (1): packages/web/tests/component-support.ts
unbound-method (1): packages/core/src/execute.ts

Correctness

No extraneous code patterns detected.

`deno fmt` owns `site/`, and the option name lost eight characters, so the
line it was wrapped for now fits differently.
Nothing has been released that names the old flag, so there is no caller
to tell. The refusal existed only to answer one, and it cost a constant
assembled from fragments to keep the migration audit empty — a string the
one place that handled it could not be searched for.
The old spelling is now an option xmd does not define, exactly like any
other typo, and no code in the repository mentions it.
Refs #271
CR35 and CR38 proved the retired option was gone from the typed surface
and unread at runtime, and CR36 proved the retired export was gone. With
the old spelling deleted rather than deprecated there is nothing to be
absent from: the audit already says no source mentions it, and a test
that spells it from fragments only reintroduces the name it checks for.
CR36 keeps what is a claim about the present surface — the default value,
and that core exports it.
Refs #271
@taras
taras marked this pull request as ready for review August 27, 2026 13:16
@taras
taras merged commit 787ebcb into mainAug 27, 2026
30 checks passed
@taras
taras deleted the agent/issue-271-includes branch August 27, 2026 13:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💥 Rename componentDirs to includes

1 participant

@taras
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

💥 Say where components come from with --include - #631

Merged
taras merged 6 commits into
mainfrom
agent/issue-271-includes
Aug 27, 2026
Merged

💥 Say where components come from with --include#631
taras merged 6 commits into
mainfrom
agent/issue-271-includes

Conversation

@taras

@tarastaras commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes#271.

Why

componentDirs named a thing the rest of the vocabulary already had a better
word for. The configured directories a document resolves components from are now
includes, and the flag that names one is --include.

This is a 💥 clean break, and a total one: nothing has been released that names
the old spelling, so no code in the repository mentions it either.

What changes

RetiredNow
DEFAULT_COMPONENT_DIRSDEFAULT_INCLUDES
componentDirs (programmatic)includes
componentDir (configliere field, CLI-private)include
--component-dir--include

Before:

$ xmd run doc.md --component-dir components

After:

$ xmd run doc.md --include components

The old flag is simply an option xmd does not define, handled exactly as any
other undefined option is. It gets no refusal, no alias and no special case,
because there is no caller to tell — see Intentionally unchanged.

“Component search path” and “component search directory” do not change. They
remain the names of the complete ordered resolution path and of one directory on
it. Includes name only the configured contribution to that path, so
componentSearchPath() keeps its name and the prose was reviewed occurrence by
occurrence rather than replaced.

How it works

argv → --include → config.include → core includes → selectComponent → search path

The CLI keeps two spellings on purpose. runConfig.include,
testConfig.include and DocumentConfig.include are singular because
configliere derives --include from the field name; everything at the
programmatic boundary is plural — ExecuteSettings.includes,
SelectOptions.includes, InspectComponentOptions.includes,
TestingHostSettings.includes. runDocument maps one to the other. No custom
argv parsing was added: configliere's existing array field already gives ordered
repeats that replace the default.

Review guide

Start with:packages/core/src/components/select.ts

Then review:

  1. packages/core/mod.ts, execute.ts, inspect.ts — the public surface
  2. packages/cli/src/cli.ts — the schemas and the singular/plural boundary
  3. packages/core/src/execution-request.ts — the middleware snapshot still
    detaches and freezes
  4. Everything else — a mechanical identifier rename

What must stay true

  • No occurrence of the retired names survives — checked by
    git grep -nE 'componentDirs|componentDir|DEFAULT_COMPONENT_DIRS|--component-dir' -- .
    returning nothing. That grep is the whole of the absence claim; no test
    restates it.
  • Absence uses the defaults; includes: [] uses none — enforced by
    options.includes ?? DEFAULT_INCLUDES, checked by CR37.
  • A workflow's configured contribution stays empty — enforced by
    include: [] at workflow assembly, checked by workflow-component-bundle and
    workflow-bundle.
  • Directory targets keep document directory, target root, configured includes,
    first duplicate wins
    — enforced by componentSearchPath(), checked by DT32.

How to verify it

  • CR36 proves DEFAULT_INCLUDES is ["components", "."] and that mod.ts
    exports it.
  • CR37 proves ?? semantics and that the default array is copied, not
    shared. Fails if || is used or [] is widened to the defaults.
  • IE25 proves repeated --include are searched in caller order and that
    explicit values replace rather than extend the defaults: a same-named
    component sits on the default path and loses.
  • DT32 proves directory-target composition directly, with one duplicate
    spelled exactly and one spelled differently but resolving the same.
  • DT24/DT25 retain end-to-end colocated resolution.
  • The nested-host case proves a child <Execution host="run"> resolves a
    component only through the outer command's --include, with the bare run as
    the negative control.
  • CH2/CH3 prove both help surfaces list --include.

Scope

Included

  • The rename across core, CLI, every package consumer, deno.json tasks, the
    CI/review/repo-analysis workflows, smoke scripts, specs, architecture and site
    copy — one commit's worth of change, because either half alone leaves main
    contradicting its own API or unable to run its own commands.

Intentionally unchanged

  • The CLI's handling of options it does not define. The parser stops at the
    first token it does not recognize rather than rejecting it, so the retired
    flag is dropped in silence like any typo. An earlier revision of this branch
    added a refusal for it; that was removed once it was established there are no
    users to migrate. Refusing unknown options in general is a separate concern
    and not this PR's.
  • Tests asserting the old names are absent. There are none. A rename with no
    deprecation leaves nothing that could still answer to the old spelling, and a
    test naming it — necessarily by assembling the string, since the audit forbids
    the literal — would reintroduce the very name it checks for. The git grep
    audit above is the single place absence is claimed.
  • Resolution tiers, candidate order, precedence, the searched diagnostic, the
    unresolved message, journal shape and replay.
  • componentSearchPath() and the words “component search path” and “component
    search directory”.
  • Richer and embedded default components — still Embed built-in components in the xmd binary #67 and Embed core/components in the xmd binary with a default component search path #83.
  • specs/release-process-spec.md: no release configuration changed.
  • Lockfiles, dependencies and generated package output.

Generated or mechanical changes

  • The bulk of the 62 files is a mechanical identifier rename with no intended
    behavior change. The parts that are not:
    packages/core/src/components/select.ts, execute.ts, inspect.ts,
    execution-request.ts, mod.ts, packages/cli/src/cli.ts,
    packages/cli/src/testing-host.ts, and the regressions in
    component-registration.test.ts, inline-cli.test.ts, test-target.test.ts,
    testing-execution-host.test.ts.

Risks and limitations

  • The principal risk is a missed first-party occurrence rather than behavior.
    The zero-match audit is the controlling evidence and it is clean.
  • Anyone who has the old flag in a script gets no diagnostic — the run searches
    the default path instead. Accepted deliberately: there is no released binary
    naming it.
  • ✨ Compose and certify the supervised adversarial implementation workflow #181 is based on an older main and still adds the old spellings. It is
    not stacked here, and must adopt --include while rebasing after this lands.
  • Recovery: revert. No persisted data, remote state or compatibility state is
    migrated.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Rename the configured component-search-path surface: `includes` at every
programmatic boundary, `--include` as the repeatable CLI flag, and
`DEFAULT_INCLUDES` for the exported `["components", "."]` default.
This is a clean break. No alias, no deprecation, no compatibility parser:
the typed API no longer declares the former member, and an untyped object
carrying it is not read.
"Component search path" and "component search directory" stay the names of
the complete ordered resolution path and of one directory on it. Includes
name only the configured contribution to that path.
Resolution order, diagnostics, the `searched` list, journal shape, the
workflow's empty contribution and directory-target composition are
unchanged.
Refs #271
The argument parser ignores options it does not define rather than
rejecting them, so `--component-dir` was silently dropped: a run searched
the defaults and either failed somewhere unrelated or succeeded while
ignoring where the caller said components come from.
`xmd run` and `xmd test` now refuse it by name, before the run resolves
its props and before a test target is discovered. Both spellings are
refused — the separated value and the `=` form — and tokens after `--`
still belong to the document.
This is a refusal, not an alias: no value is mapped, and no generic
unknown-option policy is introduced. The retired spelling is assembled
from fragments at its one remaining site, so the migration audit stays
empty.
Refs #271
A directory can be named after the retired flag, and naming a directory
is what --include is for. Scanning raw argv read that value as an option
and refused the run — the one caller using the new option correctly.
The finder now reads the parser's leftovers, where a token consumed as a
value no longer appears. The end-of-options separator survives into those
leftovers, so a retired spelling after -- still belongs to the document.
Refs #271
@github-actions

github-actionsBot commented Aug 27, 2026

Copy link
Copy Markdown

PR #631: 💥 Say where components come from with --include

62 files, +320 / -220

Scope

🟡 540 lines changed. PRs under 400 receive more thorough review.

🟡 62 files changed. Are all changes related?

🟡 Changes span 15 directories.

🟡 PR mixes config and source changes.

Structural

Oxlint structural signals:

  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unused-vars ×4: packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
  • no-empty-function ×1: packages/cli/src/cli.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts

Static Analysis

Oxlint: 40 diagnostics across 6 files (12 rules)
Density: 0.125 violations/added-line

no-unsafe-type-assertion (12): packages/cli/src/cli.ts, packages/core/src/invocation-identity.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unused-vars (4): packages/web/tests/component-support.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts
consistent-return (4): packages/core/src/inspect.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts
no-console (3): packages/cli/src/cli.ts
no-shadow (3): packages/core/src/generated-xmd.ts, packages/core/src/execute.ts
no-array-sort (2): packages/web/tests/component-support.ts, packages/core/src/execute.ts
no-unnecessary-type-conversion (2): packages/web/tests/component-support.ts
no-floating-promises (2): packages/cli/src/cli.ts, packages/core/src/execute.ts
no-empty-function (1): packages/cli/src/cli.ts
no-base-to-string (1): packages/web/tests/component-support.ts
unbound-method (1): packages/core/src/execute.ts

Correctness

No extraneous code patterns detected.

`deno fmt` owns `site/`, and the option name lost eight characters, so the
line it was wrapped for now fits differently.
Nothing has been released that names the old flag, so there is no caller
to tell. The refusal existed only to answer one, and it cost a constant
assembled from fragments to keep the migration audit empty — a string the
one place that handled it could not be searched for.
The old spelling is now an option xmd does not define, exactly like any
other typo, and no code in the repository mentions it.
Refs #271
CR35 and CR38 proved the retired option was gone from the typed surface
and unread at runtime, and CR36 proved the retired export was gone. With
the old spelling deleted rather than deprecated there is nothing to be
absent from: the audit already says no source mentions it, and a test
that spells it from fragments only reintroduces the name it checks for.
CR36 keeps what is a claim about the present surface — the default value,
and that core exports it.
Refs #271
@taras
taras marked this pull request as ready for review August 27, 2026 13:16
@taras
taras merged commit 787ebcb into mainAug 27, 2026
30 checks passed
@taras
taras deleted the agent/issue-271-includes branch August 27, 2026 13:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💥 Rename componentDirs to includes

1 participant

@taras