autocrew 0.3.5 → 0.3.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/package.json
CHANGED
|
@@ -1,23 +1,38 @@
|
|
|
1
1
|
import type { CommandDef } from "./index.js";
|
|
2
|
+
import { resolveProjectText } from "./index.js";
|
|
2
3
|
|
|
3
4
|
export const cmd: CommandDef = {
|
|
4
5
|
name: "humanize",
|
|
5
6
|
description: "Run Chinese de-AI pass on a content draft",
|
|
6
|
-
usage: "autocrew humanize <content-id>",
|
|
7
|
+
usage: "autocrew humanize <content-id-or-project-slug> [--file <path>]",
|
|
7
8
|
action: async (args, runner) => {
|
|
8
|
-
const
|
|
9
|
-
if (!
|
|
10
|
-
console.error("Usage: autocrew humanize <content-id>");
|
|
9
|
+
const id = args[0];
|
|
10
|
+
if (!id && !args.includes("--file")) {
|
|
11
|
+
console.error("Usage: autocrew humanize <content-id-or-project-slug> [--file <path>]");
|
|
11
12
|
process.exitCode = 1;
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
const resolved = await resolveProjectText(id, args);
|
|
17
|
+
if (!resolved) {
|
|
18
|
+
console.error(`Not found: "${id}". Provide a content ID, pipeline project slug, or --file <path>.`);
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const result = await runner.execute("autocrew_humanize", {
|
|
24
|
+
action: "humanize_zh",
|
|
25
|
+
text: resolved.text,
|
|
26
|
+
});
|
|
27
|
+
|
|
15
28
|
if (!result.ok) {
|
|
16
29
|
console.error(`Humanize failed: ${result.error || "unknown error"}`);
|
|
17
30
|
process.exitCode = 1;
|
|
18
31
|
return;
|
|
19
32
|
}
|
|
20
|
-
|
|
33
|
+
|
|
34
|
+
console.log(`De-AI pass complete for "${resolved.title}" (${resolved.source})`);
|
|
35
|
+
console.log(`Changes: ${result.changeCount || 0}`);
|
|
21
36
|
if ((result.changes as any[])?.length > 0) {
|
|
22
37
|
for (const c of result.changes as string[]) {
|
|
23
38
|
console.log(` • ${c}`);
|
|
@@ -21,6 +21,57 @@ export function getOption(args: string[], flag: string): string | undefined {
|
|
|
21
21
|
return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a project identifier to draft text.
|
|
26
|
+
* Supports: legacy content ID, pipeline project slug, or --file path.
|
|
27
|
+
* Returns { text, title, source } or null if not found.
|
|
28
|
+
*/
|
|
29
|
+
export async function resolveProjectText(
|
|
30
|
+
idOrSlug: string,
|
|
31
|
+
args: string[],
|
|
32
|
+
): Promise<{ text: string; title: string; source: string } | null> {
|
|
33
|
+
const filePath = getOption(args, "--file");
|
|
34
|
+
|
|
35
|
+
// --file flag: read directly from file path
|
|
36
|
+
if (filePath) {
|
|
37
|
+
const fs = await import("node:fs/promises");
|
|
38
|
+
try {
|
|
39
|
+
const text = await fs.readFile(filePath, "utf-8");
|
|
40
|
+
const titleMatch = text.match(/^#\s+(.+)/m);
|
|
41
|
+
return { text, title: titleMatch?.[1]?.trim() || filePath, source: `file:${filePath}` };
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!idOrSlug) return null;
|
|
48
|
+
|
|
49
|
+
// Try legacy content ID first
|
|
50
|
+
try {
|
|
51
|
+
const { getContent } = await import("../../storage/local-store.js");
|
|
52
|
+
const content = await getContent(idOrSlug);
|
|
53
|
+
if (content) {
|
|
54
|
+
return { text: content.body, title: content.title, source: `content:${content.id}` };
|
|
55
|
+
}
|
|
56
|
+
} catch { /* ignore */ }
|
|
57
|
+
|
|
58
|
+
// Try pipeline project slug
|
|
59
|
+
try {
|
|
60
|
+
const { findProject } = await import("../../storage/pipeline-store.js");
|
|
61
|
+
const fs = await import("node:fs/promises");
|
|
62
|
+
const path = await import("node:path");
|
|
63
|
+
const found = await findProject(idOrSlug);
|
|
64
|
+
if (found) {
|
|
65
|
+
const draftPath = path.join(found.dir, "draft.md");
|
|
66
|
+
const text = await fs.readFile(draftPath, "utf-8");
|
|
67
|
+
const titleMatch = text.match(/^#\s+(.+)/m);
|
|
68
|
+
return { text, title: titleMatch?.[1]?.trim() || idOrSlug, source: `pipeline:${idOrSlug}` };
|
|
69
|
+
}
|
|
70
|
+
} catch { /* ignore */ }
|
|
71
|
+
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
24
75
|
import { cmd as statusCmd } from "./status.js";
|
|
25
76
|
import { cmd as topicsCmd } from "./topics.js";
|
|
26
77
|
import { cmd as contentsCmd } from "./contents.js";
|
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
import type { CommandDef } from "./index.js";
|
|
2
|
+
import { resolveProjectText } from "./index.js";
|
|
2
3
|
|
|
3
4
|
export const cmd: CommandDef = {
|
|
4
5
|
name: "pre-publish",
|
|
5
6
|
description: "Run pre-publish checklist: 6 checks before allowing publish",
|
|
6
|
-
usage: "autocrew pre-publish <content-id>",
|
|
7
|
+
usage: "autocrew pre-publish <content-id-or-project-slug> [--file <path>]",
|
|
7
8
|
action: async (args, runner) => {
|
|
8
|
-
const
|
|
9
|
-
if (!
|
|
10
|
-
console.error("Usage: autocrew pre-publish <
|
|
9
|
+
const id = args[0];
|
|
10
|
+
if (!id && !args.includes("--file")) {
|
|
11
|
+
console.error("Usage: autocrew pre-publish <id-or-slug> [--file <path>]");
|
|
11
12
|
process.exitCode = 1;
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
|
|
16
|
+
const resolved = await resolveProjectText(id, args);
|
|
17
|
+
if (!resolved) {
|
|
18
|
+
console.error(`Not found: "${id}". Provide a content ID, pipeline project slug, or --file <path>.`);
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Try with content_id first (legacy), fall back to text-based check
|
|
24
|
+
let result: any;
|
|
25
|
+
if (resolved.source.startsWith("content:")) {
|
|
26
|
+
const contentId = resolved.source.replace("content:", "");
|
|
27
|
+
result = await runner.execute("autocrew_pre_publish", {
|
|
28
|
+
action: "check",
|
|
29
|
+
content_id: contentId,
|
|
30
|
+
});
|
|
31
|
+
} else {
|
|
32
|
+
// Pipeline project or file — use text-based review as proxy
|
|
33
|
+
result = await runner.execute("autocrew_review", {
|
|
34
|
+
action: "full_review",
|
|
35
|
+
text: resolved.text,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
18
38
|
|
|
19
39
|
if (!result.ok) {
|
|
20
40
|
console.error(`Pre-publish check failed: ${result.error || "unknown error"}`);
|
|
@@ -22,6 +42,7 @@ export const cmd: CommandDef = {
|
|
|
22
42
|
return;
|
|
23
43
|
}
|
|
24
44
|
|
|
25
|
-
console.log(
|
|
45
|
+
console.log(`Pre-publish check for "${resolved.title}" (${resolved.source}):`);
|
|
46
|
+
console.log(result.summary || "Check complete.");
|
|
26
47
|
},
|
|
27
48
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { CommandDef } from "./index.js";
|
|
2
|
-
import { getOption } from "./index.js";
|
|
2
|
+
import { getOption, resolveProjectText } from "./index.js";
|
|
3
3
|
|
|
4
4
|
export const cmd: CommandDef = {
|
|
5
5
|
name: "review",
|
|
6
|
-
description: "Run full content review or auto-fix
|
|
7
|
-
usage: "autocrew review <content-id> [--platform <
|
|
6
|
+
description: "Run full content review or auto-fix",
|
|
7
|
+
usage: "autocrew review <content-id-or-project-slug> [--platform <p>] [--fix] [--file <path>]",
|
|
8
8
|
action: async (args, runner) => {
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
11
|
-
console.error("Usage: autocrew review <
|
|
9
|
+
const id = args[0];
|
|
10
|
+
if (!id && !args.includes("--file")) {
|
|
11
|
+
console.error("Usage: autocrew review <id-or-slug> [--platform <p>] [--fix] [--file <path>]");
|
|
12
12
|
process.exitCode = 1;
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
@@ -16,11 +16,17 @@ export const cmd: CommandDef = {
|
|
|
16
16
|
const platform = getOption(args, "--platform");
|
|
17
17
|
const isFix = args.includes("--fix");
|
|
18
18
|
|
|
19
|
+
const resolved = await resolveProjectText(id, args);
|
|
20
|
+
if (!resolved) {
|
|
21
|
+
console.error(`Not found: "${id}". Provide a content ID, pipeline project slug, or --file <path>.`);
|
|
22
|
+
process.exitCode = 1;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
if (isFix) {
|
|
20
|
-
// auto-fix mode
|
|
21
27
|
const result = await runner.execute("autocrew_review", {
|
|
22
28
|
action: "auto_fix",
|
|
23
|
-
|
|
29
|
+
text: resolved.text,
|
|
24
30
|
platform,
|
|
25
31
|
});
|
|
26
32
|
|
|
@@ -30,17 +36,15 @@ export const cmd: CommandDef = {
|
|
|
30
36
|
return;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
console.log(`Auto-fix complete for ${
|
|
39
|
+
console.log(`Auto-fix complete for "${resolved.title}" (${resolved.source})`);
|
|
34
40
|
console.log(` Sensitive words fixed: ${result.sensitiveWordsFixed || 0}`);
|
|
35
41
|
console.log(` AI traces fixed: ${result.aiFixesApplied || 0}`);
|
|
36
|
-
console.log(` Saved: ${result.saved ? "yes" : "no"}`);
|
|
37
42
|
return;
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
// full review mode
|
|
41
45
|
const result = await runner.execute("autocrew_review", {
|
|
42
46
|
action: "full_review",
|
|
43
|
-
|
|
47
|
+
text: resolved.text,
|
|
44
48
|
platform,
|
|
45
49
|
}) as any;
|
|
46
50
|
|
|
@@ -50,6 +54,7 @@ export const cmd: CommandDef = {
|
|
|
50
54
|
return;
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
console.log(`Review for "${resolved.title}" (${resolved.source}):`);
|
|
53
58
|
console.log(result.summary);
|
|
54
59
|
if (result.fixes?.length > 0) {
|
|
55
60
|
console.log("\nSuggested fixes:");
|