@npow/ghostwriter 0.1.0
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/dist/commands/connect.d.ts +30 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +442 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/create/index.d.ts +6 -0
- package/dist/commands/create/index.d.ts.map +1 -0
- package/dist/commands/create/index.js +89 -0
- package/dist/commands/create/index.js.map +1 -0
- package/dist/commands/create/prompts/example-article.d.ts +3 -0
- package/dist/commands/create/prompts/example-article.d.ts.map +1 -0
- package/dist/commands/create/prompts/example-article.js +32 -0
- package/dist/commands/create/prompts/example-article.js.map +1 -0
- package/dist/commands/create/prompts/intent-parsing.d.ts +3 -0
- package/dist/commands/create/prompts/intent-parsing.d.ts.map +1 -0
- package/dist/commands/create/prompts/intent-parsing.js +45 -0
- package/dist/commands/create/prompts/intent-parsing.js.map +1 -0
- package/dist/commands/create/prompts/page-content.d.ts +3 -0
- package/dist/commands/create/prompts/page-content.d.ts.map +1 -0
- package/dist/commands/create/prompts/page-content.js +56 -0
- package/dist/commands/create/prompts/page-content.js.map +1 -0
- package/dist/commands/create/prompts/source-discovery.d.ts +3 -0
- package/dist/commands/create/prompts/source-discovery.d.ts.map +1 -0
- package/dist/commands/create/prompts/source-discovery.js +46 -0
- package/dist/commands/create/prompts/source-discovery.js.map +1 -0
- package/dist/commands/create/prompts/voice-generation.d.ts +3 -0
- package/dist/commands/create/prompts/voice-generation.d.ts.map +1 -0
- package/dist/commands/create/prompts/voice-generation.js +43 -0
- package/dist/commands/create/prompts/voice-generation.js.map +1 -0
- package/dist/commands/create/steps/assemble-config.d.ts +5 -0
- package/dist/commands/create/steps/assemble-config.d.ts.map +1 -0
- package/dist/commands/create/steps/assemble-config.js +82 -0
- package/dist/commands/create/steps/assemble-config.js.map +1 -0
- package/dist/commands/create/steps/discover-sources.d.ts +5 -0
- package/dist/commands/create/steps/discover-sources.d.ts.map +1 -0
- package/dist/commands/create/steps/discover-sources.js +53 -0
- package/dist/commands/create/steps/discover-sources.js.map +1 -0
- package/dist/commands/create/steps/fingerprint-style.d.ts +5 -0
- package/dist/commands/create/steps/fingerprint-style.d.ts.map +1 -0
- package/dist/commands/create/steps/fingerprint-style.js +46 -0
- package/dist/commands/create/steps/fingerprint-style.js.map +1 -0
- package/dist/commands/create/steps/generate-example.d.ts +4 -0
- package/dist/commands/create/steps/generate-example.d.ts.map +1 -0
- package/dist/commands/create/steps/generate-example.js +23 -0
- package/dist/commands/create/steps/generate-example.js.map +1 -0
- package/dist/commands/create/steps/generate-voice.d.ts +4 -0
- package/dist/commands/create/steps/generate-voice.d.ts.map +1 -0
- package/dist/commands/create/steps/generate-voice.js +32 -0
- package/dist/commands/create/steps/generate-voice.js.map +1 -0
- package/dist/commands/create/steps/parse-intent.d.ts +4 -0
- package/dist/commands/create/steps/parse-intent.d.ts.map +1 -0
- package/dist/commands/create/steps/parse-intent.js +16 -0
- package/dist/commands/create/steps/parse-intent.js.map +1 -0
- package/dist/commands/create/steps/resolve-connection.d.ts +5 -0
- package/dist/commands/create/steps/resolve-connection.d.ts.map +1 -0
- package/dist/commands/create/steps/resolve-connection.js +100 -0
- package/dist/commands/create/steps/resolve-connection.js.map +1 -0
- package/dist/commands/create/steps/resolve-schedule.d.ts +13 -0
- package/dist/commands/create/steps/resolve-schedule.d.ts.map +1 -0
- package/dist/commands/create/steps/resolve-schedule.js +70 -0
- package/dist/commands/create/steps/resolve-schedule.js.map +1 -0
- package/dist/commands/create/steps/setup-site.d.ts +5 -0
- package/dist/commands/create/steps/setup-site.d.ts.map +1 -0
- package/dist/commands/create/steps/setup-site.js +44 -0
- package/dist/commands/create/steps/setup-site.js.map +1 -0
- package/dist/commands/create/steps/validate-and-summary.d.ts +4 -0
- package/dist/commands/create/steps/validate-and-summary.d.ts.map +1 -0
- package/dist/commands/create/steps/validate-and-summary.js +60 -0
- package/dist/commands/create/steps/validate-and-summary.js.map +1 -0
- package/dist/commands/create/steps/validate-site-access.d.ts +4 -0
- package/dist/commands/create/steps/validate-site-access.d.ts.map +1 -0
- package/dist/commands/create/steps/validate-site-access.js +25 -0
- package/dist/commands/create/steps/validate-site-access.js.map +1 -0
- package/dist/commands/create/types.d.ts +72 -0
- package/dist/commands/create/types.d.ts.map +1 -0
- package/dist/commands/create/types.js +2 -0
- package/dist/commands/create/types.js.map +1 -0
- package/dist/commands/fingerprint.d.ts +4 -0
- package/dist/commands/fingerprint.d.ts.map +1 -0
- package/dist/commands/fingerprint.js +31 -0
- package/dist/commands/fingerprint.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +117 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +36 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/logs.d.ts +6 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +49 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/patterns.d.ts +6 -0
- package/dist/commands/patterns.d.ts.map +1 -0
- package/dist/commands/patterns.js +51 -0
- package/dist/commands/patterns.js.map +1 -0
- package/dist/commands/run.d.ts +6 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +139 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +66 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/validate.d.ts +2 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +83 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { getChannelsDir } from "@ghostwriter/core";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
const TEMPLATE_CONFIG = `id: {CHANNEL_ID}
|
|
6
|
+
name: "{CHANNEL_NAME}"
|
|
7
|
+
contentType: article
|
|
8
|
+
|
|
9
|
+
topic:
|
|
10
|
+
domain: your-domain
|
|
11
|
+
focus: "What this channel covers"
|
|
12
|
+
keywords:
|
|
13
|
+
- keyword1
|
|
14
|
+
- keyword2
|
|
15
|
+
constraints: "Any constraints on content"
|
|
16
|
+
|
|
17
|
+
dataSources:
|
|
18
|
+
- type: rss
|
|
19
|
+
url: https://example.com/feed.xml
|
|
20
|
+
maxItems: 10
|
|
21
|
+
|
|
22
|
+
voice:
|
|
23
|
+
name: "Your Writer Name"
|
|
24
|
+
persona: "Brief description of the writer's personality and style"
|
|
25
|
+
age: 35
|
|
26
|
+
backstory: "How they got into this topic"
|
|
27
|
+
opinions:
|
|
28
|
+
- "A strong opinion they hold"
|
|
29
|
+
verbalTics:
|
|
30
|
+
- "A catchphrase or verbal habit"
|
|
31
|
+
exampleContent:
|
|
32
|
+
- ./examples/sample-1.md
|
|
33
|
+
vocabulary:
|
|
34
|
+
preferred:
|
|
35
|
+
- word1
|
|
36
|
+
- word2
|
|
37
|
+
forbidden:
|
|
38
|
+
- "it's important to note"
|
|
39
|
+
- "delve"
|
|
40
|
+
tone: conversational
|
|
41
|
+
|
|
42
|
+
publishTargets:
|
|
43
|
+
- platform: wordpress
|
|
44
|
+
id: wordpress-com
|
|
45
|
+
- platform: twitter
|
|
46
|
+
format: thread
|
|
47
|
+
maxTweets: 10
|
|
48
|
+
|
|
49
|
+
schedule:
|
|
50
|
+
cron: "0 10 * * MON"
|
|
51
|
+
timezone: America/New_York
|
|
52
|
+
enabled: true
|
|
53
|
+
|
|
54
|
+
qualityGate:
|
|
55
|
+
minScores:
|
|
56
|
+
structure: 7
|
|
57
|
+
readability: 7
|
|
58
|
+
voiceMatch: 7
|
|
59
|
+
factualAccuracy: 7
|
|
60
|
+
sourceCoverage: 7
|
|
61
|
+
hookStrength: 7
|
|
62
|
+
engagementPotential: 7
|
|
63
|
+
naturalness: 7
|
|
64
|
+
perplexityVariance: 7
|
|
65
|
+
maxRevisions: 3
|
|
66
|
+
|
|
67
|
+
targetWordCount: 1500
|
|
68
|
+
batchApi: false
|
|
69
|
+
`;
|
|
70
|
+
const SAMPLE_CONTENT = `# Sample Article Title
|
|
71
|
+
|
|
72
|
+
Here's an example of the writing style you want this channel to replicate.
|
|
73
|
+
|
|
74
|
+
Write 3-5 sample articles that demonstrate your preferred voice, tone, and structure. The style fingerprinting system will analyze these to extract quantitative features like:
|
|
75
|
+
|
|
76
|
+
- Sentence length distribution
|
|
77
|
+
- Paragraph variation
|
|
78
|
+
- Vocabulary richness
|
|
79
|
+
- Use of questions, contractions, first/second person
|
|
80
|
+
- Opening and closing styles
|
|
81
|
+
|
|
82
|
+
The more representative your examples, the better the generated content will match your desired style.
|
|
83
|
+
|
|
84
|
+
## Tips for Good Examples
|
|
85
|
+
|
|
86
|
+
Mix up your examples. Include some shorter pieces and some longer ones. Show the range of your style — serious and light, data-heavy and opinion-heavy.
|
|
87
|
+
|
|
88
|
+
Don't overthink it. Just write naturally in the voice you want the AI to replicate.
|
|
89
|
+
`;
|
|
90
|
+
export async function initCommand(channelName) {
|
|
91
|
+
const channelId = channelName
|
|
92
|
+
.toLowerCase()
|
|
93
|
+
.replace(/[^a-z0-9-]/g, "-")
|
|
94
|
+
.replace(/-+/g, "-");
|
|
95
|
+
const channelsDir = getChannelsDir();
|
|
96
|
+
const channelDir = join(channelsDir, channelId);
|
|
97
|
+
const examplesDir = join(channelDir, "examples");
|
|
98
|
+
console.log(chalk.blue(`\nInitializing channel: ${channelId}\n`));
|
|
99
|
+
// Create directories
|
|
100
|
+
await mkdir(examplesDir, { recursive: true });
|
|
101
|
+
// Write config template
|
|
102
|
+
const config = TEMPLATE_CONFIG.replace(/{CHANNEL_ID}/g, channelId).replace(/{CHANNEL_NAME}/g, channelName);
|
|
103
|
+
await writeFile(join(channelDir, "config.yml"), config, "utf-8");
|
|
104
|
+
// Write example content
|
|
105
|
+
await writeFile(join(examplesDir, "sample-1.md"), SAMPLE_CONTENT, "utf-8");
|
|
106
|
+
console.log(chalk.green(" Created:"));
|
|
107
|
+
console.log(` ${join(channelDir, "config.yml")}`);
|
|
108
|
+
console.log(` ${join(examplesDir, "sample-1.md")}`);
|
|
109
|
+
console.log();
|
|
110
|
+
console.log(chalk.yellow(" Next steps:"));
|
|
111
|
+
console.log(` 1. Edit ${join(channelDir, "config.yml")} with your settings`);
|
|
112
|
+
console.log(` 2. Add example content to ${examplesDir}/`);
|
|
113
|
+
console.log(` 3. Run: ghostwriter validate ${channelId}`);
|
|
114
|
+
console.log(` 4. Run: ghostwriter run ${channelId} --dry-run`);
|
|
115
|
+
console.log();
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgEvB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;CAmBtB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,WAAmB;IACnD,MAAM,SAAS,GAAG,WAAW;SAC1B,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAEjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2BAA2B,SAAS,IAAI,CAAC,CAAC,CAAC;IAElE,qBAAqB;IACrB,MAAM,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9C,wBAAwB;IACxB,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,OAAO,CACxE,iBAAiB,EACjB,WAAW,CACZ,CAAC;IACF,MAAM,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAEjE,wBAAwB;IACxB,MAAM,SAAS,CACb,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,EAChC,cAAc,EACd,OAAO,CACR,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,qBAAqB,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CACT,iCAAiC,WAAW,GAAG,CAChD,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,oCAAoC,SAAS,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,+BAA+B,SAAS,YAAY,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,kBAsChC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { listChannels, loadChannelConfig } from "@ghostwriter/core";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import Table from "cli-table3";
|
|
4
|
+
export async function listCommand() {
|
|
5
|
+
const channelIds = await listChannels();
|
|
6
|
+
if (channelIds.length === 0) {
|
|
7
|
+
console.log(chalk.yellow("\nNo channels found. Run: ghostwriter init <channel-name>\n"));
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const table = new Table({
|
|
11
|
+
head: [
|
|
12
|
+
chalk.blue("Channel ID"),
|
|
13
|
+
chalk.blue("Name"),
|
|
14
|
+
chalk.blue("Content Type"),
|
|
15
|
+
chalk.blue("Voice"),
|
|
16
|
+
chalk.blue("Schedule"),
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
for (const id of channelIds) {
|
|
20
|
+
try {
|
|
21
|
+
const config = await loadChannelConfig(id);
|
|
22
|
+
table.push([
|
|
23
|
+
config.id,
|
|
24
|
+
config.name,
|
|
25
|
+
config.contentType,
|
|
26
|
+
config.voice.name,
|
|
27
|
+
config.schedule.cron,
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
table.push([id, chalk.red("(error)"), "", "", ""]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
console.log(`\n${table.toString()}\n`);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,UAAU,GAAG,MAAM,YAAY,EAAE,CAAC;IAExC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,6DAA6D,CAC9D,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;QACtB,IAAI,EAAE;YACJ,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAClB,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;YACnB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;SACvB;KACF,CAAC,CAAC;IAEH,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC3C,KAAK,CAAC,IAAI,CAAC;gBACT,MAAM,CAAC,EAAE;gBACT,MAAM,CAAC,IAAI;gBACX,MAAM,CAAC,WAAW;gBAClB,MAAM,CAAC,KAAK,CAAC,IAAI;gBACjB,MAAM,CAAC,QAAQ,CAAC,IAAI;aACrB,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAGA,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,iBA2E1E"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { getRecentRuns } from "@ghostwriter/monitoring";
|
|
3
|
+
export async function logsCommand(channelName, options) {
|
|
4
|
+
const limit = parseInt(options.lines, 10) || 20;
|
|
5
|
+
console.log(chalk.blue(`\nRecent pipeline runs for channel: ${channelName} (last ${limit})\n`));
|
|
6
|
+
try {
|
|
7
|
+
const runs = await getRecentRuns(channelName, limit);
|
|
8
|
+
if (runs.length === 0) {
|
|
9
|
+
console.log(chalk.gray(" No pipeline runs found for this channel."));
|
|
10
|
+
console.log(chalk.gray(" Run your first pipeline with: ghostwriter run " + channelName));
|
|
11
|
+
console.log();
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
for (const run of runs) {
|
|
15
|
+
const statusColor = run.status === "completed"
|
|
16
|
+
? chalk.green
|
|
17
|
+
: run.status === "failed" || run.status === "dead_letter"
|
|
18
|
+
? chalk.red
|
|
19
|
+
: chalk.yellow;
|
|
20
|
+
const startedAt = run.startedAt
|
|
21
|
+
? new Date(run.startedAt).toLocaleString()
|
|
22
|
+
: "unknown";
|
|
23
|
+
const duration = run.completedAt && run.startedAt
|
|
24
|
+
? `${Math.round((new Date(run.completedAt).getTime() - new Date(run.startedAt).getTime()) / 1000)}s`
|
|
25
|
+
: "—";
|
|
26
|
+
const cost = run.totalCost != null ? `$${run.totalCost.toFixed(4)}` : "—";
|
|
27
|
+
console.log(` ${statusColor("●")} ${chalk.bold(run.id.slice(0, 8))} ${statusColor(run.status.padEnd(12))} ${startedAt} ${chalk.gray(`duration: ${duration}`)} ${chalk.gray(`cost: ${cost}`)}`);
|
|
28
|
+
if (run.error) {
|
|
29
|
+
console.log(chalk.red(` Error: ${run.error}`));
|
|
30
|
+
}
|
|
31
|
+
if (run.currentStage) {
|
|
32
|
+
console.log(chalk.gray(` Stage: ${run.currentStage}`));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
console.log();
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39
|
+
if (message.includes("DATABASE_URL")) {
|
|
40
|
+
console.log(chalk.gray(" Database not configured. Set DATABASE_URL to enable run history."));
|
|
41
|
+
console.log(chalk.gray(" Alternatively, use the Temporal UI at http://localhost:8233 for workflow logs."));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log(chalk.red(` Failed to fetch logs: ${message}`));
|
|
45
|
+
}
|
|
46
|
+
console.log();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=logs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/commands/patterns.ts"],"names":[],"mappings":"AAMA,UAAU,eAAe;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,eAAe,iBAgBzB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { loadLearnedPatterns, saveLearnedPatterns, } from "@ghostwriter/core";
|
|
3
|
+
export async function patternsCommand(subcommand, channelId, options) {
|
|
4
|
+
if (!subcommand || !channelId) {
|
|
5
|
+
console.log(chalk.red("Usage: ghostwriter patterns <list|prune> <channel-id>"));
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
switch (subcommand) {
|
|
9
|
+
case "list":
|
|
10
|
+
return listPatterns(channelId);
|
|
11
|
+
case "prune":
|
|
12
|
+
return prunePatterns(channelId, options);
|
|
13
|
+
default:
|
|
14
|
+
console.log(chalk.red(`Unknown subcommand: ${subcommand}`));
|
|
15
|
+
console.log(chalk.gray("Available: list, prune"));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function listPatterns(channelId) {
|
|
19
|
+
const patterns = await loadLearnedPatterns(channelId);
|
|
20
|
+
if (patterns.length === 0) {
|
|
21
|
+
console.log(chalk.gray(`\n No learned patterns for channel: ${channelId}`));
|
|
22
|
+
console.log(chalk.gray(" Patterns are discovered automatically during review.\n"));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log(chalk.blue(`\nLearned patterns for ${channelId} (${patterns.length}):\n`));
|
|
26
|
+
const sorted = [...patterns].sort((a, b) => b.confidence - a.confidence);
|
|
27
|
+
for (const p of sorted) {
|
|
28
|
+
const age = Math.round((Date.now() - new Date(p.lastSeenAt).getTime()) / (1000 * 60 * 60 * 24));
|
|
29
|
+
const confidenceColor = p.confidence >= 0.8
|
|
30
|
+
? chalk.green
|
|
31
|
+
: p.confidence >= 0.6
|
|
32
|
+
? chalk.yellow
|
|
33
|
+
: chalk.gray;
|
|
34
|
+
console.log(` ${confidenceColor("●")} ${chalk.bold(p.phrase)} ${chalk.gray(`[${p.category}]`)} conf: ${confidenceColor(p.confidence.toFixed(2))} seen: ${p.occurrences}x last: ${age}d ago`);
|
|
35
|
+
}
|
|
36
|
+
console.log();
|
|
37
|
+
}
|
|
38
|
+
async function prunePatterns(channelId, options) {
|
|
39
|
+
const days = parseInt(options.days ?? "90", 10);
|
|
40
|
+
const patterns = await loadLearnedPatterns(channelId);
|
|
41
|
+
if (patterns.length === 0) {
|
|
42
|
+
console.log(chalk.gray(`\n No patterns to prune for channel: ${channelId}\n`));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
|
|
46
|
+
const kept = patterns.filter((p) => new Date(p.lastSeenAt).getTime() >= cutoff);
|
|
47
|
+
const pruned = patterns.length - kept.length;
|
|
48
|
+
await saveLearnedPatterns(channelId, kept);
|
|
49
|
+
console.log(chalk.blue(`\n Pruned ${pruned} pattern(s) not seen in ${days} days. ${kept.length} remaining.\n`));
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/commands/patterns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAeA,UAAU,UAAU;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,iBAoKxE"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { loadChannelConfig, getChannelsDir, loadHistory, appendHistory, formatHistoryForPrompt, } from "@ghostwriter/core";
|
|
2
|
+
import { ingestData } from "@ghostwriter/data-ingestion";
|
|
3
|
+
import { runPipeline, analyzeStyleFingerprint } from "@ghostwriter/content-pipeline";
|
|
4
|
+
import { publishAll } from "@ghostwriter/publishing";
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import ora from "ora";
|
|
9
|
+
export async function runCommand(channelName, options) {
|
|
10
|
+
console.log(chalk.blue(`\n${options.dryRun ? "[DRY RUN] " : ""}Running pipeline for: ${channelName}\n`));
|
|
11
|
+
const spinner = ora();
|
|
12
|
+
try {
|
|
13
|
+
// Load config
|
|
14
|
+
spinner.start("Loading channel config...");
|
|
15
|
+
const config = await loadChannelConfig(channelName);
|
|
16
|
+
spinner.succeed(`Loaded config: ${config.name}`);
|
|
17
|
+
// Ingest data
|
|
18
|
+
spinner.start("Ingesting data from sources...");
|
|
19
|
+
const sources = await ingestData(config.id, config.dataSources);
|
|
20
|
+
spinner.succeed(`Ingested ${sources.length} source materials`);
|
|
21
|
+
// Load style fingerprint
|
|
22
|
+
let fingerprint;
|
|
23
|
+
if (config.voice.exampleContent.length > 0) {
|
|
24
|
+
spinner.start("Analyzing style fingerprint...");
|
|
25
|
+
const channelsDir = getChannelsDir();
|
|
26
|
+
const exampleTexts = [];
|
|
27
|
+
for (const examplePath of config.voice.exampleContent) {
|
|
28
|
+
try {
|
|
29
|
+
const text = await readFile(join(channelsDir, config.id, examplePath), "utf-8");
|
|
30
|
+
exampleTexts.push(text);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Skip missing
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (exampleTexts.length > 0) {
|
|
37
|
+
fingerprint = analyzeStyleFingerprint(config.id, exampleTexts);
|
|
38
|
+
spinner.succeed(`Style fingerprint computed from ${exampleTexts.length} example(s)`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
spinner.warn("No example content found, skipping fingerprint");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Load article history for deduplication
|
|
45
|
+
spinner.start("Loading article history...");
|
|
46
|
+
const history = await loadHistory(config.id);
|
|
47
|
+
const historyPrompt = formatHistoryForPrompt(history);
|
|
48
|
+
if (history.length > 0) {
|
|
49
|
+
spinner.succeed(`Loaded ${history.length} past article(s) for deduplication`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
spinner.info("No article history yet — first run for this channel");
|
|
53
|
+
}
|
|
54
|
+
// Run pipeline with progress callbacks
|
|
55
|
+
const result = await runPipeline(config, sources, {
|
|
56
|
+
fingerprint,
|
|
57
|
+
skipAdapt: false,
|
|
58
|
+
performanceContext: historyPrompt || undefined,
|
|
59
|
+
callbacks: {
|
|
60
|
+
onStageStart: (stage) => {
|
|
61
|
+
spinner.start(`Running ${stage} stage...`);
|
|
62
|
+
},
|
|
63
|
+
onStageComplete: (stage, cost) => {
|
|
64
|
+
spinner.succeed(`${stage} complete ${chalk.gray(`($${cost.toFixed(3)})`)}`);
|
|
65
|
+
},
|
|
66
|
+
onRevision: (revision, feedback) => {
|
|
67
|
+
console.log(chalk.yellow(`\n Revision ${revision} — Feedback:`));
|
|
68
|
+
for (const f of feedback.slice(0, 5)) {
|
|
69
|
+
console.log(chalk.yellow(` - ${f}`));
|
|
70
|
+
}
|
|
71
|
+
console.log();
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
// Display results
|
|
76
|
+
console.log(chalk.blue("\n─── Results ───\n"));
|
|
77
|
+
console.log(` Status: ${result.passed ? chalk.green("PASSED") : chalk.red("FAILED")}`);
|
|
78
|
+
console.log(` Revisions: ${result.revisions}`);
|
|
79
|
+
console.log(` Total Cost: $${result.totalCost.toFixed(3)}`);
|
|
80
|
+
console.log(` Word Count: ${result.draft.wordCount}`);
|
|
81
|
+
console.log(chalk.blue("\n─── Quality Scores ───\n"));
|
|
82
|
+
const scores = result.review.aggregateScores;
|
|
83
|
+
for (const [key, value] of Object.entries(scores)) {
|
|
84
|
+
const color = value >= 8 ? chalk.green : value >= 7 ? chalk.yellow : chalk.red;
|
|
85
|
+
const bar = "█".repeat(value) + "░".repeat(10 - value);
|
|
86
|
+
console.log(` ${key.padEnd(22)} ${color(bar)} ${color(value.toString())}/10`);
|
|
87
|
+
}
|
|
88
|
+
// Show agent feedback
|
|
89
|
+
console.log(chalk.blue("\n─── Agent Feedback ───\n"));
|
|
90
|
+
for (const agent of result.review.agentResults) {
|
|
91
|
+
const icon = agent.passed ? chalk.green("✓") : chalk.red("✗");
|
|
92
|
+
console.log(` ${icon} ${agent.agent}`);
|
|
93
|
+
for (const f of agent.feedback.slice(0, 3)) {
|
|
94
|
+
console.log(chalk.gray(` ${f}`));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Preview
|
|
98
|
+
console.log(chalk.blue("\n─── Content Preview ───\n"));
|
|
99
|
+
const preview = result.draft.content.slice(0, 500);
|
|
100
|
+
console.log(chalk.gray(preview));
|
|
101
|
+
if (result.draft.content.length > 500) {
|
|
102
|
+
console.log(chalk.gray(" ..."));
|
|
103
|
+
}
|
|
104
|
+
// Publish
|
|
105
|
+
if (!options.dryRun && result.passed) {
|
|
106
|
+
console.log(chalk.blue("\n─── Publishing ───\n"));
|
|
107
|
+
spinner.start("Publishing to platforms...");
|
|
108
|
+
const publishResults = await publishAll(config, result.adaptations);
|
|
109
|
+
for (const pub of publishResults) {
|
|
110
|
+
if (pub.success) {
|
|
111
|
+
spinner.succeed(`Published to ${pub.platform}${pub.url ? `: ${pub.url}` : ""}`);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
spinner.fail(`Failed to publish to ${pub.platform}: ${pub.error}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else if (!options.dryRun && !result.passed) {
|
|
119
|
+
console.log(chalk.red("\n Content did not pass quality gate. Not publishing."));
|
|
120
|
+
}
|
|
121
|
+
// Append to article history so future runs avoid repeating this topic
|
|
122
|
+
if (result.passed) {
|
|
123
|
+
const summary = result.draft.content.slice(0, 200).replace(/\n/g, " ").trim() + "...";
|
|
124
|
+
await appendHistory(config.id, {
|
|
125
|
+
headline: result.draft.headline,
|
|
126
|
+
summary,
|
|
127
|
+
topics: [config.topic.focus],
|
|
128
|
+
publishedAt: new Date().toISOString(),
|
|
129
|
+
});
|
|
130
|
+
spinner.succeed("Article added to history");
|
|
131
|
+
}
|
|
132
|
+
console.log();
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
spinner.fail(`Pipeline failed: ${err instanceof Error ? err.message : err}`);
|
|
136
|
+
process.exitCode = 1;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,iBAMvD"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { loadChannelConfig, listChannels } from "@ghostwriter/core";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import Table from "cli-table3";
|
|
4
|
+
export async function statusCommand(channelName) {
|
|
5
|
+
if (channelName) {
|
|
6
|
+
await showChannelStatus(channelName);
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
await showAllStatus();
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function showChannelStatus(channelName) {
|
|
13
|
+
try {
|
|
14
|
+
const config = await loadChannelConfig(channelName);
|
|
15
|
+
console.log(chalk.blue(`\nChannel: ${config.name}\n`));
|
|
16
|
+
console.log(` ID: ${config.id}`);
|
|
17
|
+
console.log(` Content Type: ${config.contentType}`);
|
|
18
|
+
console.log(` Topic: ${config.topic.focus}`);
|
|
19
|
+
console.log(` Voice: ${config.voice.name} (${config.voice.tone})`);
|
|
20
|
+
console.log(` Schedule: ${config.schedule.cron}`);
|
|
21
|
+
console.log(` Enabled: ${config.schedule.enabled}`);
|
|
22
|
+
console.log(` Platforms: ${config.publishTargets.map((t) => t.platform).join(", ")}`);
|
|
23
|
+
console.log(` Data Sources: ${config.dataSources.map((d) => d.type).join(", ")}`);
|
|
24
|
+
console.log(` Word Target: ${config.targetWordCount}`);
|
|
25
|
+
console.log();
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
console.log(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function showAllStatus() {
|
|
33
|
+
const channelIds = await listChannels();
|
|
34
|
+
if (channelIds.length === 0) {
|
|
35
|
+
console.log(chalk.yellow("\nNo channels found. Run: ghostwriter init <channel-name>\n"));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const table = new Table({
|
|
39
|
+
head: [
|
|
40
|
+
chalk.blue("ID"),
|
|
41
|
+
chalk.blue("Name"),
|
|
42
|
+
chalk.blue("Type"),
|
|
43
|
+
chalk.blue("Schedule"),
|
|
44
|
+
chalk.blue("Platforms"),
|
|
45
|
+
chalk.blue("Enabled"),
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
for (const id of channelIds) {
|
|
49
|
+
try {
|
|
50
|
+
const config = await loadChannelConfig(id);
|
|
51
|
+
table.push([
|
|
52
|
+
config.id,
|
|
53
|
+
config.name,
|
|
54
|
+
config.contentType,
|
|
55
|
+
config.schedule.cron,
|
|
56
|
+
config.publishTargets.map((t) => t.platform).join(", "),
|
|
57
|
+
config.schedule.enabled ? chalk.green("yes") : chalk.red("no"),
|
|
58
|
+
]);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
table.push([id, chalk.red("(invalid config)"), "", "", "", ""]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
console.log(`\n${table.toString()}\n`);
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAGA,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,iBAoHxD"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { loadChannelConfig, env } from "@ghostwriter/core";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
export async function validateCommand(channelName) {
|
|
4
|
+
console.log(chalk.blue(`\nValidating channel: ${channelName}\n`));
|
|
5
|
+
let hasErrors = false;
|
|
6
|
+
// 1. Validate config schema
|
|
7
|
+
try {
|
|
8
|
+
const config = await loadChannelConfig(channelName);
|
|
9
|
+
console.log(chalk.green(" [PASS] Config schema is valid"));
|
|
10
|
+
// 2. Check data sources
|
|
11
|
+
for (const source of config.dataSources) {
|
|
12
|
+
console.log(chalk.green(` [PASS] Data source configured: ${source.type}${source.type === "api" ? ` (${source.provider})` : ""}`));
|
|
13
|
+
}
|
|
14
|
+
// 3. Check publish targets have required env vars
|
|
15
|
+
for (const target of config.publishTargets) {
|
|
16
|
+
switch (target.platform) {
|
|
17
|
+
case "twitter":
|
|
18
|
+
if (env.twitterApiKey &&
|
|
19
|
+
env.twitterApiSecret &&
|
|
20
|
+
env.twitterAccessToken &&
|
|
21
|
+
env.twitterAccessSecret) {
|
|
22
|
+
console.log(chalk.green(" [PASS] Twitter credentials found"));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(chalk.red(" [FAIL] Twitter credentials incomplete"));
|
|
26
|
+
hasErrors = true;
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
case "podcast":
|
|
30
|
+
if (env.elevenLabsApiKey) {
|
|
31
|
+
console.log(chalk.green(" [PASS] ElevenLabs API key found"));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log(chalk.red(" [FAIL] ELEVENLABS_API_KEY missing"));
|
|
35
|
+
hasErrors = true;
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
case "wordpress":
|
|
39
|
+
if ((target.url || env.wordpressUrl) &&
|
|
40
|
+
(target.username || env.wordpressUsername) &&
|
|
41
|
+
(target.password || env.wordpressPassword)) {
|
|
42
|
+
console.log(chalk.green(" [PASS] WordPress credentials found"));
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log(chalk.red(" [FAIL] WordPress credentials missing — run: ghostwriter connect wordpress"));
|
|
46
|
+
hasErrors = true;
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 4. Check Anthropic API key
|
|
52
|
+
try {
|
|
53
|
+
env.anthropicApiKey;
|
|
54
|
+
console.log(chalk.green(" [PASS] Anthropic API key found"));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
console.log(chalk.red(" [FAIL] ANTHROPIC_API_KEY missing"));
|
|
58
|
+
hasErrors = true;
|
|
59
|
+
}
|
|
60
|
+
// 5. Check voice examples exist
|
|
61
|
+
if (config.voice.exampleContent.length > 0) {
|
|
62
|
+
console.log(chalk.green(` [PASS] ${config.voice.exampleContent.length} example content file(s) configured`));
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.log(chalk.yellow(" [WARN] No example content — style fingerprinting will be skipped"));
|
|
66
|
+
}
|
|
67
|
+
console.log();
|
|
68
|
+
if (hasErrors) {
|
|
69
|
+
console.log(chalk.red(" Validation failed. Fix the errors above before running."));
|
|
70
|
+
process.exitCode = 1;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log(chalk.green(" All checks passed!"));
|
|
74
|
+
console.log(`\n Run: ghostwriter run ${channelName} --dry-run`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
console.log(chalk.red(` [FAIL] Config error: ${err instanceof Error ? err.message : err}`));
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
}
|
|
81
|
+
console.log();
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=validate.js.map
|