@longzai-intelligence-issues/config 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.
@@ -0,0 +1,5 @@
1
+ $ lzi-builder
2
+ ℹ lzi-builder v0.2.19 powered by rolldown v1.2.8
3
+ ℹ @longzai-intelligence-issues/config tsconfig: tsconfig/build.json
4
+ ℹ Cleaning 5 files
5
+ TypeScript 7.0 尚未提供稳定的 API,仍处于实验阶段。部分选项将不可用。
@@ -0,0 +1,7 @@
1
+ $ oxlint && oxfmt --check
2
+ Found 0 warnings and 0 errors.
3
+ Finished in 159ms on 13 files with 186 rules using 10 threads.
4
+ Checking formatting...
5
+
6
+ All matched files use the correct format.
7
+ Finished in 134ms on 22 files using 10 threads.
@@ -0,0 +1,3 @@
1
+ $ lzi-bun-cli test
2
+ 错误: /Volumes/JZAO/j-projects/workspaces/longzai/longzai-intelligence/longzai-intelligence-m5-edition/longzai-intelligence-issues/packages/config/bunfig.toml 已存在且非 lzi-bun-cli 生成(缺少 @lzi-bun-cli 自动生成,请勿编辑 标记),如需 lzi-bun-cli 接管,请删除该文件或手动合并后重试
3
+ error: script "test" exited with code 1
@@ -0,0 +1,4 @@
1
+ $ bun run typecheck:app && bun run typecheck:node && bun run typecheck:test
2
+ $ lzi-tsgo typecheck tsconfig/app.json
3
+ $ lzi-tsgo typecheck tsconfig/node.json
4
+ $ lzi-tsgo typecheck tsconfig/test.json
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@
5
5
  格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
6
6
  本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
7
7
 
8
+ ## [0.0.2] - 2026-09-14
9
+
10
+ ### 变更
11
+
12
+ - slugDigitPolicy 值域扩展为 forbid|allow(缺省 forbid;scope 级数字 slug 放行档位)
13
+ - init 脚手架模板 import 指向 @longzai-intelligence-issues/cli 再出口(采用仓单依赖接入)
14
+
8
15
  ## [0.0.1] - 2026-09-14
9
16
 
10
17
  ### 新增
package/dist/index.d.ts CHANGED
@@ -63,7 +63,10 @@ declare const scopeSchema: z.ZodObject<{
63
63
  reason: z.ZodString;
64
64
  }, z.core.$strip>>;
65
65
  }, z.core.$strip>>;
66
- slugDigitPolicy: z.ZodOptional<z.ZodLiteral<"forbid">>;
66
+ slugDigitPolicy: z.ZodOptional<z.ZodEnum<{
67
+ allow: "allow";
68
+ forbid: "forbid";
69
+ }>>;
67
70
  }, z.core.$strip>;
