autocrew 0.3.8 → 0.3.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autocrew",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "One-person content studio powered by AI — from trending topics to published posts",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -4,7 +4,7 @@ import { getOption, resolveProjectText } from "./index.js";
4
4
  export const cmd: CommandDef = {
5
5
  name: "review",
6
6
  description: "Run full content review or auto-fix",
7
- usage: "autocrew review <content-id-or-project-slug> [--platform <p>] [--fix] [--file <path>]",
7
+ usage: "autocrew review <id-or-slug> [--platform <p>] [--fix] [--dry-run] [--file <path>]",
8
8
  action: async (args, runner) => {
9
9
  const id = args[0];
10
10
  if (!id && !args.includes("--file")) {
@@ -15,6 +15,7 @@ export const cmd: CommandDef = {
15
15
 
16
16
  const platform = getOption(args, "--platform");
17
17
  const isFix = args.includes("--fix");
18
+ const isDryRun = args.includes("--dry-run");
18
19
 
19
20
  const resolved = await resolveProjectText(id, args);
20
21
  if (!resolved) {
@@ -23,7 +24,7 @@ export const cmd: CommandDef = {
23
24
  return;
24
25
  }
25
26
 
26
- if (isFix) {
27
+ if (isFix || isDryRun) {
27
28
  const result = await runner.execute("autocrew_review", {
28
29
  action: "auto_fix",
29
30
  text: resolved.text,
@@ -36,13 +37,47 @@ export const cmd: CommandDef = {
36
37
  return;
37
38
  }
38
39
 
39
- // Write fixed text back to source file
40
40
  const fixedText = (result.autoFixedText || result.fixedText || "") as string;
41
+ console.log(` Sensitive words fixed: ${result.sensitiveWordsFixed || 0}`);
42
+ console.log(` AI traces fixed: ${result.aiFixesApplied || 0}`);
43
+
44
+ // Show diff preview
45
+ if (fixedText && fixedText !== resolved.text) {
46
+ // Simple line-by-line diff
47
+ const origLines = resolved.text.split("\n");
48
+ const fixedLines = fixedText.split("\n");
49
+ const diffLines: string[] = [];
50
+ const maxLen = Math.max(origLines.length, fixedLines.length);
51
+ for (let i = 0; i < maxLen; i++) {
52
+ const orig = origLines[i] ?? "";
53
+ const fixed = fixedLines[i] ?? "";
54
+ if (orig !== fixed) {
55
+ if (orig) diffLines.push(` - ${orig}`);
56
+ if (fixed) diffLines.push(` + ${fixed}`);
57
+ }
58
+ }
59
+ if (diffLines.length > 0) {
60
+ console.log(`\n Changes preview:`);
61
+ for (const line of diffLines.slice(0, 20)) {
62
+ console.log(line);
63
+ }
64
+ if (diffLines.length > 20) {
65
+ console.log(` ... and ${diffLines.length - 20} more lines`);
66
+ }
67
+ }
68
+ }
69
+
70
+ if (isDryRun) {
71
+ console.log(`\n (dry-run mode — no files modified)`);
72
+ return;
73
+ }
74
+
75
+ // Write fixed text back to source file
41
76
  if (fixedText && resolved.source.startsWith("file:")) {
42
77
  const fs = await import("node:fs/promises");
43
78
  const filePath = resolved.source.replace("file:", "");
44
79
  await fs.writeFile(filePath, fixedText, "utf-8");
45
- console.log(`Auto-fix complete for "${resolved.title}" — saved back to ${filePath}`);
80
+ console.log(`\n Saved back to ${filePath}`);
46
81
  } else if (fixedText && resolved.source.startsWith("pipeline:")) {
47
82
  const fs = await import("node:fs/promises");
48
83
  const { findProject } = await import("../../storage/pipeline-store.js");
@@ -51,13 +86,9 @@ export const cmd: CommandDef = {
51
86
  if (found) {
52
87
  const path = await import("node:path");
53
88
  await fs.writeFile(path.join(found.dir, "draft.md"), fixedText, "utf-8");
54
- console.log(`Auto-fix complete for "${resolved.title}" — saved back to draft.md`);
89
+ console.log(`\n Saved back to draft.md`);
55
90
  }
56
- } else {
57
- console.log(`Auto-fix complete for "${resolved.title}" (${resolved.source})`);
58
91
  }
59
- console.log(` Sensitive words fixed: ${result.sensitiveWordsFixed || 0}`);
60
- console.log(` AI traces fixed: ${result.aiFixesApplied || 0}`);
61
92
  return;
62
93
  }
63
94
 
@@ -250,13 +250,21 @@ export async function executeReview(params: Record<string, unknown>) {
250
250
  const fixes: string[] = [];
251
251
  if (sensitiveWords.hitCount > 0) {
252
252
  fixes.push(`修复 ${sensitiveWords.hitCount} 个敏感词`);
253
- for (const hit of sensitiveWords.hits.slice(0, 5)) {
253
+ for (const hit of sensitiveWords.hits.slice(0, 10)) {
254
254
  const fix = hit.suggestion ? `"${hit.word}" → "${hit.suggestion}"` : `删除"${hit.word}"`;
255
- fixes.push(` - ${fix} (${hit.category})`);
255
+ // Show surrounding context for each hit
256
+ const pos = hit.positions[0];
257
+ const contextStart = Math.max(0, pos - 10);
258
+ const contextEnd = Math.min(fullText.length, pos + hit.word.length + 10);
259
+ const context = fullText.slice(contextStart, contextEnd).replace(/\n/g, " ");
260
+ fixes.push(` - ${fix} (${hit.category}) — "...${context}..."`);
256
261
  }
257
262
  }
258
263
  if (aiCheck.hasAiTraces) {
259
264
  fixes.push(`去 AI 味:${aiCheck.changeCount} 处需要修改`);
265
+ for (const change of aiCheck.changes.slice(0, 5)) {
266
+ fixes.push(` - ${change}`);
267
+ }
260
268
  }
261
269
  for (const note of qualityScore.notes) {
262
270
  fixes.push(note);