siluzan-cso-cli 1.1.27-beta.4 → 1.1.27-beta.6
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/README.md +1 -1
- package/dist/index.js +242 -21
- package/dist/skill/SKILL.md +3 -1
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/validate-content.md +114 -0
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/dist/skill/three-lib-content-workflow/content-writer.workflow.md +10 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ siluzan-cso init -d /path/to/skills # 写入自定义目录
|
|
|
54
54
|
siluzan-cso init --force # 强制覆盖已存在文件
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
> **注意**:当前为测试版(1.1.27-beta.
|
|
57
|
+
> **注意**:当前为测试版(1.1.27-beta.6),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-cso-cli`。
|
|
58
58
|
|
|
59
59
|
| 助手 | 建议 `--ai` |
|
|
60
60
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -5091,6 +5091,202 @@ async function runUpload(options) {
|
|
|
5091
5091
|
}
|
|
5092
5092
|
}
|
|
5093
5093
|
|
|
5094
|
+
// src/commands/validate-content.ts
|
|
5095
|
+
import * as fs9 from "fs";
|
|
5096
|
+
import * as path9 from "path";
|
|
5097
|
+
var CJK_REGEX = /[\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/g;
|
|
5098
|
+
var WORD_REGEX = /[A-Za-z0-9]+(?:['’\-][A-Za-z0-9]+)*/g;
|
|
5099
|
+
function countMetrics(text) {
|
|
5100
|
+
const chars = [...text].length;
|
|
5101
|
+
const charsNoSpace = [...text.replace(/\s+/g, "")].length;
|
|
5102
|
+
const cjk = (text.match(CJK_REGEX) ?? []).length;
|
|
5103
|
+
const words = (text.match(WORD_REGEX) ?? []).length;
|
|
5104
|
+
const lines = text.length === 0 ? 0 : text.split(/\r?\n/).length;
|
|
5105
|
+
const paragraphs = text.split(/\n\s*\n/).map((p) => p.trim()).filter((p) => p.length > 0).length;
|
|
5106
|
+
return { chars, charsNoSpace, cjk, words, lines, paragraphs };
|
|
5107
|
+
}
|
|
5108
|
+
function pickCount(metrics, countBy) {
|
|
5109
|
+
switch (countBy) {
|
|
5110
|
+
case "chars":
|
|
5111
|
+
return metrics.chars;
|
|
5112
|
+
case "cjk":
|
|
5113
|
+
return metrics.cjk;
|
|
5114
|
+
case "words":
|
|
5115
|
+
return metrics.words;
|
|
5116
|
+
case "chars-no-space":
|
|
5117
|
+
default:
|
|
5118
|
+
return metrics.charsNoSpace;
|
|
5119
|
+
}
|
|
5120
|
+
}
|
|
5121
|
+
function stripMarkdown(input) {
|
|
5122
|
+
let text = input;
|
|
5123
|
+
text = text.replace(/^\uFEFF?---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
|
|
5124
|
+
text = text.replace(/^[ \t]*(```|~~~).*$/gm, "");
|
|
5125
|
+
text = text.replace(/!\[[^\]]*\]\([^)]*\)/g, "");
|
|
5126
|
+
text = text.replace(/\[([^\]]*)\]\([^)]*\)/g, "$1");
|
|
5127
|
+
text = text.replace(/^[ \t]*#{1,6}[ \t]+/gm, "");
|
|
5128
|
+
text = text.replace(/^[ \t]*>[ \t]?/gm, "");
|
|
5129
|
+
text = text.replace(/^[ \t]*[-*+][ \t]+/gm, "");
|
|
5130
|
+
text = text.replace(/^[ \t]*\d+\.[ \t]+/gm, "");
|
|
5131
|
+
text = text.replace(/^[ \t]*\|?[ \t]*:?-{3,}.*$/gm, "");
|
|
5132
|
+
text = text.replace(/\|/g, " ");
|
|
5133
|
+
text = text.replace(/(\*\*|__|\*|_|`|~~)/g, "");
|
|
5134
|
+
return text;
|
|
5135
|
+
}
|
|
5136
|
+
var LEAK_RULES = [
|
|
5137
|
+
{ regex: /(?:TF|PA|MF)-?\d{2,}/g, reason: "\u4E09\u5E93\u5185\u90E8\u7F16\u7801\uFF08TF/PA/MF\uFF09\u4E0D\u5E94\u51FA\u73B0\u5728\u6210\u7A3F" },
|
|
5138
|
+
{ regex: /三库溯源/g, reason: "\u4E09\u5E93\u6EAF\u6E90\u5C5E\u4E8E\u8FC7\u7A0B\u8BB0\u5F55\uFF0C\u4E0D\u5E94\u51FA\u73B0\u5728\u6210\u7A3F" },
|
|
5139
|
+
{ regex: /流量因子库|产品资产库|烹调方法库/g, reason: "\u4E09\u5E93\u540D\u79F0\u5C5E\u4E8E\u5185\u90E8\u9AA8\u67B6\uFF0C\u4E0D\u5E94\u51FA\u73B0\u5728\u6210\u7A3F" },
|
|
5140
|
+
{ regex: /SOP\s*(?:执行|步骤|记录)/gi, reason: "SOP \u8FC7\u7A0B\u5185\u5BB9\u4E0D\u5E94\u51FA\u73B0\u5728\u6210\u7A3F" },
|
|
5141
|
+
{ regex: /焊点/g, reason: "\u710A\u70B9\u4E3A\u5185\u90E8\u63D0\u70BC\u672F\u8BED\uFF0C\u4E0D\u5E94\u51FA\u73B0\u5728\u6210\u7A3F" }
|
|
5142
|
+
];
|
|
5143
|
+
function findLeaks(text, extraForbidden = []) {
|
|
5144
|
+
const hits = [];
|
|
5145
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5146
|
+
for (const rule of LEAK_RULES) {
|
|
5147
|
+
const matches = text.match(rule.regex);
|
|
5148
|
+
if (!matches) continue;
|
|
5149
|
+
for (const m of matches) {
|
|
5150
|
+
const key = `${rule.reason}::${m}`;
|
|
5151
|
+
if (seen.has(key)) continue;
|
|
5152
|
+
seen.add(key);
|
|
5153
|
+
hits.push({ match: m, reason: rule.reason });
|
|
5154
|
+
}
|
|
5155
|
+
}
|
|
5156
|
+
for (const word of extraForbidden) {
|
|
5157
|
+
const w = word.trim();
|
|
5158
|
+
if (!w) continue;
|
|
5159
|
+
if (text.includes(w)) {
|
|
5160
|
+
const key = `\u81EA\u5B9A\u4E49\u7981\u7528\u8BCD::${w}`;
|
|
5161
|
+
if (seen.has(key)) continue;
|
|
5162
|
+
seen.add(key);
|
|
5163
|
+
hits.push({ match: w, reason: "\u547D\u4E2D\u81EA\u5B9A\u4E49\u7981\u7528\u8BCD\uFF08--forbidden\uFF09" });
|
|
5164
|
+
}
|
|
5165
|
+
}
|
|
5166
|
+
return hits;
|
|
5167
|
+
}
|
|
5168
|
+
function parseForbidden(raw) {
|
|
5169
|
+
if (!raw) return [];
|
|
5170
|
+
return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
5171
|
+
}
|
|
5172
|
+
var COUNT_BY_LABEL = {
|
|
5173
|
+
chars: "\u603B\u5B57\u7B26\u6570\uFF08\u542B\u7A7A\u767D\uFF09",
|
|
5174
|
+
"chars-no-space": "\u5B57\u7B26\u6570\uFF08\u4E0D\u542B\u7A7A\u767D\uFF09",
|
|
5175
|
+
cjk: "\u6C49\u5B57\u6570",
|
|
5176
|
+
words: "\u82F1\u6587\u5355\u8BCD\u6570"
|
|
5177
|
+
};
|
|
5178
|
+
function readStdin() {
|
|
5179
|
+
try {
|
|
5180
|
+
return fs9.readFileSync(0, "utf8");
|
|
5181
|
+
} catch {
|
|
5182
|
+
return "";
|
|
5183
|
+
}
|
|
5184
|
+
}
|
|
5185
|
+
function resolveContent(options) {
|
|
5186
|
+
if (options.text !== void 0) {
|
|
5187
|
+
return { raw: options.text, sourceLabel: "--text \u6587\u672C" };
|
|
5188
|
+
}
|
|
5189
|
+
if (options.file) {
|
|
5190
|
+
const filePath = path9.resolve(options.file);
|
|
5191
|
+
if (!fs9.existsSync(filePath) || !fs9.statSync(filePath).isFile()) {
|
|
5192
|
+
console.error(`
|
|
5193
|
+
\u274C \u6587\u6848\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${filePath}`);
|
|
5194
|
+
process.exit(1);
|
|
5195
|
+
}
|
|
5196
|
+
try {
|
|
5197
|
+
return { raw: fs9.readFileSync(filePath, "utf8"), sourceLabel: path9.basename(filePath) };
|
|
5198
|
+
} catch (e) {
|
|
5199
|
+
console.error(`
|
|
5200
|
+
\u274C \u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A${e.message}`);
|
|
5201
|
+
process.exit(1);
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5204
|
+
if (!process.stdin.isTTY) {
|
|
5205
|
+
const piped = readStdin();
|
|
5206
|
+
if (piped.length > 0) return { raw: piped, sourceLabel: "stdin" };
|
|
5207
|
+
}
|
|
5208
|
+
console.error("\n\u274C \u672A\u63D0\u4F9B\u5F85\u6821\u9A8C\u6587\u6848\u3002\u8BF7\u7528\u4EE5\u4E0B\u4EFB\u4E00\u65B9\u5F0F\u4F20\u5165\uFF08\u5BBF\u4E3B\u65E0\u6587\u4EF6\u5DE5\u5177\u65F6\u7528\u540E\u4E24\u79CD\uFF09\uFF1A");
|
|
5209
|
+
console.error(" 1) \u6587\u4EF6\uFF1A siluzan-cso validate-content -f draft.md --max 800");
|
|
5210
|
+
console.error(' 2) \u7BA1\u9053\uFF1A echo "\u6587\u6848\u5185\u5BB9" | siluzan-cso validate-content --max 800');
|
|
5211
|
+
console.error(' 3) \u884C\u5185\u6587\u672C\uFF1Asiluzan-cso validate-content --text "\u6587\u6848\u5185\u5BB9" --max 800');
|
|
5212
|
+
process.exit(1);
|
|
5213
|
+
}
|
|
5214
|
+
async function runValidateContent(options) {
|
|
5215
|
+
const { raw, sourceLabel } = resolveContent(options);
|
|
5216
|
+
const countBy = options.countBy ?? "chars-no-space";
|
|
5217
|
+
const checkLeak = options.checkLeak !== false;
|
|
5218
|
+
const extraForbidden = parseForbidden(options.forbidden);
|
|
5219
|
+
const textForCount = options.stripMarkdown ? stripMarkdown(raw) : raw;
|
|
5220
|
+
const metrics = countMetrics(textForCount);
|
|
5221
|
+
const value = pickCount(metrics, countBy);
|
|
5222
|
+
const limitProblems = [];
|
|
5223
|
+
if (options.min !== void 0 && value < options.min) {
|
|
5224
|
+
limitProblems.push(
|
|
5225
|
+
`\u5B57\u6570\u4E0D\u8DB3\uFF1A${COUNT_BY_LABEL[countBy]} ${value} < \u4E0B\u9650 ${options.min}\uFF08\u8FD8\u5DEE ${options.min - value}\uFF09`
|
|
5226
|
+
);
|
|
5227
|
+
}
|
|
5228
|
+
if (options.max !== void 0 && value > options.max) {
|
|
5229
|
+
limitProblems.push(
|
|
5230
|
+
`\u5B57\u6570\u8D85\u9650\uFF1A${COUNT_BY_LABEL[countBy]} ${value} > \u4E0A\u9650 ${options.max}\uFF08\u8D85\u51FA ${value - options.max}\uFF09`
|
|
5231
|
+
);
|
|
5232
|
+
}
|
|
5233
|
+
const leaks = checkLeak || extraForbidden.length > 0 ? findLeaks(raw, extraForbidden) : [];
|
|
5234
|
+
const passed = limitProblems.length === 0 && leaks.length === 0;
|
|
5235
|
+
if (options.json) {
|
|
5236
|
+
console.log(
|
|
5237
|
+
JSON.stringify(
|
|
5238
|
+
{
|
|
5239
|
+
source: sourceLabel,
|
|
5240
|
+
countBy,
|
|
5241
|
+
strippedMarkdown: Boolean(options.stripMarkdown),
|
|
5242
|
+
limit: { min: options.min ?? null, max: options.max ?? null, value },
|
|
5243
|
+
metrics,
|
|
5244
|
+
limitProblems,
|
|
5245
|
+
leaks,
|
|
5246
|
+
passed
|
|
5247
|
+
},
|
|
5248
|
+
null,
|
|
5249
|
+
2
|
|
5250
|
+
)
|
|
5251
|
+
);
|
|
5252
|
+
process.exit(passed ? 0 : 1);
|
|
5253
|
+
}
|
|
5254
|
+
console.log(`
|
|
5255
|
+
\u{1F4C4} \u6587\u6848\u6821\u9A8C\uFF1A${sourceLabel}`);
|
|
5256
|
+
if (options.stripMarkdown) console.log(" \uFF08\u5DF2\u53BB\u9664 markdown \u8BED\u6CD5 / frontmatter \u540E\u7EDF\u8BA1\uFF09");
|
|
5257
|
+
console.log("");
|
|
5258
|
+
console.log(` \u603B\u5B57\u7B26\u6570\uFF08\u542B\u7A7A\u767D\uFF09 ${metrics.chars}`);
|
|
5259
|
+
console.log(` \u5B57\u7B26\u6570\uFF08\u4E0D\u542B\u7A7A\u767D\uFF09 ${metrics.charsNoSpace}`);
|
|
5260
|
+
console.log(` \u6C49\u5B57\u6570 ${metrics.cjk}`);
|
|
5261
|
+
console.log(` \u82F1\u6587\u5355\u8BCD\u6570 ${metrics.words}`);
|
|
5262
|
+
console.log(` \u884C\u6570 / \u6BB5\u843D\u6570 ${metrics.lines} / ${metrics.paragraphs}`);
|
|
5263
|
+
if (options.min !== void 0 || options.max !== void 0) {
|
|
5264
|
+
const range = `${options.min ?? "\u2014"} ~ ${options.max ?? "\u2014"}`;
|
|
5265
|
+
console.log(`
|
|
5266
|
+
\u5B57\u6570\u9650\u5236\uFF08${COUNT_BY_LABEL[countBy]}\uFF09\uFF1A\u5F53\u524D ${value}\uFF0C\u8981\u6C42 ${range}`);
|
|
5267
|
+
}
|
|
5268
|
+
console.log("\n\u6821\u9A8C\u7ED3\u679C\uFF1A");
|
|
5269
|
+
if (limitProblems.length === 0 && (options.min !== void 0 || options.max !== void 0)) {
|
|
5270
|
+
console.log(" \u2713 \u5B57\u6570\u5728\u9650\u5236\u8303\u56F4\u5185");
|
|
5271
|
+
}
|
|
5272
|
+
for (const p of limitProblems) console.log(` \u2717 ${p}`);
|
|
5273
|
+
if (checkLeak || extraForbidden.length > 0) {
|
|
5274
|
+
if (leaks.length === 0) {
|
|
5275
|
+
console.log(" \u2713 \u672A\u53D1\u73B0\u5185\u90E8\u9AA8\u67B6\u8D44\u4EA7 / \u7981\u7528\u8BCD\u6CC4\u6F0F");
|
|
5276
|
+
} else {
|
|
5277
|
+
console.log(` \u2717 \u53D1\u73B0 ${leaks.length} \u5904\u7591\u4F3C\u6CC4\u6F0F\uFF08\u4E0D\u5E94\u51FA\u73B0\u5728\u4EA4\u4ED8\u6210\u7A3F\uFF09\uFF1A`);
|
|
5278
|
+
for (const l of leaks) console.log(` \u300C${l.match}\u300D\u2014 ${l.reason}`);
|
|
5279
|
+
}
|
|
5280
|
+
}
|
|
5281
|
+
if (passed) {
|
|
5282
|
+
console.log("\n\u2705 \u6587\u6848\u6821\u9A8C\u901A\u8FC7");
|
|
5283
|
+
process.exit(0);
|
|
5284
|
+
} else {
|
|
5285
|
+
console.log("\n\u274C \u6587\u6848\u6821\u9A8C\u672A\u901A\u8FC7\uFF0C\u8BF7\u6309\u4E0A\u8FF0\u95EE\u9898\u4FEE\u8BA2\u540E\u91CD\u65B0\u6821\u9A8C");
|
|
5286
|
+
process.exit(1);
|
|
5287
|
+
}
|
|
5288
|
+
}
|
|
5289
|
+
|
|
5094
5290
|
// src/commands/report/_shared.ts
|
|
5095
5291
|
var DEFAULT_METHOD = "Day";
|
|
5096
5292
|
var DEFAULT_WORKS_ORDER = "play";
|
|
@@ -5408,8 +5604,8 @@ function printMarkdownFetch(runtime, includeModules, sections) {
|
|
|
5408
5604
|
}
|
|
5409
5605
|
|
|
5410
5606
|
// src/commands/report/commands.ts
|
|
5411
|
-
import * as
|
|
5412
|
-
import * as
|
|
5607
|
+
import * as fs10 from "fs";
|
|
5608
|
+
import * as path10 from "path";
|
|
5413
5609
|
async function runReportFetch(options) {
|
|
5414
5610
|
const runtime = buildRuntime(options);
|
|
5415
5611
|
const includeModules = parseModules(options.include);
|
|
@@ -5593,7 +5789,7 @@ function defaultDownloadPath(recordId) {
|
|
|
5593
5789
|
const now = /* @__PURE__ */ new Date();
|
|
5594
5790
|
const pad = (n) => String(n).padStart(2, "0");
|
|
5595
5791
|
const name = `operations-report-${recordId}-${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}.pdf`;
|
|
5596
|
-
return
|
|
5792
|
+
return path10.resolve(process.cwd(), name);
|
|
5597
5793
|
}
|
|
5598
5794
|
async function downloadFile(url, output) {
|
|
5599
5795
|
const res = await fetch(url);
|
|
@@ -5601,7 +5797,7 @@ async function downloadFile(url, output) {
|
|
|
5601
5797
|
throw new Error(`\u4E0B\u8F7D\u5931\u8D25\uFF0CHTTP ${res.status}`);
|
|
5602
5798
|
}
|
|
5603
5799
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
5604
|
-
|
|
5800
|
+
fs10.writeFileSync(output, buffer);
|
|
5605
5801
|
}
|
|
5606
5802
|
async function runReportDownload(options) {
|
|
5607
5803
|
if (!options.id) {
|
|
@@ -5621,7 +5817,7 @@ async function runReportDownload(options) {
|
|
|
5621
5817
|
const msg = error.message;
|
|
5622
5818
|
exitWithError(`\u83B7\u53D6\u4E0B\u8F7D\u5730\u5740\u5931\u8D25\uFF1A${msg}`);
|
|
5623
5819
|
}
|
|
5624
|
-
const output =
|
|
5820
|
+
const output = path10.resolve(options.output ? options.output : defaultDownloadPath(options.id));
|
|
5625
5821
|
try {
|
|
5626
5822
|
await downloadFile(pdfUrl, output);
|
|
5627
5823
|
} catch (error) {
|
|
@@ -5852,8 +6048,8 @@ async function requestPlanning(config, endpoint, init = {}, verbose = false) {
|
|
|
5852
6048
|
}
|
|
5853
6049
|
|
|
5854
6050
|
// src/commands/planning/commands.ts
|
|
5855
|
-
import * as
|
|
5856
|
-
import * as
|
|
6051
|
+
import * as fs11 from "fs";
|
|
6052
|
+
import * as path11 from "path";
|
|
5857
6053
|
async function runPlanningEnterprises(options) {
|
|
5858
6054
|
const config = loadConfig(options.token);
|
|
5859
6055
|
const verbose = Boolean(options.verbose);
|
|
@@ -5981,7 +6177,7 @@ async function watchPlanTask(config, taskId, maxWaitMs, onProgress) {
|
|
|
5981
6177
|
const url = `${baseUrl}/api/plans/tasks/${encodeURIComponent(taskId)}/progress`;
|
|
5982
6178
|
const controller = new AbortController();
|
|
5983
6179
|
let finished = false;
|
|
5984
|
-
return new Promise((
|
|
6180
|
+
return new Promise((resolve7, reject) => {
|
|
5985
6181
|
const settle = (fn) => {
|
|
5986
6182
|
if (finished) return;
|
|
5987
6183
|
finished = true;
|
|
@@ -6028,7 +6224,7 @@ async function watchPlanTask(config, taskId, maxWaitMs, onProgress) {
|
|
|
6028
6224
|
}
|
|
6029
6225
|
onProgress?.(event);
|
|
6030
6226
|
if (event.status === "completed") {
|
|
6031
|
-
settle(() =>
|
|
6227
|
+
settle(() => resolve7(event.plan ?? null));
|
|
6032
6228
|
return;
|
|
6033
6229
|
}
|
|
6034
6230
|
if (event.status === "failed" || event.status === "cancelled") {
|
|
@@ -6359,13 +6555,13 @@ function inferEnterpriseNameFromPlan(plan) {
|
|
|
6359
6555
|
}
|
|
6360
6556
|
async function loadPlanFromSource(options, config) {
|
|
6361
6557
|
if (options.input) {
|
|
6362
|
-
const inputPath =
|
|
6363
|
-
if (!
|
|
6558
|
+
const inputPath = path11.resolve(options.input);
|
|
6559
|
+
if (!fs11.existsSync(inputPath)) {
|
|
6364
6560
|
exitWithError2(`\u8F93\u5165\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${inputPath}`);
|
|
6365
6561
|
}
|
|
6366
6562
|
let raw = "";
|
|
6367
6563
|
try {
|
|
6368
|
-
raw =
|
|
6564
|
+
raw = fs11.readFileSync(inputPath, "utf-8");
|
|
6369
6565
|
} catch (error) {
|
|
6370
6566
|
exitWithError2(`\u8BFB\u53D6\u8F93\u5165\u6587\u4EF6\u5931\u8D25\uFF1A${error.message}`);
|
|
6371
6567
|
}
|
|
@@ -6399,9 +6595,9 @@ async function runPlanningExportTxt(options) {
|
|
|
6399
6595
|
const defaultName = sanitizeFilename(
|
|
6400
6596
|
`\u5185\u5BB9\u9009\u9898\u65B9\u5411\u89C4\u5212_${enterpriseName}_${plan.yearMonth ?? "unknown"}.txt`
|
|
6401
6597
|
);
|
|
6402
|
-
const outputPath =
|
|
6598
|
+
const outputPath = path11.resolve(options.output ? options.output : defaultName);
|
|
6403
6599
|
try {
|
|
6404
|
-
|
|
6600
|
+
fs11.writeFileSync(outputPath, text, "utf-8");
|
|
6405
6601
|
} catch (error) {
|
|
6406
6602
|
exitWithError2(`\u5199\u5165\u5BFC\u51FA\u6587\u4EF6\u5931\u8D25\uFF1A${error.message}`);
|
|
6407
6603
|
}
|
|
@@ -6898,8 +7094,8 @@ async function runAuthorize(opts) {
|
|
|
6898
7094
|
}
|
|
6899
7095
|
|
|
6900
7096
|
// src/commands/persona.ts
|
|
6901
|
-
import
|
|
6902
|
-
import
|
|
7097
|
+
import fs12 from "fs";
|
|
7098
|
+
import path12 from "path";
|
|
6903
7099
|
var MAX_PERSONA_NAME = 60;
|
|
6904
7100
|
function unwrapGetPersonas(raw) {
|
|
6905
7101
|
if (!raw || typeof raw !== "object") return null;
|
|
@@ -7002,15 +7198,15 @@ ${hint}`);
|
|
|
7002
7198
|
console.log("\n\u63D0\u793A\uFF1A\u5B8C\u6574 styleGuide\uFF08Markdown\uFF09\u8BF7\u4F7F\u7528 --json \u67E5\u770B\u6BCF\u6761\u8BB0\u5F55\u7684 styleGuide \u5B57\u6BB5\u3002");
|
|
7003
7199
|
}
|
|
7004
7200
|
function readStyleGuideFromFile(filePath) {
|
|
7005
|
-
const resolved =
|
|
7006
|
-
if (!
|
|
7201
|
+
const resolved = path12.resolve(process.cwd(), filePath);
|
|
7202
|
+
if (!fs12.existsSync(resolved)) {
|
|
7007
7203
|
throw new Error(`styleGuide \u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${resolved}`);
|
|
7008
7204
|
}
|
|
7009
|
-
const stat =
|
|
7205
|
+
const stat = fs12.statSync(resolved);
|
|
7010
7206
|
if (!stat.isFile()) {
|
|
7011
7207
|
throw new Error(`styleGuide \u6587\u4EF6\u8DEF\u5F84\u4E0D\u662F\u666E\u901A\u6587\u4EF6\uFF1A${resolved}`);
|
|
7012
7208
|
}
|
|
7013
|
-
return
|
|
7209
|
+
return fs12.readFileSync(resolved, "utf-8");
|
|
7014
7210
|
}
|
|
7015
7211
|
function unwrapAddPersona(raw) {
|
|
7016
7212
|
if (!raw || typeof raw !== "object") return null;
|
|
@@ -7545,7 +7741,7 @@ async function runRagList(options) {
|
|
|
7545
7741
|
}
|
|
7546
7742
|
|
|
7547
7743
|
// src/commands/config.ts
|
|
7548
|
-
import * as
|
|
7744
|
+
import * as fs13 from "fs";
|
|
7549
7745
|
function cmdConfigShow() {
|
|
7550
7746
|
const shared = readSharedConfig();
|
|
7551
7747
|
const envApiKey = process.env.SILUZAN_API_KEY;
|
|
@@ -7893,6 +8089,31 @@ function registerCsoCommands(program2) {
|
|
|
7893
8089
|
});
|
|
7894
8090
|
}
|
|
7895
8091
|
);
|
|
8092
|
+
program2.command("validate-content").description(
|
|
8093
|
+
"\u6821\u9A8C\u6587\u6848\uFF1A\u7EDF\u8BA1\u5B57\u6570\uFF08\u6C49\u5B57/\u5B57\u7B26/\u5355\u8BCD\uFF09\uFF0C\u6309 --min/--max \u68C0\u67E5\u5B57\u6570\u9650\u5236\uFF0C\u5E76\u68C0\u67E5\u4E09\u5E93\u7F16\u7801/\u6EAF\u6E90\u7B49\u5185\u90E8\u5185\u5BB9\u662F\u5426\u6CC4\u6F0F\u5230\u6210\u7A3F\u3002\u6587\u6848\u6765\u6E90\u652F\u6301 -f \u6587\u4EF6\u3001--text \u884C\u5185\u6587\u672C\u3001\u6216 stdin \u7BA1\u9053\uFF08\u5BBF\u4E3B\u65E0\u6587\u4EF6\u5DE5\u5177\u65F6\u7528\u540E\u4E24\u79CD\uFF09"
|
|
8094
|
+
).option("-f, --file <path>", "\u5F85\u6821\u9A8C\u7684\u6587\u6848\u6587\u4EF6\u8DEF\u5F84\uFF08.md / .txt\uFF09\uFF1B\u4E0E --text / stdin \u4E09\u9009\u4E00").option(
|
|
8095
|
+
"--text <content>",
|
|
8096
|
+
"\u76F4\u63A5\u4F20\u5165\u6587\u6848\u6B63\u6587\uFF08\u5BBF\u4E3B\u65E0\u6587\u4EF6\u5DE5\u5177\u65F6\u7528\uFF09\uFF1B\u4F18\u5148\u7EA7\u9AD8\u4E8E -f \u4E0E stdin"
|
|
8097
|
+
).option("--min <n>", "\u5B57\u6570\u4E0B\u9650\uFF08\u6309 --count-by \u53E3\u5F84\uFF09", parseInt).option("--max <n>", "\u5B57\u6570\u4E0A\u9650\uFF08\u6309 --count-by \u53E3\u5F84\uFF09", parseInt).option(
|
|
8098
|
+
"--count-by <mode>",
|
|
8099
|
+
"\u9650\u5236\u53E3\u5F84\uFF1Achars-no-space\uFF08\u4E0D\u542B\u7A7A\u767D\uFF0C\u9ED8\u8BA4\uFF09| chars\uFF08\u542B\u7A7A\u767D\uFF09| cjk\uFF08\u6C49\u5B57\uFF09| words\uFF08\u82F1\u6587\u5355\u8BCD\uFF09",
|
|
8100
|
+
"chars-no-space"
|
|
8101
|
+
).option("--strip-markdown", "\u7EDF\u8BA1\u524D\u53BB\u9664 markdown \u8BED\u6CD5\u4E0E frontmatter\uFF08\u66F4\u8D34\u8FD1\u6B63\u6587\u5B57\u6570\uFF09", false).option("--no-check-leak", "\u8DF3\u8FC7\u5185\u90E8\u9AA8\u67B6\u8D44\u4EA7\uFF08\u4E09\u5E93\u7F16\u7801/\u6EAF\u6E90/SOP \u7B49\uFF09\u6CC4\u6F0F\u68C0\u67E5").option("--forbidden <words>", "\u989D\u5916\u7981\u7528\u5B50\u4E32\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u547D\u4E2D\u5373\u6821\u9A8C\u4E0D\u901A\u8FC7\uFF09").option("--json", "\u4EE5 JSON \u8F93\u51FA\u6821\u9A8C\u7ED3\u679C\uFF08\u9002\u5408\u811A\u672C/\u81EA\u52A8\u5316\uFF09", false).option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
|
|
8102
|
+
async (opts) => {
|
|
8103
|
+
await runValidateContent({
|
|
8104
|
+
file: opts.file,
|
|
8105
|
+
text: opts.text,
|
|
8106
|
+
min: opts.min,
|
|
8107
|
+
max: opts.max,
|
|
8108
|
+
countBy: opts.countBy,
|
|
8109
|
+
stripMarkdown: opts.stripMarkdown,
|
|
8110
|
+
checkLeak: opts.checkLeak,
|
|
8111
|
+
forbidden: opts.forbidden,
|
|
8112
|
+
json: opts.json,
|
|
8113
|
+
verbose: opts.verbose
|
|
8114
|
+
});
|
|
8115
|
+
}
|
|
8116
|
+
);
|
|
7896
8117
|
program2.command("publish").description("\u6309 JSON \u914D\u7F6E\u6587\u4EF6\u63D0\u4EA4\u53D1\u5E03\u4EFB\u52A1\u5230 CSO").requiredOption("-c, --config <path>", "\u53D1\u5E03\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08JSON\uFF09").option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--dry-run", "\u4EC5\u9884\u89C8\u8BF7\u6C42\u4F53\uFF0C\u4E0D\u5B9E\u9645\u63D0\u4EA4", false).option("--verbose", "\u663E\u793A\u5B8C\u6574\u8BF7\u6C42\u4F53\u53CA\u8BE6\u7EC6\u9519\u8BEF\uFF08\u542B\u654F\u611F\u5B57\u6BB5\uFF0C\u9ED8\u8BA4\u8131\u654F\uFF09", false).action(
|
|
7897
8118
|
async (opts) => {
|
|
7898
8119
|
await runPublish({
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -29,7 +29,7 @@ Windows 注意:部分 Agent 客户端通过 PowerShell / cmd 代执行命令
|
|
|
29
29
|
|
|
30
30
|
- **只读**:查询媒体账号列表、账号分组、运营报表、发布任务状态、人设列表、RAG 知识库检索、AI 内容规划详情
|
|
31
31
|
- **写入**(需用户确认):上传素材、提交发布任务、创建/更新账号分组、生成 AI 内容规划、站内信回复
|
|
32
|
-
- **本地文件操作**:`extract-cover` 在本地截取视频帧并输出图片文件;`init` 将 Skill 文件写入 AI 助手目录
|
|
32
|
+
- **本地文件操作**:`extract-cover` 在本地截取视频帧并输出图片文件;`validate-content` 在本地校验文案文件(字数限制 / 内部内容泄漏);`init` 将 Skill 文件写入 AI 助手目录
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
@@ -68,6 +68,7 @@ Windows 注意:部分 Agent 客户端通过 PowerShell / cmd 代执行命令
|
|
|
68
68
|
| `siluzan-cso account-group list/create/add-accounts/remove-accounts/update/delete` | 账号分组管理 | `references/account-group.md` |
|
|
69
69
|
| `siluzan-cso upload -f <file>` | 上传视频 / 图片到素材库 | `references/upload.md` |
|
|
70
70
|
| `siluzan-cso extract-cover -f <video> -p <平台>` | 从视频截取封面帧 | `references/extract-cover.md` |
|
|
71
|
+
| `siluzan-cso validate-content -f <file>` | 文案落盘后校验:字数统计 / 字数限制(`--min`/`--max`)/ 内部内容泄漏检查 | `references/validate-content.md` |
|
|
71
72
|
| `siluzan-cso publish -c config.json` | 提交多平台发布任务 | `references/publish.md` |
|
|
72
73
|
| `siluzan-cso task list/detail/item` | 查看任务状态 / 处理失败 / 重试 | `references/task.md` |
|
|
73
74
|
| `siluzan-cso report fetch --media <平台>` | 运营报表(核心指标 / 视频排行 / 趋势) | `references/report.md` |
|
|
@@ -84,6 +85,7 @@ Windows 注意:部分 Agent 客户端通过 PowerShell / cmd 代执行命令
|
|
|
84
85
|
| 发布视频或图文 | `references/publish.md` |
|
|
85
86
|
| 上传素材 | `references/upload.md` |
|
|
86
87
|
| 截取视频封面 | `references/extract-cover.md` |
|
|
88
|
+
| 文案写完落盘后校验字数 / 检查内部内容泄漏 | `references/validate-content.md` |
|
|
87
89
|
| 查发布记录 / 处理失败 | `references/task.md` |
|
|
88
90
|
| 查账号数据 / 运营报表 | `references/report.md` |
|
|
89
91
|
| 查找账号 ID 或账号详情 | `references/list-accounts.md` |
|
package/dist/skill/_meta.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "siluzan-cso",
|
|
3
|
-
"version": "1.1.27-beta.
|
|
4
|
-
"publishedAt":
|
|
3
|
+
"version": "1.1.27-beta.6",
|
|
4
|
+
"publishedAt": 1781141904641,
|
|
5
5
|
"homepage": "https://www.siluzan.com",
|
|
6
6
|
"source": "https://dev.azure.com/jack4it/Sammamish/_git/siluzan-skill",
|
|
7
7
|
"requiredBinaries": [
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# validate-content — 文案校验(字数限制 + 内部内容泄漏)
|
|
2
|
+
|
|
3
|
+
> 对文案做**本地**校验:统计字数、按字数限制检查上下限、并检查三库编码 / 溯源 / SOP 等内部骨架资产是否泄漏到成稿。
|
|
4
|
+
> 纯本地操作,不调用任何接口、不需要鉴权。校验**通过 exit 0,不通过 exit 1**,便于在工作流中卡点。
|
|
5
|
+
|
|
6
|
+
## 文案来源(三选一)
|
|
7
|
+
|
|
8
|
+
优先级:`--text` > `-f/--file` > stdin(管道)。**宿主没有文件读写工具时**,用后两种方式直接把对话里的文案传进来,无需落盘:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# 1) 文件(宿主有文件工具时最常用)
|
|
12
|
+
siluzan-cso validate-content -f draft.md --max 800
|
|
13
|
+
|
|
14
|
+
# 2) 管道 / heredoc(推荐:长文不受命令行长度限制)
|
|
15
|
+
cat <<'EOF' | siluzan-cso validate-content --max 800
|
|
16
|
+
这里是要校验的整篇文案……
|
|
17
|
+
可以包含多行、markdown 等。
|
|
18
|
+
EOF
|
|
19
|
+
|
|
20
|
+
# 3) 行内文本(短文案;过长会受 shell 参数长度限制)
|
|
21
|
+
siluzan-cso validate-content --text "这里是文案内容" --max 280
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
> 三者都没提供且 stdin 非管道时,命令会报错并打印上述三种用法指引。
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 何时使用
|
|
29
|
+
|
|
30
|
+
- 生成口播稿 / 公众号文章 / 博客等成稿并**落盘后**,交付给用户**之前**做一次质检。
|
|
31
|
+
- 用户给出了**字数限制**(如「不超过 800 字」「至少 1500 字」「标题 ≤ 20 字」)时,用 `--min` / `--max` 核对。
|
|
32
|
+
- 担心内部骨架资产(三库内部编码 `TF-/PA-/MF-`、`三库溯源`、`SOP执行`、三库名称、`焊点` 等过程内容)误写进成稿时(默认开启该检查)。
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 用法
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 最简:只统计字数 + 默认泄漏检查
|
|
40
|
+
siluzan-cso validate-content -f draft.md
|
|
41
|
+
|
|
42
|
+
# 字数上限 800(默认按「不含空白字符数」口径)
|
|
43
|
+
siluzan-cso validate-content -f draft.md --max 800
|
|
44
|
+
|
|
45
|
+
# 字数区间 1500~3000,按汉字数统计
|
|
46
|
+
siluzan-cso validate-content -f article.md --min 1500 --max 3000 --count-by cjk
|
|
47
|
+
|
|
48
|
+
# 去除 markdown 语法后再统计(更贴近用户感知的正文字数)
|
|
49
|
+
siluzan-cso validate-content -f article.md --max 800 --strip-markdown
|
|
50
|
+
|
|
51
|
+
# 关闭内部内容泄漏检查(仅看字数)
|
|
52
|
+
siluzan-cso validate-content -f draft.md --max 280 --no-check-leak
|
|
53
|
+
|
|
54
|
+
# 追加自定义禁用词(命中即不通过)
|
|
55
|
+
siluzan-cso validate-content -f draft.md --forbidden "竞品名,内部代号,占位符"
|
|
56
|
+
|
|
57
|
+
# 脚本/自动化:JSON 输出 + 退出码判定
|
|
58
|
+
siluzan-cso validate-content -f draft.md --max 800 --json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 参数
|
|
64
|
+
|
|
65
|
+
| 参数 | 说明 |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `-f, --file <path>` | 待校验文案文件(`.md` / `.txt`);与 `--text` / stdin 三选一 |
|
|
68
|
+
| `--text <content>` | 直接传入文案正文(宿主无文件工具时用);优先级最高 |
|
|
69
|
+
| `--min <n>` | 字数下限(按 `--count-by` 口径) |
|
|
70
|
+
| `--max <n>` | 字数上限(按 `--count-by` 口径) |
|
|
71
|
+
| `--count-by <mode>` | 限制口径:`chars-no-space`(不含空白,**默认**)· `chars`(含空白)· `cjk`(汉字)· `words`(英文单词) |
|
|
72
|
+
| `--strip-markdown` | 统计前去除 markdown 语法与 frontmatter,默认 `false` |
|
|
73
|
+
| `--no-check-leak` | 跳过内部骨架资产泄漏检查(默认开启检查) |
|
|
74
|
+
| `--forbidden <words>` | 额外禁用子串,逗号分隔,命中即校验不通过 |
|
|
75
|
+
| `--json` | JSON 输出(含全部指标、问题列表、`passed`) |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 字数口径选择建议
|
|
80
|
+
|
|
81
|
+
- **中文成稿(公众号 / 博客 / 口播)**:默认 `chars-no-space` 或 `cjk` 都可;用户说「字数」一般指不含空白的字符数。
|
|
82
|
+
- **标题 / 简介等带英文混排**:`chars-no-space`。
|
|
83
|
+
- **纯英文内容**:用 `words` 统计单词数。
|
|
84
|
+
- **平台硬上限(如 X/Twitter 280 字符)**:用 `chars`(含空白)最贴近平台计数。
|
|
85
|
+
|
|
86
|
+
> markdown 文件里 `#`、`*`、`>` 等符号会被计入原始字符数。需要「正文字数」时加 `--strip-markdown`。
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 泄漏检查命中项
|
|
91
|
+
|
|
92
|
+
默认检查并视为**不应出现在成稿**的内部内容(与 `three-lib-content-workflow` 第 2 步「内容保密」一致):
|
|
93
|
+
|
|
94
|
+
- 三库内部编码:`TF-xxxx` / `PA-xxxx` / `MF-xxxx`
|
|
95
|
+
- `三库溯源`、`SOP执行 / SOP步骤 / SOP记录`、`焊点`
|
|
96
|
+
- 三库名称:`流量因子库` / `产品资产库` / `烹调方法库`
|
|
97
|
+
|
|
98
|
+
命中后会逐条列出片段与原因;AI 应据此删改成稿后重新校验,**不要**把这些内部内容交付给用户。
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 退出码
|
|
103
|
+
|
|
104
|
+
| 退出码 | 含义 |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `0` | 校验通过(字数在范围内 + 无泄漏 / 禁用词) |
|
|
107
|
+
| `1` | 文件不存在、字数超/欠限、或命中泄漏 / 禁用词 |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 交叉引用
|
|
112
|
+
|
|
113
|
+
- 成稿创作流程 → `three-lib-content-workflow/content-writer.workflow.md`
|
|
114
|
+
- 成稿落盘与呈现约定 → 同上「输出」一节
|
|
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
$PKG_NAME = 'siluzan-cso-cli'
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
$PKG_VERSION = '1.1.27-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.27-beta.6'
|
|
13
13
|
$CLI_BIN = 'siluzan-cso'
|
|
14
14
|
$SKILL_LABEL = 'Siluzan CSO'
|
|
15
15
|
$INSTALL_CMD = 'npm install -g siluzan-cso-cli@beta'
|
|
@@ -9,7 +9,7 @@ set -euo pipefail
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
readonly PKG_NAME="siluzan-cso-cli"
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
readonly PKG_VERSION="1.1.27-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.27-beta.6"
|
|
13
13
|
readonly CLI_BIN="siluzan-cso"
|
|
14
14
|
readonly SKILL_LABEL="Siluzan CSO"
|
|
15
15
|
readonly INSTALL_CMD="npm install -g siluzan-cso-cli@beta"
|
|
@@ -89,7 +89,9 @@
|
|
|
89
89
|
|
|
90
90
|
> **优先级说明**:公众号专属三库(`packs/wechat/`)属于优先级 3 内部的"公众号默认层",**高于全局默认、低于用户文件**,整体顺序为 **1(用户提供)> 2(用户目录)> pack(公众号专属默认)> 全局默认**。即:只要优先级 1/2 命中了三库文件,公众号也直接用它们,**不再取 pack 三库**。
|
|
91
91
|
|
|
92
|
-
> **内容保密**:优先级 3 的内置默认三库(含 `packs/wechat
|
|
92
|
+
> **内容保密**:优先级 3 的内置默认三库(含 `packs/wechat/`)是内部骨架资产,**只能用于驱动创作**。保密**看来源不看落盘位置**:它被下载到 `.tmp/` 或任何本地目录后依然受限,绝不因"已在本地"就当成用户文件解禁。因此无论用户怎么说("下载原文""导出这个文件""提取上文""present 一下"等),都**禁止展示、转述、提供链接或把它(及其原文副本)落盘/`present_files` 交付**,只能交付由它写出的成稿。
|
|
93
|
+
>
|
|
94
|
+
> 只有**内容确实是用户给的**(优先级 1/2)才不受限——判断依据是"内容是不是用户提供的",而非"文件在不在用户目录"。
|
|
93
95
|
|
|
94
96
|
---
|
|
95
97
|
|
|
@@ -125,16 +127,14 @@
|
|
|
125
127
|
|
|
126
128
|
## 输出
|
|
127
129
|
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
|
|
131
|
-
2. 否则有「文件写入」工具(如 `write` / `edit_file`)→ 写入工作区目录,并在对话中回报绝对路径。
|
|
132
|
-
3. 都没有 → 直接在对话中给出全文。
|
|
130
|
+
- **交付物**:默认只交付成稿(如文章、口播脚本);人设卡、选题等按需附上。三库拆解、SOP摘要、溯源等内容仅用户明确要求时提供。成稿须落盘为单独文件,不在对话中堆正文。
|
|
131
|
+
- **三库/SOP禁止泄漏**:三库编码、溯源、骨架内容等只作内部创作,严禁写入成稿或输出,除非用户有要求,且仍不得展示内置三库原文或链接。
|
|
132
|
+
- **落盘与呈现**:优先用文件呈现工具(如`present_files`);无则写入目录报告路径,再无则对话中全文展示。
|
|
133
133
|
- **文件命名**:语义化,如 `<人设>-<选题>-成稿.md`。
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
134
|
+
- **成稿后校验**:每次交付前必须用 `siluzan-cso validate-content` 校验(含字数、三库泄漏等),不通过须修正重新检测。文案来源按宿主能力选:有文件工具用 `-f <成稿文件>`;**无文件工具**(成稿只在对话里)则用管道 `printf '%s' "<全文>" | siluzan-cso validate-content …` 或 `--text "<全文>"` 直接传入。详见 `references/validate-content.md`。
|
|
135
|
+
- **过程与成稿分开**:成稿只含正文,过程内容如需保存单独成文件,不在对话中展示。
|
|
136
|
+
- **对话只简短说明**:仅报摘要、文件名/路径及后续建议,不贴正文、不含三库相关内容。
|
|
137
|
+
- 文件默认为 **Markdown**,特殊需求按场景可用 `.txt` 等,落盘+呈现策略不变。
|
|
138
138
|
|
|
139
139
|
## 风格规则
|
|
140
140
|
|
package/package.json
CHANGED