@longzai-intelligence-readme/cli 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -3
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -180,7 +180,7 @@ ${J.default.gray(au+ru.repeat(i+2)+ou)}
|
|
|
180
180
|
`);process.stdout.write(q.cursor.move(-999,e.length-1)),process.stdout.write(q.erase.down(e.length))},g=e=>e.replace(/\.+$/,``),_=e=>{let t=(performance.now()-e)/1e3,n=Math.floor(t/60),r=Math.floor(t%60);return n>0?`[${n}m ${r}s]`:`[${r}s]`},v=(u=``)=>{o=!0,i=Rl(),s=g(u),l=performance.now(),process.stdout.write(`${J.default.gray(Q)}
|
|
181
181
|
`);let d=0,f=0;p(),a=setInterval(()=>{if(r&&s===c)return;h(),c=s;let n=J.default.magenta(t[d]);if(r)process.stdout.write(`${n} ${s}...`);else if(e===`timer`)process.stdout.write(`${n} ${s} ${_(l)}`);else{let e=`.`.repeat(Math.floor(f)).slice(0,3);process.stdout.write(`${n} ${s}${e}`)}d=d+1<t.length?d+1:0,f=f<t.length?f+.125:0},n)},y=(t=``,n=0)=>{o=!1,clearInterval(a),h();let r=n===0?J.default.green($l):n===1?J.default.red(Zl):J.default.red(Ql);s=g(t??s),e===`timer`?process.stdout.write(`${r} ${s} ${_(l)}
|
|
182
182
|
`):process.stdout.write(`${r} ${s}
|
|
183
|
-
`),m(),i()};return{start:v,stop:y,message:(e=``)=>{s=g(e??s)}}},yu={red:e=>J.default.red(e),green:e=>J.default.green(e),yellow:e=>J.default.yellow(e),blue:e=>J.default.blue(e),cyan:e=>J.default.cyan(e),magenta:e=>J.default.magenta(e),gray:e=>J.default.gray(e),bold:e=>J.default.bold(e),dim:e=>J.default.dim(e)},bu={async select(e,t){let n=await hu({message:e,options:t.map(e=>({value:e.value,label:e.label,hint:e.hint}))});return Il(n)&&(_u(`操作已取消`),process.exit(0)),typeof n==`string`?n:String(n)},async textInput(e,t){let n=await pu({message:e,placeholder:t?.placeholder,defaultValue:t?.defaultValue});return Il(n)&&(_u(`操作已取消`),process.exit(0)),typeof n==`string`?n:String(n)},async confirm(e,t){let n=await mu({message:e,initialValue:t?.defaultValue??!1});return Il(n)&&(_u(`操作已取消`),process.exit(0)),typeof n==`boolean`?n:!!n},spinner(){let e=vu();return{start(t){e.start(t)},stop(t){e.stop(t)}}},note(e,t){gu(e,t)},log:{info(e){$.info(J.default.blue(e))},success(e){$.success(J.default.green(e))},warn(e){$.warn(J.default.yellow(e))},error(e){$.error(J.default.red(e))},step(e){$.step(e)}}};var xu=class extends Error{configPath;constructor(e,t){super(e),this.name=`SharedConfigError`,this.configPath=t}},Su=class extends xu{cause;constructor(e,t){super(`加载配置文件 ${e} 失败`,e),this.name=`SharedConfigLoadError`,this.cause=t}},Cu=class extends xu{searchFrom;constructor(e){super(`未在 ${e} 及其上级目录中找到 lzi.config.ts 配置文件`,e),this.name=`SharedConfigNotFoundError`,this.searchFrom=e}};function wu(e=process.cwd()){let n=c(e);for(;;){let e=s(n,`lzi.config.ts`);if(t(e))return e;let r=o(n);if(r===n)return null;n=r}}async function Tu(e={}){let t=e.cwd??process.cwd(),n=wu(t);if(n===null)throw new Cu(t);let r=c(n,`..`);try{return{config:(await import(n)).default,configPath:r,configFilePath:n}}catch(e){throw new Su(n,e)}}function Eu(e,n=process.cwd()){let r=Array.isArray(e)?e:[e],i=c(n);for(;;){for(let e of r){let n=s(i,e);if(t(n))return n}let e=o(i);if(e===i)return null;i=e}}async function Du(e={}){let t=e.cwd??c(process.cwd());if(e.standaloneFile){let n=Eu(e.standaloneFile,t);if(n)try{let e=await import(n);return{success:!0,config:e.default??e,source:`standalone`,configFilePath:n}}catch(e){throw new Su(n,e)}}if(e.unifiedField)try{let{config:n,configFilePath:r}=await Tu({cwd:t}),i=n?.[e.unifiedField];if(i!==void 0)return{success:!0,config:i,source:`unified`,configFilePath:r}}catch{}return{success:!1,configFilePath:null}}const Ou=`lzi-readme.config.ts`,ku=pc({file:Ps().min(1),rule:Ps().min(1),reason:Ps().min(1)}),Au=pc({domain:Ps().min(1).optional(),exemptions:dc(ku).default([])}),ju=(
|
|
184
|
-
`),Mu=e=>typeof e==`object`&&!!e,Nu=e=>{let t=Au.safeParse(e);if(!t.success){let e=t.error.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`;`);throw Error(`lzi-readme 配置非法:${e}`)}return t.data},Pu=async e=>{let t=await Du({standaloneFile:Ou,unifiedField:`readme`,cwd:e});return t.success?{config:Nu(t.config),configFilePath:t.configFilePath,source:t.source}:null},Fu=async e=>{let n=c(e);if(!t(n))throw Error(`配置文件不存在:${e}`);let r=await import(l(n).href);if(!Mu(r)||r.default===void 0)throw Error(`配置文件缺省导出:${e}`);return{config:Nu(r.default),configFilePath:n,source:`standalone`}},Iu=[{id:`E-BRAND-CN`,severity:`error`,pattern:/龙智|龙仔智能|隆智|龙崽/g,message:`中文品牌译名——品牌唯一正确表达为 "Longzai Intelligence",任何中文译名禁止`},{id:`E-SHORT-SCOPE`,severity:`error`,pattern:/@lzi\//g,message:`短 scope 包名——包名一律长形式 @longzai-intelligence-*`},{id:`E-BAD-ABBR`,severity:`error`,pattern:/\bLI\b|\bLZ\b/g,message:`禁用缩写——品牌缩写仅 LZI/lzi`},{id:`E-INTERNAL-NET`,severity:`error`,pattern:/\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3})\b|\b[\w-]+\.(?:local|internal|corp)\b/g,message:`内网地址/域名——README 按发布口径处理,不得含内网信息(示例也用占位形态)`},{id:`E-ABS-PATH`,severity:`error`,pattern:/\/Volumes\/|\/Users\/[A-Za-z0-9_-]+|\/home\/[A-Za-z0-9_-]+/g,message:`本机绝对路径——示例一律用 ~/ 或 <占位> 形态`},{id:`E-EMAIL`,severity:`error`,pattern:/[\w.+-]+@(?!([\w-]+\.)*example\.(?:com|org|net)\b)[A-Za-z][\w-]*(?:\.[\w-]+)*\.[A-Za-z]{2,}/g,message:`邮箱形态——README 不含联系方式(文档示例域 example.* 及其子域除外)`},{id:`E-CREDENTIAL`,severity:`error`,pattern:/(?:api[_-]?key|secret|passwd|password|token)\s*[:=]\s*(?!['"]?(?:your-|xxx|<))\S+/gi,message:`凭据形态——密钥/token/口令及其实值不得出现(占位示例除外)`},{id:`E-SCALE`,severity:`error`,pattern:/\d{2,}\s*个(?:子)?(?:项目|仓库|仓)/g,message:`内部规模数字(「N 个项目」类)——不入发布 README`},{id:`E-OPS`,severity:`error`,pattern:/\bbun\s+(?:push-all|push|version:upgrade-across|version:upgrade|agent:sync|vscode:sync)\b/g,message:`跨仓运维命令——产品群级操作不入 README`},{id:`E-ORG-COMPARE`,severity:`error`,pattern:/与\s*`?@longzai-intelligence-[a-z-]+`?(?:[、,]\s*`?@longzai-intelligence-[a-z-]+`?)*\s*同级/g,message:`内部组织结构对比表述——不入发布 README`},{id:`E-GIT-REMOTE`,severity:`error`,pattern:/git@[A-Za-z0-9.-]+:[\w./-]+|longzai-tech\b/g,message:`内部 git remote/组织账号/托管位置——不入 README`},{id:`E-DEV-CONSTRAINT`,severity:`error`,pattern:/禁止在[^,。\n]{0,12}(?:运行|执行)|请在(?:子包|各应用目录|应用目录|包目录|各仓)/g,message:`内部工程约束——面向仓内开发者的禁令/流程,迁内部承接文件`},{id:`E-MIT`,severity:`error`,pattern:/\[MIT\]|MIT License/gi,message:`MIT 表述——默认 UNLICENSED,禁默认 MIT`}],Lu=[{id:`W-MECH`,severity:`warn`,pattern:/\.lzi\/|\.lzi\b|lzi-architecture(?:\.sample)?\.yaml|docs\/ledgers|lzi-[a-z-]+\.config\.ts/g,message:`内部治理机制命名/路径(线索级,人工判定;机制即本仓产品者可豁免登记)`},{id:`W-TOOL`,severity:`warn`,pattern:/\blzi-(?:builder|projects|dev-cli|release|env|git|decision|issues|vscode|agent|npm-registry|bun)\b/g,message:`内部工具名(线索级,人工判定)`},{id:`W-ADR`,severity:`warn`,pattern:/ADR[\s-]?\d{3,4}/g,message:`ADR 编号引用(线索级,人工判定;指向本仓决策记录者可豁免登记)`}],Ru=[...Iu,...Lu],zu=/^#\s+Longzai Intelligence(\s|$)/,Bu=/^#\s+/,Vu=/^#{1,3}\s*(?:许可证|贡献|License|Contributing)\s*$/,Hu=/^#{1,3}\s*(?:创建初衷|工作范围)\s*$/,Uu=/[│├└]/,Wu=/#\s+\S/,Gu=/* @__PURE__ */ new Set([`node_modules`,`dist`,`out`,`.turbo`,`.git`,`build`,`.next`,`coverage`,`.cache`,`target`,`.venv`]),Ku=[`packages`,`apps`],qu=e=>{let t=[];Yu(s(e,`README.md`))&&t.push({relPath:`README.md`,kind:`root`});for(let n of Ku){let r=s(e,n);Xu(r)&&Ju(r,n,0,t)}return t},Ju=(e,t,n,i)=>{if(n>3)return;let a;try{a=r(e,{withFileTypes:!0})}catch{return}for(let r of a){if(Gu.has(r.name))continue;let a=`${t}/${r.name}`;r.isDirectory()?Ju(s(e,r.name),a,n+1,i):r.isFile()&&r.name===`README.md`&&i.push({relPath:a,kind:`nested`})}},Yu=e=>{try{return i(e).isFile()}catch{return!1}},Xu=e=>{try{return i(e).isDirectory()}catch{return!1}},Zu=(e,t)=>{let n=[],r=t.split(`
|
|
185
|
-
`);return n.push(...Qu(e.relPath,r)),n.push(...$u(e,r)),n.sort((e,t)=>(e.line??0)-(t.line??0)),n},Qu=(e,t)=>{let n=[];for(let r of Ru){let i=0;for(let a=0;a<t.length&&i<8;a+=1){let o=t[a];if(o===void 0)break;new RegExp(r.pattern.source,r.pattern.flags).test(o)&&(n.push({file:e,line:a+1,rule:r.id,severity:r.severity,message:r.message,excerpt:nd(o)}),i+=1)}}return n},$u=(e,t)=>{let n=[];e.kind===`root`&&n.push(...ed(e.relPath,t));let r=t.map((e,t)=>({line:e,number:t+1})).filter(e=>Vu.test(e.line));for(let t of r)n.push({file:e.relPath,line:t.number,rule:`E-FORBIDDEN-SECTION`,severity:`error`,message:`许可证/贡献段落——由 package.json 承载,README 不设该段`,excerpt:nd(t.line)});let i=t.map((e,t)=>({line:e,number:t+1})).filter(e=>Hu.test(e.line));for(let t of i)n.push({file:e.relPath,line:t.number,rule:`E-CHARTER-SECTION`,severity:`error`,message:`立项文体节(创建初衷/工作范围)——发布 README 精简口径,内部细节迁内部承接文件`,excerpt:nd(t.line)});return n.push(...td(e.relPath,t)),n},ed=(e,t)=>{let n=t.findIndex(e=>Bu.test(e)),r=n===-1?void 0:t[n];return r!==void 0&&zu.test(r)?[]:[{file:e,line:n===-1?null:n+1,rule:`E-ROOT-TITLE`,severity:`error`,message:"根标题须为 `# Longzai Intelligence <Name>`——缺品牌前缀/纯中文/仓库名或包名充当标题均不合规",excerpt:r===void 0?void 0:nd(r)}]},td=(e,t)=>{let n=[],r=t.map((e,t)=>({line:e,number:t+1})).filter(e=>Uu.test(e.line));if(r.length===0)return n;let i=r.filter(e=>Wu.test(e.line));return i.length>=3&&n.push({file:e,line:i[0]?.number??null,rule:`E-TREE-ANNOTATED`,severity:`error`,message:`结构树逐行注释(${i.length} 行)——树只表达层级,职责在正文说明`,excerpt:i[0]===void 0?void 0:nd(i[0].line)}),r.length>40&&n.push({file:e,line:r[0]?.number??null,rule:`E-TREE-LONG`,severity:`error`,message:`结构树过长(${r.length} 行 > 40)——发布 README 精简口径`,excerpt:r[0]===void 0?void 0:nd(r[0].line)}),n},nd=e=>{let t=e.trim();return t.length>120?`${t.slice(0,120)}…`:t},rd=e=>{let t=e.exemptions??[],r=qu(e.repoRoot),i=[];for(let t of r){let r=null;try{r=n(s(e.repoRoot,t.relPath),`utf8`)}catch{continue}i.push(...Zu(t,r))}let a=e=>{for(let n of t)if(n.file===e.file&&n.rule===e.rule)return n;return null},o=[],c=[];for(let e of i){let t=a(e);t===null?o.push(e):c.push({...e,reason:t.reason})}return{rulesVersion:`readme-rules@draft-v2`,specPointer:`longzai-intelligence-architecture/docs/ledgers/readme-publication-compliance/drafts/001(草案 v2,未经批准不作为正式规范)`,violations:o,exempted:c,summary:{filesScanned:r.length,rootCount:r.filter(e=>e.kind===`root`).length,nestedCount:r.filter(e=>e.kind===`nested`).length,errorCount:o.filter(e=>e.severity===`error`).length,warnCount:o.filter(e=>e.severity===`warn`).length,exemptedCount:c.length}}},id=e=>{let t=[];t.push(`[INFO] readme:check 规则版本 ${e.rulesVersion}`),t.push(`[INFO] 依据 ${e.specPointer}`),t.push(`[INFO] 扫描 README ${e.summary.filesScanned} 个(根 ${e.summary.rootCount}、嵌套 ${e.summary.nestedCount})`);for(let n of e.violations)t.push(ad(n));for(let n of e.exempted)t.push(od(n));return e.summary.errorCount===0?t.push(`[SUCCESS] readme:check 通过(0 error、${e.summary.warnCount} warn、豁免 ${e.summary.exemptedCount})`):t.push(`✖ ${e.summary.errorCount} error、${e.summary.warnCount} warn(豁免 ${e.summary.exemptedCount})`),t.join(`
|
|
183
|
+
`),m(),i()};return{start:v,stop:y,message:(e=``)=>{s=g(e??s)}}},yu={red:e=>J.default.red(e),green:e=>J.default.green(e),yellow:e=>J.default.yellow(e),blue:e=>J.default.blue(e),cyan:e=>J.default.cyan(e),magenta:e=>J.default.magenta(e),gray:e=>J.default.gray(e),bold:e=>J.default.bold(e),dim:e=>J.default.dim(e)},bu={async select(e,t){let n=await hu({message:e,options:t.map(e=>({value:e.value,label:e.label,hint:e.hint}))});return Il(n)&&(_u(`操作已取消`),process.exit(0)),typeof n==`string`?n:String(n)},async textInput(e,t){let n=await pu({message:e,placeholder:t?.placeholder,defaultValue:t?.defaultValue});return Il(n)&&(_u(`操作已取消`),process.exit(0)),typeof n==`string`?n:String(n)},async confirm(e,t){let n=await mu({message:e,initialValue:t?.defaultValue??!1});return Il(n)&&(_u(`操作已取消`),process.exit(0)),typeof n==`boolean`?n:!!n},spinner(){let e=vu();return{start(t){e.start(t)},stop(t){e.stop(t)}}},note(e,t){gu(e,t)},log:{info(e){$.info(J.default.blue(e))},success(e){$.success(J.default.green(e))},warn(e){$.warn(J.default.yellow(e))},error(e){$.error(J.default.red(e))},step(e){$.step(e)}}};var xu=class extends Error{configPath;constructor(e,t){super(e),this.name=`SharedConfigError`,this.configPath=t}},Su=class extends xu{cause;constructor(e,t){super(`加载配置文件 ${e} 失败`,e),this.name=`SharedConfigLoadError`,this.cause=t}},Cu=class extends xu{searchFrom;constructor(e){super(`未在 ${e} 及其上级目录中找到 lzi.config.ts 配置文件`,e),this.name=`SharedConfigNotFoundError`,this.searchFrom=e}};function wu(e=process.cwd()){let n=c(e);for(;;){let e=s(n,`lzi.config.ts`);if(t(e))return e;let r=o(n);if(r===n)return null;n=r}}async function Tu(e={}){let t=e.cwd??process.cwd(),n=wu(t);if(n===null)throw new Cu(t);let r=c(n,`..`);try{return{config:(await import(n)).default,configPath:r,configFilePath:n}}catch(e){throw new Su(n,e)}}function Eu(e,n=process.cwd()){let r=Array.isArray(e)?e:[e],i=c(n);for(;;){for(let e of r){let n=s(i,e);if(t(n))return n}let e=o(i);if(e===i)return null;i=e}}async function Du(e={}){let t=e.cwd??c(process.cwd());if(e.standaloneFile){let n=Eu(e.standaloneFile,t);if(n)try{let e=await import(n);return{success:!0,config:e.default??e,source:`standalone`,configFilePath:n}}catch(e){throw new Su(n,e)}}if(e.unifiedField)try{let{config:n,configFilePath:r}=await Tu({cwd:t}),i=n?.[e.unifiedField];if(i!==void 0)return{success:!0,config:i,source:`unified`,configFilePath:r}}catch{}return{success:!1,configFilePath:null}}const Ou=`lzi-readme.config.ts`,ku=pc({file:Ps().min(1),rule:Ps().min(1),reason:Ps().min(1)}),Au=pc({domain:Ps().min(1).optional(),exemptions:dc(ku).default([])}),ju=()=>[`import { defineConfig } from '@longzai-intelligence-readme/config';`,``,`/**`,` * lzi-readme 配置`,` */`,`export default defineConfig();`,``].join(`
|
|
184
|
+
`),Mu=e=>typeof e==`object`&&!!e,Nu=e=>{let t=Au.safeParse(e);if(!t.success){let e=t.error.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`;`);throw Error(`lzi-readme 配置非法:${e}`)}return t.data},Pu=async e=>{let t=await Du({standaloneFile:Ou,unifiedField:`readme`,cwd:e});return t.success?{config:Nu(t.config),configFilePath:t.configFilePath,source:t.source}:null},Fu=async e=>{let n=c(e);if(!t(n))throw Error(`配置文件不存在:${e}`);let r=await import(l(n).href);if(!Mu(r)||r.default===void 0)throw Error(`配置文件缺省导出:${e}`);return{config:Nu(r.default),configFilePath:n,source:`standalone`}},Iu=[{id:`E-BRAND-CN`,severity:`error`,pattern:/龙智|龙仔智能|隆智|龙崽/g,message:`中文品牌译名——品牌唯一正确表达为 "Longzai Intelligence",任何中文译名禁止`},{id:`E-SHORT-SCOPE`,severity:`error`,pattern:/@lzi\//g,message:`短 scope 包名——包名一律长形式 @longzai-intelligence-*`},{id:`E-BAD-ABBR`,severity:`error`,pattern:/\bLI\b|\bLZ\b/g,message:`禁用缩写——品牌缩写仅 LZI/lzi`},{id:`E-INTERNAL-NET`,severity:`error`,pattern:/\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3})\b|\b[\w-]+\.(?:local|internal|corp)\b/g,message:`内网地址/域名——README 按发布口径处理,不得含内网信息(示例也用占位形态)`},{id:`E-ABS-PATH`,severity:`error`,pattern:/\/Volumes\/|\/Users\/[A-Za-z0-9_-]+|\/home\/[A-Za-z0-9_-]+/g,message:`本机绝对路径——示例一律用 ~/ 或 <占位> 形态`},{id:`E-EMAIL`,severity:`error`,pattern:/[\w.+-]+@(?!([\w-]+\.)*example\.(?:com|org|net)\b)[A-Za-z][\w-]*(?:\.[\w-]+)*\.[A-Za-z]{2,}/g,message:`邮箱形态——README 不含联系方式(文档示例域 example.* 及其子域除外)`},{id:`E-CREDENTIAL`,severity:`error`,pattern:/(?:api[_-]?key|secret|passwd|password|token)\s*[:=]\s*(?!['"]?(?:your-|xxx|<))\S+/gi,message:`凭据形态——密钥/token/口令及其实值不得出现(占位示例除外)`},{id:`E-SCALE`,severity:`error`,pattern:/\d{2,}\s*个(?:子)?(?:项目|仓库|仓)/g,message:`内部规模数字(「N 个项目」类)——不入发布 README`},{id:`E-OPS`,severity:`error`,pattern:/\bbun\s+(?:push-all|push|version:upgrade-across|version:upgrade|agent:sync|vscode:sync)\b/g,message:`跨仓运维命令——产品群级操作不入 README`},{id:`E-ORG-COMPARE`,severity:`error`,pattern:/与\s*`?@longzai-intelligence-[a-z-]+`?(?:[、,]\s*`?@longzai-intelligence-[a-z-]+`?)*\s*同级/g,message:`内部组织结构对比表述——不入发布 README`},{id:`E-GIT-REMOTE`,severity:`error`,pattern:/git@[A-Za-z0-9.-]+:[\w./-]+|longzai-tech\b/g,message:`内部 git remote/组织账号/托管位置——不入 README`},{id:`E-DEV-CONSTRAINT`,severity:`error`,pattern:/禁止在[^,。\n]{0,12}(?:运行|执行)|请在(?:子包|各应用目录|应用目录|包目录|各仓)/g,message:`内部工程约束——面向仓内开发者的禁令/流程,迁内部承接文件`},{id:`E-MIT`,severity:`error`,pattern:/\[MIT\]|MIT License/gi,message:`MIT 表述——默认 UNLICENSED,禁默认 MIT`}],Lu=[{id:`W-MECH`,severity:`warn`,pattern:/\.lzi\/|\.lzi\b|lzi-architecture(?:\.sample)?\.yaml|docs\/ledgers|lzi-[a-z-]+\.config\.ts/g,message:`内部治理机制命名/路径(线索级,人工判定;机制即本仓产品者可豁免登记)`},{id:`W-TOOL`,severity:`warn`,pattern:/\blzi-(?:builder|projects|dev-cli|release|env|git|decision|issues|vscode|agent|npm-registry|bun)\b/g,message:`内部工具名(线索级,人工判定)`},{id:`W-ADR`,severity:`warn`,pattern:/ADR[\s-]?\d{3,4}/g,message:`ADR 编号引用(线索级,人工判定;指向本仓决策记录者可豁免登记)`}],Ru=[...Iu,...Lu],zu=/^#\s+Longzai Intelligence(\s|$)/,Bu=/^#\s+/,Vu=/^#{1,3}\s*(?:许可证|贡献|License|Contributing)\s*$/,Hu=/^#{1,3}\s*(?:创建初衷|工作范围)\s*$/,Uu=/[│├└]/,Wu=/#\s+\S/,Gu=/* @__PURE__ */ new Set([`node_modules`,`dist`,`out`,`.turbo`,`.git`,`build`,`.next`,`coverage`,`.cache`,`target`,`.venv`,`docs`]),Ku=[`packages`,`apps`],qu=e=>{let t=[];Yu(s(e,`README.md`))&&t.push({relPath:`README.md`,kind:`root`});for(let n of Ku){let r=s(e,n);Xu(r)&&Ju(r,n,0,t)}return t},Ju=(e,t,n,i)=>{if(n>3)return;let a;try{a=r(e,{withFileTypes:!0})}catch{return}for(let r of a){if(Gu.has(r.name))continue;let a=`${t}/${r.name}`;r.isDirectory()?Ju(s(e,r.name),a,n+1,i):r.isFile()&&r.name===`README.md`&&i.push({relPath:a,kind:`nested`})}},Yu=e=>{try{return i(e).isFile()}catch{return!1}},Xu=e=>{try{return i(e).isDirectory()}catch{return!1}},Zu=(e,t)=>{let n=[],r=t.split(`
|
|
185
|
+
`);return n.push(...Qu(e.relPath,r)),n.push(...$u(e,r)),n.sort((e,t)=>(e.line??0)-(t.line??0)),n},Qu=(e,t)=>{let n=[];for(let r of Ru){let i=0;for(let a=0;a<t.length&&i<8;a+=1){let o=t[a];if(o===void 0)break;new RegExp(r.pattern.source,r.pattern.flags).test(o)&&(n.push({file:e,line:a+1,rule:r.id,severity:r.severity,message:r.message,excerpt:nd(o)}),i+=1)}}return n},$u=(e,t)=>{let n=[];e.kind===`root`&&n.push(...ed(e.relPath,t));let r=t.map((e,t)=>({line:e,number:t+1})).filter(e=>Vu.test(e.line));for(let t of r)n.push({file:e.relPath,line:t.number,rule:`E-FORBIDDEN-SECTION`,severity:`error`,message:`许可证/贡献段落——由 package.json 承载,README 不设该段`,excerpt:nd(t.line)});let i=t.map((e,t)=>({line:e,number:t+1})).filter(e=>Hu.test(e.line));for(let t of i)n.push({file:e.relPath,line:t.number,rule:`E-CHARTER-SECTION`,severity:`error`,message:`立项文体节(创建初衷/工作范围)——发布 README 精简口径,内部细节迁内部承接文件`,excerpt:nd(t.line)});return n.push(...td(e.relPath,t)),n},ed=(e,t)=>{let n=t.findIndex(e=>Bu.test(e)),r=n===-1?void 0:t[n];return r!==void 0&&zu.test(r)?[]:[{file:e,line:n===-1?null:n+1,rule:`E-ROOT-TITLE`,severity:`error`,message:"根标题须为 `# Longzai Intelligence <Name>`——缺品牌前缀/纯中文/仓库名或包名充当标题均不合规",excerpt:r===void 0?void 0:nd(r)}]},td=(e,t)=>{let n=[],r=t.map((e,t)=>({line:e,number:t+1})).filter(e=>Uu.test(e.line));if(r.length===0)return n;let i=r.filter(e=>Wu.test(e.line));return i.length>=3&&n.push({file:e,line:i[0]?.number??null,rule:`E-TREE-ANNOTATED`,severity:`error`,message:`结构树逐行注释(${i.length} 行)——树只表达层级,职责在正文说明`,excerpt:i[0]===void 0?void 0:nd(i[0].line)}),r.length>40&&n.push({file:e,line:r[0]?.number??null,rule:`E-TREE-LONG`,severity:`error`,message:`结构树过长(${r.length} 行 > 40)——发布 README 精简口径`,excerpt:r[0]===void 0?void 0:nd(r[0].line)}),n},nd=e=>{let t=e.trim();return t.length>120?`${t.slice(0,120)}…`:t},rd=e=>{let t=e.exemptions??[],r=qu(e.repoRoot),i=[];for(let t of r){let r=null;try{r=n(s(e.repoRoot,t.relPath),`utf8`)}catch{continue}i.push(...Zu(t,r))}let a=e=>{for(let n of t)if(n.file===e.file&&n.rule===e.rule)return n;return null},o=[],c=[];for(let e of i){let t=a(e);t===null?o.push(e):c.push({...e,reason:t.reason})}return{rulesVersion:`readme-rules@draft-v2.1`,specPointer:`longzai-intelligence-architecture/docs/ledgers/readme-publication-compliance/drafts/001(草案 v2,未经批准不作为正式规范)`,violations:o,exempted:c,summary:{filesScanned:r.length,rootCount:r.filter(e=>e.kind===`root`).length,nestedCount:r.filter(e=>e.kind===`nested`).length,errorCount:o.filter(e=>e.severity===`error`).length,warnCount:o.filter(e=>e.severity===`warn`).length,exemptedCount:c.length}}},id=e=>{let t=[];t.push(`[INFO] readme:check 规则版本 ${e.rulesVersion}`),t.push(`[INFO] 依据 ${e.specPointer}`),t.push(`[INFO] 扫描 README ${e.summary.filesScanned} 个(根 ${e.summary.rootCount}、嵌套 ${e.summary.nestedCount})`);for(let n of e.violations)t.push(ad(n));for(let n of e.exempted)t.push(od(n));return e.summary.errorCount===0?t.push(`[SUCCESS] readme:check 通过(0 error、${e.summary.warnCount} warn、豁免 ${e.summary.exemptedCount})`):t.push(`✖ ${e.summary.errorCount} error、${e.summary.warnCount} warn(豁免 ${e.summary.exemptedCount})`),t.join(`
|
|
186
186
|
`)},ad=e=>{let t=e.line===null?e.file:`${e.file}:${e.line}`,n=e.excerpt===void 0?``:`|摘录:${e.excerpt}`;return`${t} [${e.rule}] ${e.message}${n}`},od=e=>`[豁免] ${e.line===null?e.file:`${e.file}:${e.line}`} [${e.rule}](原因:${e.reason})`,sd=e=>JSON.stringify(e,null,2),cd=e=>{process.stdout.write(`${e}\n`)},ld=e=>{process.stderr.write(`${e}\n`)},ud=async e=>{let t=c(e.cwd??process.cwd()),n=null;try{n=e.config===void 0?await Pu(t):await Fu(e.config)}catch(e){return ld(`错误: ${e instanceof Error?e.message:String(e)}`),2}let r=n?.config.exemptions??[],i=rd({repoRoot:t,exemptions:r});return e.format===`json`?cd(sd(i)):(n===null&&cd(`[INFO] 未找到 lzi-readme.config.ts,按默认规则(零豁免)运行`),cd(id(i))),i.summary.errorCount>0?(ld(`错误: readme:check ${i.summary.errorCount} 项 error 违例|warn ${i.summary.warnCount}|豁免 ${i.summary.exemptedCount}`),1):0},dd=async e=>{let n=c(e.cwd??process.cwd()),r=s(n,Ou);if(t(r))return ld(`错误: 配置已存在,拒绝覆盖:${r}`),1;let i=ju();return e.dryRun===!0?(cd(`[INFO] dry-run:将写入 ${r}`),cd(i),0):(a(r,i),cd(`[SUCCESS] 已生成 ${r}`),0)};function fd(e){pd(e),md(e)}function pd(e){rl(e,{name:`check`,description:`README 发布合规门禁(品牌规范 + 内部信息负面清单,规则版本随报告输出)`,options:[{flags:`--cwd <path>`,description:`目标仓根目录(缺省当前目录)`},{flags:`--format <format>`,description:`输出格式:text(缺省)| json`},{flags:`--config <path>`,description:`显式配置文件路径(覆盖自动查找)`}],schema:mc({cwd:Ps().optional(),format:bc([`text`,`json`]).optional(),config:Ps().optional()}),action:async e=>{let t=await ud({cwd:e.cwd,format:e.format,config:e.config});t>0&&process.exit(t)}})}function md(e){rl(e,{name:`init`,description:`生成 lzi-readme.config.ts 配置骨架(豁免登记清单)`,options:[{flags:`--cwd <path>`,description:`目标仓根目录(缺省当前目录)`},{flags:`--dry-run`,description:`仅预览不写盘`}],schema:mc({cwd:Ps().optional(),dryRun:ac().optional()}),action:async e=>{let t=await dd({cwd:e.cwd,dryRun:e.dryRun===!0});t>0&&process.exit(t)}})}const hd=$c({name:`lzi-readme`,description:`Longzai Intelligence README 发布合规门禁(发布口径:品牌规范 + 内部信息负面清单)`,interaction:bu,color:yu});fd(hd);async function gd(){await hd.parseAsync(process.argv)}gd().catch(e=>{process.stderr.write(`错误: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)});export{};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longzai-intelligence-readme/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Longzai Intelligence README 门禁 CLI(lzi-readme)",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@longzai-intelligence-cli/core": "^0.0.10",
|
|
38
38
|
"@longzai-intelligence-cli/standard": "^0.0.10",
|
|
39
|
-
"@longzai-intelligence-readme/config": "0.0.
|
|
40
|
-
"@longzai-intelligence-readme/core": "0.0.
|
|
39
|
+
"@longzai-intelligence-readme/config": "0.0.2",
|
|
40
|
+
"@longzai-intelligence-readme/core": "0.0.2",
|
|
41
41
|
"zod": "^4.4.3"
|
|
42
42
|
}
|
|
43
43
|
}
|