68
71
  /**
69
72
  * scope 注册条目(书写形态)
@@ -102,7 +105,10 @@ declare const lziIssuesConfigSchema: z.ZodObject<{
102
105
  reason: z.ZodString;
103
106
  }, z.core.$strip>>;
104
107
  }, z.core.$strip>>;
105
- slugDigitPolicy: z.ZodOptional<z.ZodLiteral<"forbid">>;
108
+ slugDigitPolicy: z.ZodOptional<z.ZodEnum<{
109
+ allow: "allow";
110
+ forbid: "forbid";
111
+ }>>;
106
112
  }, z.core.$strip>>;
107
113
  lint: z.ZodDefault<z.ZodObject<{
108
114
  baseline: z.ZodDefault<z.ZodArray<z.ZodObject<{
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import"./rolldown-runtime-BqT_7tdF.js";import*as e from"zod";import{loadUnifiedConfig as t}from"@longzai-intelligence-shared-config/core";import{existsSync as n}from"node:fs";import{resolve as r}from"node:path";import{pathToFileURL as i}from"node:url";const a=[`files`,`sqlite`,`postgres`,`mysql`,`memory`],o=[`待补跑`,`待复跑`,`待低负载`,`环境不具备`,`挂起`,`后补跑`],s=`^\\d{1,4}[-._]`,c=[`docs`],l=`docs/issues`,u=`.lzi/issues/issues.sqlite`,d=/^[a-z][a-z0-9-]*$/,f=/^\d+$/,p=/^\.[A-Za-z0-9]+$/,m=e.object({number:e.string().regex(f),reason:e.string().min(1)}),h=e.object({file:e.string().min(1),rule:e.string().min(1),issue:e.string().min(1)}),g=e.object({glob:e.string().min(1),reason:e.string().min(1)}),_=e.object({key:e.string().regex(d),title:e.string().min(1),paths:e.array(e.string().min(1)).min(1),registryDir:e.string().min(1),numbering:e.object({reserved:e.array(m)}).default({reserved:[]}),slugDigitPolicy:e.literal(`forbid`).optional()}),v=e.object({strategy:e.enum(a).default(`files`),sqlitePath:e.string().min(1).default(u)}),y=e.object({baseline:e.array(h).default([]),strictLegacy:e.boolean().default(!1),rulePacks:e.array(e.string().min(1)).default([])}),b=e.object({scopeKey:e.string().min(1),number:e.string().regex(f),files:e.array(e.string().min(1)).min(2),status:e.enum([`待清偿`,`维持现状`]),reason:e.string().min(1)}),x=e.object({allowlist:e.array(b).default([]),globalExclusions:e.array(g).default([]),audit:e.object({roots:e.array(e.string().min(1)).min(1).default([...c]),numberishPattern:e.string().min(1).default(s),pending:e.array(g).default([])}).default({roots:[...c],numberishPattern:s,pending:[]})}),S=e.object({scanRoots:e.array(e.string().min(1)).min(1),includeExtensions:e.array(e.string().regex(p)).default([`.md`]),exclusions:e.array(g).default([]),baseline:e.array(h).default([])}),C=e.object({pendingWords:e.array(e.string().min(1)).default([...o]),heavyPattern:e.string().min(1).optional(),fullPattern:e.string().min(1).optional(),blockingMustBeGreen:e.boolean().default(!0)}),w=e.object({builtin:e.boolean().default(!0),extraDir:e.string().min(1).optional()}),T=e.object({schemaVersion:e.literal(1),storage:v.default({strategy:`files`,sqlitePath:u}),scopes:e.array(_).min(1),lint:y.default({baseline:[],strictLegacy:!1,rulePacks:[]}),numbering:x.default({allowlist:[],globalExclusions:[],audit:{roots:[...c],numberishPattern:s,pending:[]}}),slugDigitAllowlist:e.array(g).default([]),docs:S.optional(),close:C.default({pendingWords:[...o],blockingMustBeGreen:!0}),prompts:w.default({builtin:!0})});function E(e){let t=T.safeParse(e);if(!t.success){let e=t.error.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`;`);throw Error(`lzi-issues 配置形态非法:${e}`)}return t.data}function D(e){return e}const O=[`/**`," * lzi-issues 配置(单一真源)——由 `lzi-issues init` 生成。",` *`,` * 引擎零仓库知识:一切仓库特有信息(scope 注册 / 扫描面 / 门禁参数)只在本文件登记。`,` * 存储默认 files(Local First):issue 为注册表 markdown,派生数据统一 .lzi/issues/。`,` */`].join(`
1
+ import"./rolldown-runtime-BqT_7tdF.js";import*as e from"zod";import{loadUnifiedConfig as t}from"@longzai-intelligence-shared-config/core";import{existsSync as n}from"node:fs";import{resolve as r}from"node:path";import{pathToFileURL as i}from"node:url";const a=[`files`,`sqlite`,`postgres`,`mysql`,`memory`],o=[`待补跑`,`待复跑`,`待低负载`,`环境不具备`,`挂起`,`后补跑`],s=`^\\d{1,4}[-._]`,c=[`docs`],l=`docs/issues`,u=`.lzi/issues/issues.sqlite`,d=/^[a-z][a-z0-9-]*$/,f=/^\d+$/,p=/^\.[A-Za-z0-9]+$/,m=e.object({number:e.string().regex(f),reason:e.string().min(1)}),h=e.object({file:e.string().min(1),rule:e.string().min(1),issue:e.string().min(1)}),g=e.object({glob:e.string().min(1),reason:e.string().min(1)}),_=e.object({key:e.string().regex(d),title:e.string().min(1),paths:e.array(e.string().min(1)).min(1),registryDir:e.string().min(1),numbering:e.object({reserved:e.array(m)}).default({reserved:[]}),slugDigitPolicy:e.enum([`forbid`,`allow`]).optional()}),v=e.object({strategy:e.enum(a).default(`files`),sqlitePath:e.string().min(1).default(u)}),y=e.object({baseline:e.array(h).default([]),strictLegacy:e.boolean().default(!1),rulePacks:e.array(e.string().min(1)).default([])}),b=e.object({scopeKey:e.string().min(1),number:e.string().regex(f),files:e.array(e.string().min(1)).min(2),status:e.enum([`待清偿`,`维持现状`]),reason:e.string().min(1)}),x=e.object({allowlist:e.array(b).default([]),globalExclusions:e.array(g).default([]),audit:e.object({roots:e.array(e.string().min(1)).min(1).default([...c]),numberishPattern:e.string().min(1).default(s),pending:e.array(g).default([])}).default({roots:[...c],numberishPattern:s,pending:[]})}),S=e.object({scanRoots:e.array(e.string().min(1)).min(1),includeExtensions:e.array(e.string().regex(p)).default([`.md`]),exclusions:e.array(g).default([]),baseline:e.array(h).default([])}),C=e.object({pendingWords:e.array(e.string().min(1)).default([...o]),heavyPattern:e.string().min(1).optional(),fullPattern:e.string().min(1).optional(),blockingMustBeGreen:e.boolean().default(!0)}),w=e.object({builtin:e.boolean().default(!0),extraDir:e.string().min(1).optional()}),T=e.object({schemaVersion:e.literal(1),storage:v.default({strategy:`files`,sqlitePath:u}),scopes:e.array(_).min(1),lint:y.default({baseline:[],strictLegacy:!1,rulePacks:[]}),numbering:x.default({allowlist:[],globalExclusions:[],audit:{roots:[...c],numberishPattern:s,pending:[]}}),slugDigitAllowlist:e.array(g).default([]),docs:S.optional(),close:C.default({pendingWords:[...o],blockingMustBeGreen:!0}),prompts:w.default({builtin:!0})});function E(e){let t=T.safeParse(e);if(!t.success){let e=t.error.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`;`);throw Error(`lzi-issues 配置形态非法:${e}`)}return t.data}function D(e){return e}const O=[`/**`," * lzi-issues 配置(单一真源)——由 `lzi-issues init` 生成。",` *`,` * 引擎零仓库知识:一切仓库特有信息(scope 注册 / 扫描面 / 门禁参数)只在本文件登记。`,` * 存储默认 files(Local First):issue 为注册表 markdown,派生数据统一 .lzi/issues/。`,` */`].join(`
2
2
  `);function k(e){return`'${e.replace(/\\/g,`\\\\`).replace(/'/g,`\\'`).replace(/\n/g,`\\n`)}'`}function A(e,t){if(e.length===0)return`[]`;let n=` `.repeat(t+1),r=` `.repeat(t);return e.every(e=>typeof e==`object`&&!!e)?`[\n${e.map(e=>`${n}${N(e,t+1)},`).join(`
3
3
  `)}\n${r}]`:`[${e.map(e=>N(e,t+1)).join(`, `)}]`}function j(e,t){let n=Object.keys(e).filter(t=>e[t]!==void 0);if(n.length===0)return`{}`;let r=` `.repeat(t+1),i=` `.repeat(t);return`{\n${n.map(n=>`${r}${n}: ${N(e[n],t+1)},`).join(`
4
- `)}\n${i}}`}function M(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function N(e,t){return typeof e==`string`?k(e):Array.isArray(e)?A(e,t):M(e)?j(e,t):String(e)}function P(e){return`export default defineConfig(${N(e,0)});\n`}function F(e,t=O){return`import { defineConfig } from '@longzai-intelligence-issues/config';\n\n${t}\n${P(e)}`}function I(e){return N({key:e.key,title:e.title,paths:e.paths??[`.`],registryDir:e.registryDir??`docs/issues`},2).trimStart()}function L(e){return F({schemaVersion:1,scopes:[{key:e.key,title:e.title,paths:e.paths??[`.`],registryDir:e.registryDir??`docs/issues`}]})}function R(e,t){let n=e[t]??``,r={"[":`]`,"{":`}`,"(":`)`}[n];if(r===void 0)throw Error(`扫描起点不是开括号:位置 ${t}`);let i=0;for(let a=t;a<e.length;a+=1){let t=e[a]??``,o=e[a+1]??``;if(t===`/`&&o===`/`){if(a=e.indexOf(`
4
+ `)}\n${i}}`}function M(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function N(e,t){return typeof e==`string`?k(e):Array.isArray(e)?A(e,t):M(e)?j(e,t):String(e)}function P(e){return`export default defineConfig(${N(e,0)});\n`}function F(e,t=O){return`import { defineConfig } from '@longzai-intelligence-issues/cli';\n\n${t}\n${P(e)}`}function I(e){return N({key:e.key,title:e.title,paths:e.paths??[`.`],registryDir:e.registryDir??`docs/issues`},2).trimStart()}function L(e){return F({schemaVersion:1,scopes:[{key:e.key,title:e.title,paths:e.paths??[`.`],registryDir:e.registryDir??`docs/issues`}]})}function R(e,t){let n=e[t]??``,r={"[":`]`,"{":`}`,"(":`)`}[n];if(r===void 0)throw Error(`扫描起点不是开括号:位置 ${t}`);let i=0;for(let a=t;a<e.length;a+=1){let t=e[a]??``,o=e[a+1]??``;if(t===`/`&&o===`/`){if(a=e.indexOf(`
5
5
  `,a),a===-1)break;continue}if(t===`/`&&o===`*`){if(a=e.indexOf(`*/`,a+2),a===-1)throw Error(`括号扫描遇未闭合块注释`);a+=1;continue}if(t===`'`||t===`"`||t==="`"){for(a+=1;a<e.length;){let n=e[a]??``;if(n===`\\`){a+=2;continue}if(n===t)break;a+=1}continue}if(t===n)i+=1;else if(t===r&&(--i,i===0))return a}throw Error(`括号不配平:scopes 数组未闭合`)}function z(e,t){if(RegExp(`key\\s*:\\s*'${t.key}'`).test(e))throw Error(`scope key「${t.key}」已注册,拒绝重复追加`);let n=/scopes\s*:\s*\[/.exec(e);if(n===null)throw Error(`配置文件缺少 scopes 数组,无法追加 scope`);let r=R(e,(n.index??0)+n[0].length-1),i=r-1;for(;i>=0&&/\s/.test(e[i]??``);)--i;let a=e[i]===`,`?`\n ${I(t)}`:`,\n ${I(t)}`;return`${e.slice(0,r)}${a}${e.slice(r)}`}const B=[`/**`," * lzi-issues 配置(单一真源)——由 `--write-baseline --issue <指针>` 再生。",` *`,` * 棘轮基线语义:基线按 (file, rule) 精确命中豁免存量违规;基线外新增违规仍红;`,` * 基线条目无对应现行违规计陈旧红——修复存量即须同步删除对应条目,棘轮只许缩短直至清零;`,` * 每条豁免必须携带 issue 收编指针(非空)。`,` *`,` * 注意:再生以解析值重建本文件,节内手工注释不保留——长篇说明请写入 docs/guides。`,` */`].join(`
6
6
  `);function V(e){let t=new Map;for(let n of e){let e=`${n.file}::${n.rule}`;t.has(e)||t.set(e,{...n})}return[...t.values()].sort((e,t)=>e.file===t.file?e.rule.localeCompare(t.rule):e.file.localeCompare(t.file))}function H(e,t,n){let r=V(n);if(t===`lint`)return F({schemaVersion:e.schemaVersion,storage:e.storage,scopes:e.scopes,lint:{...e.lint,baseline:r},numbering:e.numbering,slugDigitAllowlist:e.slugDigitAllowlist,docs:e.docs,close:e.close,prompts:e.prompts},B);if(e.docs===void 0)throw Error(`配置未登记 docs 节,无法再生 docs 基线`);return F({schemaVersion:e.schemaVersion,storage:e.storage,scopes:e.scopes,lint:e.lint,numbering:e.numbering,slugDigitAllowlist:e.slugDigitAllowlist,docs:{...e.docs,baseline:r},close:e.close,prompts:e.prompts},B)}function U(e,t,n){(t.startsWith(`/`)||t.startsWith(`\\`))&&n.push(`${e}「${t}」不得为绝对路径`),t.includes(`\\`)&&n.push(`${e}「${t}」不得包含反斜杠(须为 posix 相对路径)`),t.split(`/`).includes(`..`)&&n.push(`${e}「${t}」不得包含 .. 上溯段`)}function W(e,t,n){t.includes(`\\`)&&n.push(`${e}「${t}」不得包含反斜杠`),t.startsWith(`/`)&&n.push(`${e}「${t}」不得以 / 起首(须为仓库相对 glob)`)}function G(e,t,n){let r=new Set;for(let i of t)r.has(i)&&n.push(`${e} 存在重复 glob「${i}」`),r.add(i)}function K(e){let t=[],n=new Set;e.scopes.forEach((e,r)=>{let i=`scopes[${r}](${e.key})`;n.has(e.key)&&t.push(`scope key「${e.key}」重复注册`),n.add(e.key),U(`${i}.registryDir`,e.registryDir,t);let a=new Set;for(let n of e.numbering.reserved)a.has(n.number)&&t.push(`${i} 保留号「${n.number}」重复登记`),a.add(n.number)});let r=new Set;for(let n of e.lint.baseline){let e=`${n.file}::${n.rule}`;r.has(e)&&t.push(`lint.baseline 条目(${n.file}, ${n.rule})重复`),r.add(e)}if(e.docs!==void 0){let n=new Set;for(let r of e.docs.baseline){let e=`${r.file}::${r.rule}`;n.has(e)&&t.push(`docs.baseline 条目(${r.file}, ${r.rule})重复`),n.add(e)}for(let n of e.docs.exclusions)W(`docs.exclusions`,n.glob,t);G(`docs.exclusions`,e.docs.exclusions.map(e=>e.glob),t);for(let n of e.docs.scanRoots)U(`docs.scanRoots`,n,t)}let i=new Set;for(let r of e.numbering.allowlist){n.has(r.scopeKey)||t.push(`numbering.allowlist 条目指向未登记 scope「${r.scopeKey}」(编号 ${r.number})`);let e=`${r.scopeKey}::${r.number}::${[...r.files].sort().join(`,`)}`;i.has(e)&&t.push(`numbering.allowlist 条目(${r.scopeKey} ${r.number})重复`),i.add(e)}for(let n of e.numbering.globalExclusions)W(`numbering.globalExclusions`,n.glob,t);G(`numbering.globalExclusions`,e.numbering.globalExclusions.map(e=>e.glob),t);for(let n of e.numbering.audit.pending)W(`numbering.audit.pending`,n.glob,t);G(`numbering.audit.pending`,e.numbering.audit.pending.map(e=>e.glob),t);for(let n of e.numbering.audit.roots)U(`numbering.audit.roots`,n,t);for(let n of e.slugDigitAllowlist)W(`slugDigitAllowlist`,n.glob,t);return G(`slugDigitAllowlist`,e.slugDigitAllowlist.map(e=>e.glob),t),t}function q(e){let t=K(e);if(t.length>0)throw Error(`lzi-issues 配置跨条目校验失败:${t.join(`;`)}`);return e}function J(e,t){try{return q(E(e))}catch(e){let n=e instanceof Error?e.message:String(e);throw Error(`${n}(配置文件:${t})`)}}async function Y(e={}){if(e.configPath!==void 0){let t=r(e.cwd??process.cwd(),e.configPath);return n(t)?{ok:!0,config:J(await X(t),t),configFilePath:t,source:`explicit`}:{ok:!1,reason:`未找到配置文件:${t}`}}let i=await t({standaloneFile:`lzi-issues.config.ts`,unifiedField:`issues`,cwd:e.cwd});return i.success?{ok:!0,config:J(i.config,i.configFilePath),configFilePath:i.configFilePath,source:i.source}:{ok:!1,reason:`未找到 lzi-issues.config.ts(且 lzi.config.ts 无 issues 字段)——可先执行 lzi-issues init`}}async function X(e){let t=await import(i(e).href);if(t.default===void 0)throw Error(`配置文件缺少 default 导出:${e}`);return t.default}export{O as CONFIG_SCAFFOLD_HEADER,c as DEFAULT_AUDIT_ROOTS,s as DEFAULT_NUMBERISH_PATTERN,o as DEFAULT_PENDING_WORDS,l as DEFAULT_REGISTRY_DIR,u as DEFAULT_SQLITE_PATH,p as EXTENSION_PATTERN,f as NUMBER_PATTERN,B as RATCHET_CONTRACT_HEADER,d as SCOPE_KEY_PATTERN,a as STORAGE_STRATEGIES,z as appendScopeToConfigText,h as baselineEntrySchema,D as defineConfig,V as deriveBaselineEntries,X as importConfigModule,Y as loadLziIssuesConfig,T as lziIssuesConfigSchema,E as parseLziIssuesConfig,H as renderBaselineRegeneratedConfig,F as renderConfigFile,L as renderConfigScaffoldFile,I as renderScopeEntry,P as serializeConfigBody,K as validateCrossEntries,q as validateLziIssuesConfig};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@longzai-intelligence-issues/config",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -31,10 +31,6 @@
31
31
  "zod": "^4.4.3"
32
32
  },
33
33
  "devDependencies": {
34
- "@longzai-intelligence-builder/cli": "^0.2.16",
35
- "@longzai-intelligence-tsgo/cli": "^0.0.1",
36
- "@types/bun": "latest",
37
- "@typescript/native-preview": "beta",
38
- "oxlint": "^1.77.0"
34
+ "@types/bun": "latest"
39
35
  }
40
- }
36
+ }
@@ -45,12 +45,11 @@ async function importAndParse(generated: string) {
45
45
 
46
46
  try {
47
47
  /**
48
- * 可导入文本
48
+ * 可导入文本(包导入改写为包内别名;cli 再出口与 config 直连两形态均映射)
49
49
  */
50
- const importable = generated.replace(
51
- "'@longzai-intelligence-issues/config'",
52
- "'@/schema/lzi-issues-config.schema'",
53
- );
50
+ const importable = generated
51
+ .replace("'@longzai-intelligence-issues/cli'", "'@/schema/lzi-issues-config.schema'")
52
+ .replace("'@longzai-intelligence-issues/config'", "'@/schema/lzi-issues-config.schema'");
54
53
 
55
54
  writeFileSync(tmpFile, importable);
56
55
 
@@ -35,12 +35,12 @@ async function importAndParse(generated: string) {
35
35
 
36
36
  try {
37
37
  /**
38
- * 可导入文本(包导入改写为包内别名,规避 dist 构建依赖)
38
+ * 可导入文本(包导入改写为包内别名,规避 dist 构建依赖;cli 再出口与 config
39
+ * 直连两形态均映射——回环测的是配置体可解析性,import 指定符另行断言)
39
40
  */
40
- const importable = generated.replace(
41
- "'@longzai-intelligence-issues/config'",
42
- "'@/schema/lzi-issues-config.schema'",
43
- );
41
+ const importable = generated
42
+ .replace("'@longzai-intelligence-issues/cli'", "'@/schema/lzi-issues-config.schema'")
43
+ .replace("'@longzai-intelligence-issues/config'", "'@/schema/lzi-issues-config.schema'");
44
44
 
45
45
  writeFileSync(tmpFile, importable);
46
46
 
@@ -56,12 +56,15 @@ async function importAndParse(generated: string) {
56
56
  }
57
57
 
58
58
  describe('renderConfigScaffoldFile', () => {
59
- test('生成文件含契约头、defineConfig 与缺省 scope ', () => {
59
+ test('生成文件含契约头、defineConfig 与缺省 scope 值(采用仓单依赖:import 指向 cli 再出口)', () => {
60
60
  const text = renderConfigScaffoldFile({ key: 'demo', title: '演示域' });
61
61
 
62
+ expect(text.includes("import { defineConfig } from '@longzai-intelligence-issues/cli';")).toBe(
63
+ true,
64
+ );
62
65
  expect(
63
66
  text.includes("import { defineConfig } from '@longzai-intelligence-issues/config';"),
64
- ).toBe(true);
67
+ ).toBe(false);
65
68
  expect(text.includes('lzi-issues init')).toBe(true);
66
69
  expect(text.includes("key: 'demo'")).toBe(true);
67
70
  expect(text.includes("paths: ['.']")).toBe(true);
@@ -69,6 +69,44 @@ describe('parseLziIssuesConfig 默认值落定', () => {
69
69
  expect(config.scopes[0]?.slugDigitPolicy).toBe('forbid');
70
70
  });
71
71
 
72
+ test('slugDigitPolicy 支持 allow 档位(缺省仍为不登记=forbid)', () => {
73
+ const config = parseLziIssuesConfig({
74
+ ...MINIMAL_INPUT,
75
+ scopes: [
76
+ {
77
+ key: 'root',
78
+ title: '项目全局',
79
+ paths: ['.'],
80
+ registryDir: 'docs/issues',
81
+ slugDigitPolicy: 'allow',
82
+ },
83
+ ],
84
+ });
85
+
86
+ expect(config.scopes[0]?.slugDigitPolicy).toBe('allow');
87
+
88
+ const minimal = parseLziIssuesConfig(MINIMAL_INPUT);
89
+
90
+ expect(minimal.scopes[0]?.slugDigitPolicy).toBeUndefined();
91
+ });
92
+
93
+ test('slugDigitPolicy 非法档位拒收', () => {
94
+ expect(() =>
95
+ parseLziIssuesConfig({
96
+ ...MINIMAL_INPUT,
97
+ scopes: [
98
+ {
99
+ key: 'root',
100
+ title: '项目全局',
101
+ paths: ['.'],
102
+ registryDir: 'docs/issues',
103
+ slugDigitPolicy: 'permissive',
104
+ },
105
+ ],
106
+ }),
107
+ ).toThrow('slugDigitPolicy');
108
+ });
109
+
72
110
  test('docs 节可省略,登记时 scanRoots 必填', () => {
73
111
  const withDocs = parseLziIssuesConfig({
74
112
  ...MINIMAL_INPUT,
@@ -195,7 +195,7 @@ export function renderConfigFile(
195
195
  config: Record<string, unknown>,
196
196
  header: string = CONFIG_SCAFFOLD_HEADER,
197
197
  ): string {
198
- return `import { defineConfig } from '@longzai-intelligence-issues/config';\n\n${header}\n${serializeConfigBody(config)}`;
198
+ return `import { defineConfig } from '@longzai-intelligence-issues/cli';\n\n${header}\n${serializeConfigBody(config)}`;
199
199
  }
200
200
 
201
201
  /**
@@ -100,7 +100,12 @@ const scopeSchema = z.object({
100
100
  paths: z.array(z.string().min(1)).min(1),
101
101
  registryDir: z.string().min(1),
102
102
  numbering: z.object({ reserved: z.array(reservedEntrySchema) }).default({ reserved: [] }),
103
- slugDigitPolicy: z.literal('forbid').optional(),
103
+
104
+ /**
105
+ * slug 数字政策:forbid(缺省)禁数字、例外走根级 slugDigitAllowlist;allow 放行
106
+ * 数字 slug(适用于存量 slug 惯例含数字的注册表,如 e2e/adr-0024/400-line-limit)。
107
+ */
108
+ slugDigitPolicy: z.enum(['forbid', 'allow']).optional(),
104
109
  });
105
110
 
106
111
  /**