@longzai-intelligence-issues/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.
@@ -7,9 +7,11 @@ import {
7
7
  listPrompts,
8
8
  normalizeHeaderFile,
9
9
  rerunCloseFlow,
10
+ scanRegistryDir,
10
11
  showPrompt,
11
12
  unfreezeIssue,
12
13
  } from '@longzai-intelligence-issues/ledger';
14
+ import { join } from 'node:path';
13
15
  import * as z from 'zod';
14
16
 
15
17
  import { fail, info, loadConfigOrExit, ok, repoRoot, violation } from './context.utils.js';
@@ -18,8 +20,15 @@ import { fail, info, loadConfigOrExit, ok, repoRoot, violation } from './context
18
20
  * 收口与冻结命令组:verify-close / freeze / unfreeze / normalize-header / prompts
19
21
  *
20
22
  * 判据口径:exit 0 过 / 1 违规 / 2 门禁拦截零执行。
23
+ *
24
+ * @param program - CLI 程序实例
21
25
  */
22
- export function registerCloseCommands(program: Command): void {
26
+ /**
27
+ * issue 收口命令(缺省零执行证据收口;--rerun 证书化真跑)
28
+ *
29
+ * @param program - CLI 程序实例
30
+ */
31
+ function registerVerifyCloseCommand(program: Command): void {
23
32
  defineCommand(program, {
24
33
  name: 'verify-close',
25
34
  description: 'issue 收口(缺省零执行证据收口;--rerun 证书化真跑)',
@@ -28,33 +37,42 @@ export function registerCloseCommands(program: Command): void {
28
37
  { flags: '--summary <summary>', description: '收口概要(批量禁用)' },
29
38
  { flags: '--dry-run', description: '只呈现不落盘/不执行' },
30
39
  { flags: '--rerun', description: '证书化真跑(重度命令,仅人类明令)' },
31
- { flags: '--criterion <criterion>', description: '显式判据 label|channel|cwd|command(可重复)' },
40
+ {
41
+ flags: '--criterion <criterion>',
42
+ description: '显式判据 label|channel|cwd|command(可重复)',
43
+ },
32
44
  { flags: '--criteria-from-issue', description: '从各案 criteria 块取判据' },
33
45
  { flags: '--confirm-heavy', description: '重度命令确认' },
34
46
  { flags: '--allow-full-criterion', description: '全量判据豁免(须留痕)' },
35
47
  { flags: '--config <path>', description: '显式配置路径' },
36
48
  ],
37
- schema: z
38
- .object({
39
- issue: z.union([z.string(), z.array(z.string())]).optional(),
40
- summary: z.string().optional(),
41
- dryRun: z.boolean().optional(),
42
- rerun: z.boolean().optional(),
43
- criterion: z.union([z.string(), z.array(z.string())]).optional(),
44
- criteriaFromIssue: z.boolean().optional(),
45
- confirmHeavy: z.boolean().optional(),
46
- allowFullCriterion: z.boolean().optional(),
47
- config: z.string().optional(),
48
- })
49
- .passthrough(),
49
+ schema: z.looseObject({
50
+ issue: z.union([z.string(), z.array(z.string())]).optional(),
51
+ summary: z.string().optional(),
52
+ dryRun: z.boolean().optional(),
53
+ rerun: z.boolean().optional(),
54
+ criterion: z.union([z.string(), z.array(z.string())]).optional(),
55
+ criteriaFromIssue: z.boolean().optional(),
56
+ confirmHeavy: z.boolean().optional(),
57
+ allowFullCriterion: z.boolean().optional(),
58
+ config: z.string().optional(),
59
+ }),
50
60
  action: async (opts) => {
61
+ /**
62
+ * 仓库根
63
+ */
51
64
  const root = repoRoot();
65
+
66
+ /**
67
+ * 解析后配置
68
+ */
52
69
  const { config } = await loadConfigOrExit(opts.config);
53
70
 
54
71
  /**
55
72
  * 目标文件归一
56
73
  */
57
- const files = opts.issue === undefined ? [] : Array.isArray(opts.issue) ? opts.issue : [opts.issue];
74
+ const files =
75
+ opts.issue === undefined ? [] : Array.isArray(opts.issue) ? opts.issue : [opts.issue];
58
76
 
59
77
  if (files.length === 0) {
60
78
  fail('缺少 --issue <路径>(可重复指定批量)');
@@ -63,7 +81,12 @@ export function registerCloseCommands(program: Command): void {
63
81
  /**
64
82
  * 显式判据归一
65
83
  */
66
- const criteria = opts.criterion === undefined ? [] : Array.isArray(opts.criterion) ? opts.criterion : [opts.criterion];
84
+ const criteria =
85
+ opts.criterion === undefined
86
+ ? []
87
+ : Array.isArray(opts.criterion)
88
+ ? opts.criterion
89
+ : [opts.criterion];
67
90
 
68
91
  if (opts.rerun === true) {
69
92
  /**
@@ -102,10 +125,20 @@ export function registerCloseCommands(program: Command): void {
102
125
  /**
103
126
  * 缺省证据收口(零执行)
104
127
  */
105
- if (criteria.length > 0 || opts.criteriaFromIssue === true || opts.confirmHeavy === true || opts.allowFullCriterion === true) {
106
- fail('证据收口(缺省模式)不接受 --criterion/--criteria-from-issue/--confirm-heavy/--allow-full-criterion(属 --rerun 真跑旗标)');
128
+ if (
129
+ criteria.length > 0 ||
130
+ opts.criteriaFromIssue === true ||
131
+ opts.confirmHeavy === true ||
132
+ opts.allowFullCriterion === true
133
+ ) {
134
+ fail(
135
+ '证据收口(缺省模式)不接受 --criterion/--criteria-from-issue/--confirm-heavy/--allow-full-criterion(属 --rerun 真跑旗标)',
136
+ );
107
137
  }
108
138
 
139
+ /**
140
+ * 零执行证据收口批次结果
141
+ */
109
142
  const result = evidenceCloseFlow({
110
143
  root,
111
144
  config,
@@ -125,7 +158,14 @@ export function registerCloseCommands(program: Command): void {
125
158
  }
126
159
  },
127
160
  });
161
+ }
128
162
 
163
+ /**
164
+ * 冻结命令(freeze:--reason 须含「用户裁定」)
165
+ *
166
+ * @param program - CLI 程序实例
167
+ */
168
+ function registerFreezeCommand(program: Command): void {
129
169
  defineCommand(program, {
130
170
  name: 'freeze',
131
171
  description: '冻结 issue(--reason 须含「用户裁定」)',
@@ -134,8 +174,15 @@ export function registerCloseCommands(program: Command): void {
134
174
  { flags: '--reason <reason>', description: '裁定理由(须含「用户裁定」)' },
135
175
  { flags: '--config <path>', description: '显式配置路径' },
136
176
  ],
137
- schema: z.object({ issue: z.string().optional(), reason: z.string().optional(), config: z.string().optional() }).passthrough(),
177
+ schema: z.looseObject({
178
+ issue: z.string().optional(),
179
+ reason: z.string().optional(),
180
+ config: z.string().optional(),
181
+ }),
138
182
  action: async (opts) => {
183
+ /**
184
+ * 仓库根
185
+ */
139
186
  const root = repoRoot();
140
187
  await loadConfigOrExit(opts.config);
141
188
 
@@ -143,6 +190,9 @@ export function registerCloseCommands(program: Command): void {
143
190
  fail('freeze 须 --issue <路径> 与 --reason <裁定理由>');
144
191
  }
145
192
 
193
+ /**
194
+ * 冻结写入结果
195
+ */
146
196
  const result = freezeIssue({ root, file: opts.issue, reason: opts.reason });
147
197
 
148
198
  if (!result.ok) {
@@ -152,7 +202,14 @@ export function registerCloseCommands(program: Command): void {
152
202
  ok(`${opts.issue}: ${result.message}`);
153
203
  },
154
204
  });
205
+ }
155
206
 
207
+ /**
208
+ * 解冻命令(unfreeze:--note 须含「用户裁定」;恢复 🔴)
209
+ *
210
+ * @param program - CLI 程序实例
211
+ */
212
+ function registerUnfreezeCommand(program: Command): void {
156
213
  defineCommand(program, {
157
214
  name: 'unfreeze',
158
215
  description: '解冻 issue(--note 须含「用户裁定」;恢复 🔴)',
@@ -161,8 +218,15 @@ export function registerCloseCommands(program: Command): void {
161
218
  { flags: '--note <note>', description: '解冻注记(须含「用户裁定」)' },
162
219
  { flags: '--config <path>', description: '显式配置路径' },
163
220
  ],
164
- schema: z.object({ issue: z.string().optional(), note: z.string().optional(), config: z.string().optional() }).passthrough(),
221
+ schema: z.looseObject({
222
+ issue: z.string().optional(),
223
+ note: z.string().optional(),
224
+ config: z.string().optional(),
225
+ }),
165
226
  action: async (opts) => {
227
+ /**
228
+ * 仓库根
229
+ */
166
230
  const root = repoRoot();
167
231
  await loadConfigOrExit(opts.config);
168
232
 
@@ -170,6 +234,9 @@ export function registerCloseCommands(program: Command): void {
170
234
  fail('unfreeze 须 --issue <路径> 与 --note <解冻注记>');
171
235
  }
172
236
 
237
+ /**
238
+ * 解冻写入结果
239
+ */
173
240
  const result = unfreezeIssue({ root, file: opts.issue, note: opts.note });
174
241
 
175
242
  if (!result.ok) {
@@ -179,26 +246,60 @@ export function registerCloseCommands(program: Command): void {
179
246
  ok(`${opts.issue}: ${result.message}`);
180
247
  },
181
248
  });
249
+ }
182
250
 
251
+ /**
252
+ * 方言头部迁移命令(normalize-header:字段规范序 / 零丢失守卫 / 幂等)
253
+ *
254
+ * @param program - CLI 程序实例
255
+ */
256
+ function registerNormalizeHeaderCommand(program: Command): void {
183
257
  defineCommand(program, {
184
258
  name: 'normalize-header',
185
259
  description: '方言头部迁移(字段规范序 / 零丢失守卫 / 幂等)',
186
260
  options: [
187
- { flags: '--issue <issue>', description: 'issue 文件路径(可重复)' },
261
+ { flags: '--issue <issue>', description: 'issue 文件路径(可重复,与 --dir 互斥)' },
262
+ {
263
+ flags: '--dir <dir>',
264
+ description: '注册表目录批量(目录内全部编号文件,与 --issue 互斥)',
265
+ },
266
+ {
267
+ flags: '--status <status>',
268
+ description: '无可识别状态行时的显式灯位 red|yellow|green|canceled(frozen 须经 freeze)',
269
+ },
188
270
  { flags: '--config <path>', description: '显式配置路径' },
189
271
  ],
190
- schema: z.object({ issue: z.union([z.string(), z.array(z.string())]).optional(), config: z.string().optional() }).passthrough(),
272
+ schema: z.looseObject({
273
+ issue: z.union([z.string(), z.array(z.string())]).optional(),
274
+ dir: z.string().optional(),
275
+ status: z.enum(['red', 'yellow', 'green', 'canceled']).optional(),
276
+ config: z.string().optional(),
277
+ }),
191
278
  action: async (opts) => {
279
+ /**
280
+ * 仓库根
281
+ */
192
282
  const root = repoRoot();
193
283
  await loadConfigOrExit(opts.config);
194
284
 
285
+ if (opts.issue !== undefined && opts.dir !== undefined) {
286
+ fail('--issue 与 --dir 互斥(单文件指定或目录批量二选一)');
287
+ }
288
+
195
289
  /**
196
- * 目标文件归一
290
+ * 目标文件清单(--dir 展开为注册表编号文件)
197
291
  */
198
- const files = opts.issue === undefined ? [] : Array.isArray(opts.issue) ? opts.issue : [opts.issue];
292
+ const files =
293
+ opts.dir !== undefined
294
+ ? scanRegistryDir(join(root, opts.dir)).map((record) => `${opts.dir}/${record.file}`)
295
+ : opts.issue === undefined
296
+ ? []
297
+ : Array.isArray(opts.issue)
298
+ ? opts.issue
299
+ : [opts.issue];
199
300
 
200
301
  if (files.length === 0) {
201
- fail('缺少 --issue <路径>(可重复)');
302
+ fail('缺少 --issue <路径>(可重复)或 --dir <注册表目录>');
202
303
  }
203
304
 
204
305
  /**
@@ -207,7 +308,10 @@ export function registerCloseCommands(program: Command): void {
207
308
  let failed = 0;
208
309
 
209
310
  for (const file of files) {
210
- const result = normalizeHeaderFile({ root, file });
311
+ /**
312
+ * 单文件头部迁移结果
313
+ */
314
+ const result = normalizeHeaderFile({ root, file, status: opts.status });
211
315
  violation(`${file}: ${result.outcome}(${result.message})`);
212
316
  failed += result.outcome === 'failed' ? 1 : 0;
213
317
  }
@@ -217,7 +321,14 @@ export function registerCloseCommands(program: Command): void {
217
321
  }
218
322
  },
219
323
  });
324
+ }
220
325
 
326
+ /**
327
+ * 推荐提示词命令(prompts:list / show <id>)
328
+ *
329
+ * @param program - CLI 程序实例
330
+ */
331
+ function registerPromptsCommand(program: Command): void {
221
332
  defineCommand(program, {
222
333
  name: 'prompts',
223
334
  description: '推荐提示词(list / show <id>)',
@@ -226,8 +337,11 @@ export function registerCloseCommands(program: Command): void {
226
337
  { flags: '--id <id>', description: '提示词 id(show 用)' },
227
338
  { flags: '--config <path>', description: '显式配置路径' },
228
339
  ],
229
- schema: z.object({ action: z.string().optional(), id: z.string().optional(), config: z.string().optional() }).passthrough(),
230
- action: async (opts) => {
340
+ schema: z.looseObject({ id: z.string().optional(), config: z.string().optional() }),
341
+ action: async (opts, positionals) => {
342
+ /**
343
+ * 解析后配置
344
+ */
231
345
  const { config } = await loadConfigOrExit(opts.config);
232
346
 
233
347
  /**
@@ -235,15 +349,29 @@ export function registerCloseCommands(program: Command): void {
235
349
  */
236
350
  const options = {
237
351
  builtin: config.prompts.builtin,
238
- extraDir: config.prompts.extraDir === undefined ? undefined : `${repoRoot()}/${config.prompts.extraDir}`,
352
+ extraDir:
353
+ config.prompts.extraDir === undefined
354
+ ? undefined
355
+ : `${repoRoot()}/${config.prompts.extraDir}`,
239
356
  };
240
357
 
241
- const action = opts.action ?? 'list';
358
+ /**
359
+ * 子动作(defineCommand 位置参数第二通道;缺省 list)
360
+ */
361
+ const action = positionals[0] ?? 'list';
242
362
 
243
363
  if (action === 'show') {
364
+ /**
365
+ * 目标提示词 id
366
+ */
244
367
  const id = opts.id ?? fail('show 须 --id <提示词 id>');
245
368
 
246
- const entry = showPrompt(id, options) ?? fail(`提示词「${id}」未命中(lzi-issues prompts list 查看全部)`);
369
+ /**
370
+ * 命中的提示词条目
371
+ */
372
+ const entry =
373
+ showPrompt(id, options) ??
374
+ fail(`提示词「${id}」未命中(lzi-issues prompts list 查看全部)`);
247
375
 
248
376
  process.stdout.write(`${entry.content}\n`);
249
377
  return;
@@ -255,3 +383,18 @@ export function registerCloseCommands(program: Command): void {
255
383
  },
256
384
  });
257
385
  }
386
+
387
+ /**
388
+ * 收口与冻结命令组:verify-close / freeze / unfreeze / normalize-header / prompts
389
+ *
390
+ * 判据口径:exit 0 过 / 1 违规 / 2 门禁拦截零执行。
391
+ *
392
+ * @param program - CLI 程序实例
393
+ */
394
+ export function registerCloseCommands(program: Command): void {
395
+ registerVerifyCloseCommand(program);
396
+ registerFreezeCommand(program);
397
+ registerUnfreezeCommand(program);
398
+ registerNormalizeHeaderCommand(program);
399
+ registerPromptsCommand(program);
400
+ }
@@ -5,12 +5,17 @@
5
5
  * 信息走 stdout([INFO]/[SUCCESS] 前缀);exit 2 = 门禁拦截零执行。
6
6
  */
7
7
 
8
- import { loadLziIssuesConfig, type LoadLziIssuesConfigResult, type LziIssuesConfig } from '@longzai-intelligence-issues/config';
9
-
8
+ import {
9
+ loadLziIssuesConfig,
10
+ type LoadLziIssuesConfigResult,
11
+ type LziIssuesConfig,
12
+ } from '@longzai-intelligence-issues/config';
10
13
  import { resolve } from 'node:path';
11
14
 
12
15
  /**
13
16
  * 仓库根绝对路径(cwd 锚定;配置查找亦自 cwd 向上)
17
+ *
18
+ * @returns 仓库根绝对路径
14
19
  */
15
20
  export function repoRoot(): string {
16
21
  return resolve(process.cwd());
@@ -22,7 +27,9 @@ export function repoRoot(): string {
22
27
  * @param configPath - 显式配置路径(--config)
23
28
  * @returns 解析后配置与命中路径
24
29
  */
25
- export async function loadConfigOrExit(configPath?: string): Promise<{ config: LziIssuesConfig; configFilePath: string }> {
30
+ export async function loadConfigOrExit(
31
+ configPath?: string,
32
+ ): Promise<{ config: LziIssuesConfig; configFilePath: string }> {
26
33
  /**
27
34
  * 加载结果
28
35
  */
@@ -88,6 +95,9 @@ export function resolveScopeFromCwd(config: LziIssuesConfig, cwdRel: string): st
88
95
  */
89
96
  let bestKey: string | null = null;
90
97
 
98
+ /**
99
+ * 当前最长命中 path 的长度('.' 全仓命中按 -1 起步,任意具体 path 更长)
100
+ */
91
101
  let bestLen = -1;
92
102
 
93
103
  for (const scope of config.scopes) {