Skip to content

feat(scripts): check-doc-links 扫描面第四扩 packages/*/README.md,并付清入场价的 11 条死链 (#3622) - #3649

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-3622-scan-roots-fourth-ext
Aug 7, 2026
Merged

feat(scripts): check-doc-links 扫描面第四扩 packages/*/README.md,并付清入场价的 11 条死链 (#3622)#3649
yinlianghui merged 2 commits into
mainfrom
claude/issue-3622-scan-roots-fourth-ext

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#3622
Fixes#3603

先量后付的第四次。红账先清零,再加扫描行——门禁首跑对真仓即绿,而这 11 条正是它的验收语料。父单 #3603 的门禁第 1 层至此落地,两半合齐。

一、11 条红账处置表(逐条独立查证,全部改指,零删除)

#位置原 href处置依据(逐条实测)
1packages/components/README.md:30../../docs/SHADCN_SYNC.md改指 ./README_SHADCN_SYNC.mdfind . -name SHADCN_SYNC.md 全仓零命中,该文件从未存在;真正的完整指南是同包的 README_SHADCN_SYNC.md(278 行,pnpm shadcn:check / shadcn:update 全在其中),且 shadcn-components.json 也在同目录
2packages/components/README.md:212https://objectui.org/api/components改指 https://objectui.org/docs/componentsapps/site/app/api 下只有 search/route.ts,/api/components 无路由;content/docs/components/index.md 是 Component Gallery,正是该包的组件参考。#3629 给 vscode-extension 的「Component Library」用的就是这一页
3packages/core/README.md:144https://objectui.org/api/core改指 https://objectui.org/docs/api同上无路由;content/docs/api/index.md 标题即 "API Reference",自述 "Comprehensive reference documentation for all ObjectUI types, schemas, and APIs",与该节标题 ## API Reference 对位
4packages/core/README.md:158https://www.objectui.org/docs/core改指 https://www.objectui.org/docs/guide/architecturecontent/docs/core/ 只有 5 个 .mdx,无 index 页,fumadocs 不生成路由;guide/architecture.md 的 §Package Structure 有 #### @object-ui/core 一节逐包说明角色与边界
5packages/fields/README.md:131https://www.objectui.org/docs/fields改指 https://www.objectui.org/docs/guide/fieldscontent/docs/fields/ 26 个字段页,无 index;guide/fields.md 标题 "Field Registry",正文首句即 "The @object-ui/fields package serves as the Universal Language for rendering values"
6packages/layout/README.md:122https://www.objectui.org/docs/layout改指 https://www.objectui.org/docs/layout/app-shellcontent/docs/layout/ 无 index;该行在 ## API Reference 下、紧跟一段 AppShell 示例,layout/app-shell.mdx 就是这个组件的 API 页
7packages/layout/README.md:137https://www.objectui.org/docs/layout改指 https://www.objectui.org/docs/guide/layout同上无 index;该行在 ## Links 的「Documentation」位,guide/layout.md 标题 "Layout System",逐个介绍 AppShell / Page / PageHeader / SidebarNav——是包总览而非单组件页,故与第 6 条取不同目标
8packages/react/README.md:228https://objectui.org/api/react改指 https://objectui.org/docs/core/schema-renderer/api/react 路由(#3490 已扫过同款);core/schema-renderer.mdx 是该包主导出 SchemaRenderer 的参考页。与 #3629 给同包 :243 选的目标相同——这一处重复是有意留下的:站点没有按包组织的 API 页(#3490 的结论),这就是 react 最贴近的真实参考页
9packages/types/README.md:329https://objectui.org/docs/types改指 https://objectui.org/docs/api/schema-referencecontent/docs/types 整个目录不存在;api/schema-reference.md 开篇写着 "Import: All types are available from @object-ui/types",就是这个包的内容
10packages/vscode-extension/README.md:190https://www.objectui.org/examples改指 https://github.com/objectstack-ai/objectui/tree/main/examples/examples 不是站点路由(#3490 已确认);examples/ 目录真实存在,且 content/docs/utilities/vscode-extension.mdx:489 这条同名链接用的正是这个 URL,仓内另有 3 处同款写法
11packages/vscode-extension/README.md:242./LICENSE改指 https://github.com/objectstack-ai/objectui/blob/main/LICENSE39 个包里 35 个有 LICENSE 文件,该包没有;仓根有。该 README 第 237 行给 CONTRIBUTING.md 用的就是 blob/main/ 形态,与之统一。⚠️ 未改成补 LICENSE 文件——那是打包策略,已另开 #3647

没有删除任何一行。#3603/#3629 的口径是「查不到真实页才删」;这 11 条逐条都找到了实测存在的对位页面,所以全部改指。这也是它与 #3629(9 条里删 6 改 3)的差别:那 6 条假设的是一整个不存在的 /docs/packages/PKG 命名空间,本单这 11 条各自都有真实归属。

改指后全部保留 https://[www.]objectui.org/... 的 origin,不写成 origin-less 的 /docs/...:包 README 在 GitHub 与 npm 上被读,那里开头的 / 会被解析到它们自己的域名。这一点已写进头注释与 ci-cd-pipeline.md,避免下一个人按 content/docs 的偏好「顺手改正」。

二、扫描行

{ path: 'packages/*/README.md', rule: 'disk' },

disk 规则,不新增规则类:包 README 在 npm 与 GitHub 被阅读,相对链接是磁盘路径语义(./CHANGELOG.md 是身边的文件而非路由),与 examples/**README.mdCONTRIBUTING.mdROADMAP.mddocs/** 完全同类。理由与「必须保留 origin」的推论一并写进头注释。

这是表里唯一带通配符的一行,所以 collectFiles() 增加了 expandWildcard():只认整段*,再复杂的写法直接抛错,而不是静默匹配零个路径——扫描面被悄悄丢掉是这个门禁唯一不能有的失效模式(与 routeExists() 缺路由表时抛错同一立场)。

头注释的 "Measured and NOT bought" 一节改写为已购入,并把 #3572 那份过期的 "Still not bought" 清单挪到当前位置(那四个文件仍在单上,另加包内非 README 的 markdown)。⚠️ 注释里仍未原样写出 glob——星号加斜杠会提前闭合块注释(#3629 踩过),只用散文描述,真正的 glob 只出现在下方的数据表里(那是代码)。

顺带更新了两处随扫描面漂移的实测数字:「把 docs 规则套到 disk 面会误杀多少条」由 111 改为 186。111 是用本次同一套方法独立复算出来的(examples 21 + README 40 + CONTRIBUTING 0 + ROADMAP 3 + docs 47 = 111,与文件里记的数字一致),包 README 贡献新增的 75 条。

三、逆向验证(方向先定后跑)

这是「扩扫描面」类改动,方向是常规的加行则多报,不是 #5018/#5046 那种反转或计数下降的情形——先写下预测再跑:

步骤预测实测
真仓首跑,11 条已清、扫描行已加绿Links are valid across 7 scan roots.(exit 0)
packages/core/README.md 植入两条死链(相对磁盘路径 + 站内绝对 URL 各一)红,且恰好是这 2 条Found 2 broken links,[example-relative] ./NO_SUCH_FILE.md + [site-absolute-url] .../docs/no-such-page,exit 1
仅撤掉扫描行,植入的死链原地留着绿——证明是这一行在干活,不是别的根顺带扫到了Links are valid across 6 scan roots.(exit 0)
还原两者绿,7 根Links are valid across 7 scan roots.

测试层做了同一件事(撤掉扫描行跑测试):

预测实测
依赖扫描面的用例转红✅ 7 条红:really scans every surfacepairs each scan root,以及 #3622 describe 里的 4 条(四种死链形状 / 只收 README / 排除 node_modules / disk 与 docs 对照对)+ 「floor under the green」
两条直接调 collectFiles()、不经 SCAN_ROOTS 的用例保持绿✅ 恰好这 2 条绿(通配符展开、非整段通配符抛错)

「floor under the green」原本也直接写死路径、撤行后不会红,已改成从 SCAN_ROOTS 里取那一行——现在删行会连它一起带红,而不是留下一条对着门禁已不再扫描的目录做测量的绿测试。

四、测试

  • SCAN_ROOTStoEqual pin 与逐根 count 表按新行扩写(新根文件数下限 35,今日 38——39 个包里 sdui-parser 没有 README)。
  • 新根另加「可判定 href 数」下限,这是本次的反空绿主力:文件数只能证明通配符展开了,证明不了这批文件里有东西可判。实测 38 个 README 共 294 条链接、其中 200 条可判定(47 条是站内绝对 URL,即 11 条死链里 9 条的形状),下限写 150 / 40。
  • 新增 7 条用例:四种死链形状同框(每种旁边配一条同形状的活链作对照,任一条判对判错都会响)、通配符展开与排序、只收 README 的边界(包内 CHANGELOG.md / TESTING.md / docs/ 不扫,用 README 自己的死链作控制项防止空绿)、packages/node_modules 排除、disk 与 docs 规则的双向对照对、非整段通配符抛错。
npx vitest run scripts/__tests__/check-doc-links.test.ts
Test Files 1 passed (1) Tests 82 passed (82)
npx vitest run scripts/__tests__/ # 全量
Test Files 16 passed (16) Tests 300 passed (300)
pnpm type-check:scripts # tsc -p tsconfig.scripts.json,无输出
npx eslint scripts/check-doc-links.mjs scripts/__tests__/check-doc-links.test.ts # 无输出
node scripts/check-control-bytes.mjs
✅ OK (scanned 3655 tracked text file(s); skipped 85 binary)

另按仓规自查了控制字节(grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' 扫本 PR 全部改动文件,零命中)。

五、不加 changeset

改的是包 README 的链接与 CI 脚本,不触发任何包的版本发布,与 #3589 / #3629 仓例一致(#3629 的部分验收评论第 5 条已确认接受)。

六、范围外发现(已另开,未在本 PR 修)

七、未做,且是有意的

content/docs/core / fields / layout / rfcs 四个目录缺 index 页(侧边栏这四个分组标题本身不可点)。给它们补 index 页会让第 4/5/6/7 条链接原地复活,但那是内容创作,#3622 正文与 PM 认领评论都判在本卡之外,留给分诊池。本 PR 按「链接侧处置」的裁决,把这四条改指到实测存在的真实页。


🤖 Generated with Claude Code

https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt


Generated by Claude Code

… 条死链 (#3622)
先量后付的第四次:红账先清零,再加扫描行,门禁首跑对真仓即绿。
11 条死链逐条查证后处置(全部改指实测存在的真实页,零删除):
- 三条 /api/PKG(components/core/react)——站点从来没有这个路由段
(apps/site/app/api 下只有 search/route.ts)。components 改指
/docs/components(Component Gallery,#3629 给 vscode-extension 用过
的同一页),core 改指 /docs/api(站点自称的 API Reference 总页),
react 改指 /docs/core/schema-renderer(它主导出的参考页)。
- 四条指向 content/docs 下无 index 页的目录(core/fields/layout x2)——
fumadocs 不为裸目录生成路由,#3603 正文的复核脚本把裸目录也算作候选
才误判为绿。core 改指 /docs/guide/architecture(Package Structure 一节
逐包说明 @object-ui/core),fields 改指 /docs/guide/fields(Field Registry,
正是该包的文档),layout 的 API Reference 改指 /docs/layout/app-shell、
Links 改指 /docs/guide/layout。
- /docs/types 完全不存在 → 改指 /docs/api/schema-reference,该页开头写着
「All types are available from @object-ui/types」。
- /examples 不是站点路由(#3490 已确认)→ 改指
github.com/objectstack-ai/objectui/tree/main/examples,与
content/docs/utilities/vscode-extension.mdx 里同一条链接的写法一致。
- 两条磁盘路径:docs/SHADCN_SYNC.md 从未存在,真正的完整指南是同包的
README_SHADCN_SYNC.md(278 行);vscode-extension 没有 LICENSE 文件
(39 个包里 4 个没有),按该 README 已有的仓根文件写法改指
blob/main/LICENSE。
扫描行沿用 disk 规则:包 README 在 npm 与 GitHub 上被阅读,相对链接是
磁盘路径语义,与 examples/README/CONTRIBUTING/ROADMAP/docs 同类,无需新
规则类。同一条理由也决定了上面修好的站内链接必须保留 origin——GitHub 与
npm 都把开头的 / 解析到它们自己的域名。
该行是表里唯一带通配符的一条,故 collectFiles 增加 expandWildcard():只
认整段的 *,再复杂的写法直接抛错而不是静默匹配零个路径——扫描面被悄悄
丢掉是这个门禁唯一不能有的失效模式。
测试:SCAN_ROOTS 的 toEqual 与逐根 count 扩写;新根另加「可判定 href 数」
下限(200 条,其中 47 条站内绝对 URL),因为文件数只能证明通配符展开了,
证明不了这批文件里有东西可判;新增 7 条用例覆盖四种死链形状、通配符展开、
只收 README 的边界、packages/node_modules 排除、disk 与 docs 规则的对照对,
以及非整段通配符抛错。
逆向验证(方向先定后跑):植入两条死链(相对磁盘路径 + 站内绝对 URL 各一)
→ 门禁红,正是那 2 条;仅撤掉扫描行、死链留在原地 → 绿,证明是该行在干活;
还原后 7 根全绿。测试层同样验证:撤行后恰好 7 条用例红,唯二直接调
collectFiles 的两条保持绿——与预测一致。
不加 changeset:改的是包 README 的链接与 CI 脚本,不触发任何包的版本
发布,与 #3589/#3629 仓例一致。
Fixes#3622Fixes#3603
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@vercel

vercelBot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 7, 2026 5:01pm

Request Review

原句写成「Each was resolved to a real page, or dropped where none exists」,
但本次 11 条逐条都找到了实测存在的对位页面,零删除。措辞改准,并点明与
#3603 那 9 条的差别:那 6 条删掉是因为它们假设了一整个从未写过的
/docs/packages/... 命名空间,本单这 11 条各自都有真实归属。
顺带把「七个包,其中五个 #3603 从未打开」一句的中英夹缠语序理顺。纯注释,
零行为改动。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)28.1 KB350 KB
Entry fileindex-Db9tmbJX.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)8.66KB3.13KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)7.57KB2.97KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)22.10KB4.37KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)35.76KB9.11KB
auth (createAuthenticatedFetch.js)4.37KB1.69KB
auth (index.js)2.35KB1.07KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)4.91KB0.87KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)480.72KB105.64KB
core (index.js)2.96KB1.13KB
create-plugin (index.js)9.28KB2.98KB
data-objectstack (index.js)137.51KB35.11KB
fields (index.js)230.87KB56.83KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)2.65KB1.06KB
i18n (pickLocalized.js)1.70KB0.83KB
i18n (provider.js)9.48KB3.27KB
i18n (useObjectLabel.js)26.14KB6.07KB
i18n (useSafeTranslation.js)4.52KB1.96KB
layout (index.js)38.53KB10.71KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)8.75KB3.06KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.67KB1.12KB
permissions (evaluator.js)4.41KB1.44KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.55KB0.71KB
plugin-ai (index.js)15.71KB3.79KB
plugin-calendar (index.js)44.98KB12.37KB
plugin-charts (index.js)61.04KB17.31KB
plugin-chatbot (index.js)180.09KB42.72KB
plugin-dashboard (index.js)115.50KB29.96KB
plugin-designer (index.js)210.51KB42.51KB
plugin-detail (index.js)232.79KB57.42KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)112.10KB27.10KB
plugin-gantt (index.js)162.55KB39.57KB
plugin-grid (index.js)186.61KB49.34KB
plugin-kanban (index.js)48.30KB13.28KB
plugin-list (index.js)105.12KB25.48KB
plugin-map (index.js)16.81KB5.24KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)40.58KB10.58KB
plugin-timeline (index.js)25.76KB7.33KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.03KB20.55KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.67KB2.37KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)19.28KB6.38KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.02KB0.55KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)4.47KB2.03KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)2.71KB1.34KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@yinlianghui
yinlianghui marked this pull request as ready for review August 7, 2026 17:06
@yinlianghui
yinlianghui added this pull request to the merge queueAug 7, 2026
Merged via the queue into main with commit 0d5da53Aug 7, 2026
18 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3622-scan-roots-fourth-ext branch August 7, 2026 17:06
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Aug 10, 2026
…d READMEs carry (objectstack-ai#3664) (objectstack-ai#3695)
`packages/plugin-tree/README.md` was the only one of the 38 published packages
that had a README but no `## License` section. Census over origin/main:
- 38 published (non-private) packages
- 37 have a README (`sdui-parser` has none — out of scope, see objectstack-ai#3647)
- 36 of those 37 carry `## License`; plugin-tree was the sole omission
The section is copied verbatim from the dominant form, 32 of the 36:
## License
MIT — see [LICENSE](./LICENSE).
The four minority spellings are `MIT` (types, react-runtime) and
`MIT © ObjectStack Inc.` (plugin-timeline, plugin-chatbot). The issue suggested
plugin-timeline as the exemplar, but that form is 1-of-36 and carries no
`./LICENSE` link at all — the majority form is both the convention and the one
that gives the link gate something to check. Position matches too: final
section, as in 34 of the 36 (plugin-view and types continue past it).
This also closes the gap objectstack-ai#3664 identified: `check-doc-links.mjs` scan root 7
(`packages/*/README.md`, `disk` rule) resolves relative hrefs as repository
paths, so the new `./LICENSE` link is now mechanically checked against the file
PR objectstack-ai#3662 landed. Previously the README linked nothing, which is exactly why the
objectstack-ai#3622/objectstack-ai#3649 dead-link sweep could not detect the missing LICENSE — no link, no
dead link.
Verified the new link is load-bearing rather than vacuously green: temporarily
removing `packages/plugin-tree/LICENSE` turns the gate red with
`packages/plugin-tree/README.md:50 -> ./LICENSE` (exit 1); restoring it returns
`Links are valid across 7 scan roots` (exit 0).
No changeset: documentation-only, matching the precedent of PR objectstack-ai#3662 (which
added this same package's LICENSE, likewise shipped in the tarball) and PR objectstack-ai#3688
(36 package READMEs), neither of which carried one.
Fixesobjectstack-ai#3664
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@yinlianghui@claude