seshat-scribe 0.9.2 → 3.0.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.
Files changed (52) hide show
  1. package/README.md +47 -58
  2. package/dist/commands/check-due.d.ts +15 -0
  3. package/dist/commands/check-due.d.ts.map +1 -0
  4. package/dist/commands/check-due.js +53 -0
  5. package/dist/commands/check-due.js.map +1 -0
  6. package/dist/commands/generate.d.ts +4 -1
  7. package/dist/commands/generate.d.ts.map +1 -1
  8. package/dist/commands/generate.js +120 -97
  9. package/dist/commands/generate.js.map +1 -1
  10. package/dist/commands/init.d.ts.map +1 -1
  11. package/dist/commands/init.js +73 -338
  12. package/dist/commands/init.js.map +1 -1
  13. package/dist/config.d.ts +21 -179
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/config.js +43 -112
  16. package/dist/config.js.map +1 -1
  17. package/dist/core/analyzer.d.ts +1 -1
  18. package/dist/core/analyzer.d.ts.map +1 -1
  19. package/dist/core/analyzer.js +2 -115
  20. package/dist/core/analyzer.js.map +1 -1
  21. package/dist/core/artist.d.ts +1 -2
  22. package/dist/core/artist.d.ts.map +1 -1
  23. package/dist/core/artist.js +2 -5
  24. package/dist/core/artist.js.map +1 -1
  25. package/dist/core/planner.d.ts +2 -2
  26. package/dist/core/sanity.d.ts +36 -1
  27. package/dist/core/sanity.d.ts.map +1 -1
  28. package/dist/core/sanity.js +78 -2
  29. package/dist/core/sanity.js.map +1 -1
  30. package/dist/core/scheduler.d.ts +45 -0
  31. package/dist/core/scheduler.d.ts.map +1 -0
  32. package/dist/core/scheduler.js +136 -0
  33. package/dist/core/scheduler.js.map +1 -0
  34. package/dist/index.js +26 -3
  35. package/dist/index.js.map +1 -1
  36. package/dist/types.d.ts +52 -0
  37. package/dist/types.d.ts.map +1 -0
  38. package/dist/types.js +5 -0
  39. package/dist/types.js.map +1 -0
  40. package/package.json +7 -8
  41. package/dist/core/writer.d.ts +0 -7
  42. package/dist/core/writer.d.ts.map +0 -1
  43. package/dist/core/writer.js +0 -126
  44. package/dist/core/writer.js.map +0 -1
  45. package/dist/lib/detection.d.ts +0 -13
  46. package/dist/lib/detection.d.ts.map +0 -1
  47. package/dist/lib/detection.js +0 -158
  48. package/dist/lib/detection.js.map +0 -1
  49. package/dist/lib/frontmatter.d.ts +0 -28
  50. package/dist/lib/frontmatter.d.ts.map +0 -1
  51. package/dist/lib/frontmatter.js +0 -114
  52. package/dist/lib/frontmatter.js.map +0 -1
@@ -1,126 +0,0 @@
1
- import { createGenAIClient } from '../lib/gemini.js';
2
- import { addUsage, fromGenerateContentResponse } from '../lib/usage.js';
3
- import { buildFrontmatter } from '../lib/frontmatter.js';
4
- const WRITE_MODEL = 'gemini-3-flash-preview';
5
- function pickOne(arr) {
6
- return arr[Math.floor(Math.random() * arr.length)];
7
- }
8
- const OPENING_STYLES = [
9
- { instruction: 'Start with 1–2 sentences on why this matters to the reader.' },
10
- { instruction: 'Open with a question that the post will answer.' },
11
- { instruction: 'Open with a bold or surprising claim, then back it up.' },
12
- { instruction: 'Open with a very short anecdote or moment (2–3 sentences) that leads into the topic.' },
13
- { instruction: 'Dive straight into the technical content; no preamble. Start with a concrete example or definition.' },
14
- { instruction: 'Start with an understated, almost casual observation that draws the reader in.' },
15
- { instruction: 'Start by contradicting a common belief or practice, then explain.' },
16
- { instruction: 'Start with a specific frustration or "this used to confuse me" and then resolve it.' },
17
- ];
18
- /**
19
- * Use Gemini to write a complete MDX blog post
20
- */
21
- export async function writeBlogPost(config, plan, postDate = new Date(), imagePath = 'PLACEHOLDER_IMAGE') {
22
- const ai = createGenAIClient();
23
- // Pick the first tag from the plan
24
- const primaryTag = plan.tags[0] || 'general';
25
- // Ensure frontmatter config exists (should be set by resolveConfig)
26
- if (!config.frontmatter) {
27
- throw new Error('Frontmatter configuration is missing. This should not happen.');
28
- }
29
- // Build frontmatter using the new system
30
- const frontmatter = buildFrontmatter(config.frontmatter, {
31
- title: plan.title,
32
- description: plan.description,
33
- date: postDate,
34
- tag: primaryTag,
35
- imagePath,
36
- });
37
- const opening = pickOne(OPENING_STYLES);
38
- // Build generation instructions
39
- let generationInstructions = '';
40
- if (config.generation) {
41
- if (config.generation.targetWordCount) {
42
- generationInstructions += `\n- Target length: approximately ${config.generation.targetWordCount} words`;
43
- }
44
- if (config.generation.includeCodeExamples) {
45
- generationInstructions += '\n- Include multiple practical code examples throughout the post';
46
- }
47
- if (config.generation.seoOptimized) {
48
- generationInstructions += '\n- Optimize for SEO: use keywords naturally, clear headings, scannable structure';
49
- }
50
- if (config.generation.customInstructions) {
51
- generationInstructions += `\n- Additional instructions: ${config.generation.customInstructions}`;
52
- }
53
- }
54
- const prompt = `Write a technical blog post in MDX format. Clear, valuable, focused on helping readers understand. Vary your voice — avoid sounding like a generic AI or a template.
55
-
56
- **Post Details:**
57
- - Title: ${plan.title}
58
- - Description: ${plan.description}
59
- - Tag: ${primaryTag}${generationInstructions}
60
-
61
- **Opening (follow this for the first paragraph):**
62
- ${opening.instruction}
63
- Do NOT start with "In this article we will...", "In today's post...", or similar. Each post should feel like it was written on a different day.
64
-
65
- **Writing Style:**
66
- - Prose that delivers value without fluff or filler
67
- - First-person when it fits ("I found", "I learned"); not every sentence
68
- - Vary sentence length and rhythm — short and long, not uniform
69
- - It's okay to be a bit idiosyncratic or opinionated
70
- - Use examples and code to clarify; show real code, not pseudo-code
71
- - Explain the "why" behind decisions; include edge cases or gotchas when relevant
72
- - Don't use perfect grammar, just write like a human.
73
- - Avoid obvious AI writing patterns like "—" or "...", which a human would never use.
74
-
75
- **Structure:**
76
- - Use clear headings, but don't follow a cookie-cutter pattern (e.g. not always Intro → Background → Solution → Conclusion with equal weight)
77
- - Let the topic dictate structure: some posts need a long setup, others can jump in
78
- - Include practical code examples where helpful
79
-
80
- **Technical Quality:**
81
- - Be accurate and specific
82
- - Avoid formulaic transitions ("Furthermore", "Moreover", "It's worth noting that" as crutches)
83
-
84
- **Tone: ${config.tone}**
85
-
86
- **Format Requirements:**
87
- Use EXACTLY this frontmatter:
88
-
89
- ${frontmatter}
90
-
91
- After the frontmatter, start your content immediately. No import statements.
92
-
93
- **MDX Syntax Rules (CRITICAL):**
94
- MDX content requires proper escaping of special characters that could be interpreted as HTML/JSX:
95
-
96
- 1. **Less-than signs (\`<\`)**: ALWAYS escape \`<\` when followed by a number or letter
97
- - ✅ CORRECT: \`{"<"}5ms\`, \`{"<"}10%\`, \`less than {"<"} 100\`
98
- - ✅ CORRECT: \`\\<5ms\` (alternative escape method)
99
- - ❌ WRONG: \`<5ms\`, \`<10%\`, \`less than <100\`
100
-
101
- 2. **Greater-than signs (\`>\`)**: Escape when it could be ambiguous
102
- - ✅ CORRECT: \`{">"}5ms\`, \`\\>5ms\`
103
-
104
- 3. **Common patterns that need escaping**:
105
- - Comparisons: \`{"<"}5ms\`, \`{">"}100kb\`, \`x {"<"} y\`
106
- - Arrows: \`A {"=>"} B\`
107
- - Math: \`a {">="} b\`, \`x {"<="} y\`
108
-
109
- Remember: In MDX, any \`<\` followed by a letter or number will be parsed as the start of a JSX tag. Always use \`{"<"}\` or \`\\<\` to escape it.
110
-
111
- Write a focused, valuable post that helps developers understand ${plan.title}.`;
112
- const response = await ai.models.generateContent({
113
- model: WRITE_MODEL,
114
- contents: prompt,
115
- });
116
- const u = fromGenerateContentResponse(WRITE_MODEL, response.usageMetadata);
117
- if (u)
118
- addUsage(u);
119
- let content = response.text?.trim() || '';
120
- // Clean up: remove wrapping code blocks if Gemini added them
121
- if (content.startsWith('```')) {
122
- content = content.replace(/^```(?:mdx|markdown|md)?\n/, '').replace(/\n```$/, '');
123
- }
124
- return content;
125
- }
126
- //# sourceMappingURL=writer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"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"}
@@ -1,13 +0,0 @@
1
- export interface DetectedBlogStructure {
2
- framework?: 'remix' | 'next' | 'astro';
3
- contentDir?: string;
4
- assetsDir?: string;
5
- publicAssetPath?: string;
6
- hasExistingContent: boolean;
7
- contentFileCount: number;
8
- }
9
- /**
10
- * Auto-detect blog structure in the current directory
11
- */
12
- export declare function detectBlogStructure(cwd?: string): Promise<DetectedBlogStructure>;
13
- //# sourceMappingURL=detection.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"detection.d.ts","sourceRoot":"","sources":["../../src/lib/detection.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AA0HD;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA4CrG"}
@@ -1,158 +0,0 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
- /**
4
- * Common content directory patterns to check
5
- */
6
- const CONTENT_DIR_PATTERNS = [
7
- 'app/routes/blog', // Remix
8
- 'content/posts',
9
- 'content/blog',
10
- 'posts',
11
- 'blog',
12
- 'src/content/blog', // Astro
13
- 'src/content/posts',
14
- 'app/blog', // Next.js app router
15
- 'pages/blog', // Next.js pages router
16
- 'content',
17
- ];
18
- /**
19
- * Common asset directory patterns to check
20
- */
21
- const ASSET_DIR_PATTERNS = [
22
- 'public/images',
23
- 'public/assets',
24
- 'public/img',
25
- 'public/images/generated',
26
- 'public/assets/images',
27
- 'assets/images',
28
- ];
29
- /**
30
- * Detect framework from package.json dependencies
31
- */
32
- async function detectFramework(cwd) {
33
- try {
34
- const packageJsonPath = path.join(cwd, 'package.json');
35
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
36
- const allDeps = {
37
- ...packageJson.dependencies,
38
- ...packageJson.devDependencies,
39
- };
40
- // Check for framework-specific dependencies
41
- if (allDeps['@remix-run/react'] || allDeps['@remix-run/node']) {
42
- return 'remix';
43
- }
44
- if (allDeps['next']) {
45
- return 'next';
46
- }
47
- if (allDeps['astro']) {
48
- return 'astro';
49
- }
50
- return undefined;
51
- }
52
- catch {
53
- return undefined;
54
- }
55
- }
56
- /**
57
- * Count MDX/MD files in a directory recursively
58
- */
59
- async function countContentFiles(dirPath) {
60
- try {
61
- let count = 0;
62
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
63
- for (const entry of entries) {
64
- const fullPath = path.join(dirPath, entry.name);
65
- if (entry.isDirectory()) {
66
- // Skip node_modules and hidden directories
67
- if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
68
- count += await countContentFiles(fullPath);
69
- }
70
- }
71
- else if (entry.isFile()) {
72
- if (entry.name.endsWith('.mdx') || entry.name.endsWith('.md')) {
73
- count++;
74
- }
75
- }
76
- }
77
- return count;
78
- }
79
- catch {
80
- return 0;
81
- }
82
- }
83
- /**
84
- * Find the first existing directory from a list of patterns
85
- */
86
- async function findExistingDirectory(cwd, patterns) {
87
- for (const pattern of patterns) {
88
- const fullPath = path.join(cwd, pattern);
89
- try {
90
- const stat = await fs.stat(fullPath);
91
- if (stat.isDirectory()) {
92
- const fileCount = await countContentFiles(fullPath);
93
- if (fileCount > 0) {
94
- return pattern;
95
- }
96
- }
97
- }
98
- catch {
99
- // Directory doesn't exist, continue
100
- continue;
101
- }
102
- }
103
- return undefined;
104
- }
105
- /**
106
- * Detect public asset path from assets directory
107
- */
108
- function derivePublicAssetPath(assetsDir) {
109
- // Extract the public-facing path (everything after 'public/')
110
- if (assetsDir.startsWith('public/')) {
111
- return '/' + assetsDir.substring('public/'.length);
112
- }
113
- // Default fallback
114
- return '/images/generated';
115
- }
116
- /**
117
- * Auto-detect blog structure in the current directory
118
- */
119
- export async function detectBlogStructure(cwd = process.cwd()) {
120
- const detected = {
121
- hasExistingContent: false,
122
- contentFileCount: 0,
123
- };
124
- // Detect framework
125
- detected.framework = await detectFramework(cwd);
126
- // Detect content directory
127
- detected.contentDir = await findExistingDirectory(cwd, CONTENT_DIR_PATTERNS);
128
- if (detected.contentDir) {
129
- // Count content files
130
- const contentPath = path.join(cwd, detected.contentDir);
131
- detected.contentFileCount = await countContentFiles(contentPath);
132
- detected.hasExistingContent = detected.contentFileCount > 0;
133
- }
134
- // Detect assets directory
135
- detected.assetsDir = await findExistingDirectory(cwd, ASSET_DIR_PATTERNS);
136
- // If no existing assets dir found, try to find any public/images or public/assets dir
137
- if (!detected.assetsDir) {
138
- for (const pattern of ASSET_DIR_PATTERNS) {
139
- const fullPath = path.join(cwd, pattern);
140
- try {
141
- const stat = await fs.stat(fullPath);
142
- if (stat.isDirectory()) {
143
- detected.assetsDir = pattern;
144
- break;
145
- }
146
- }
147
- catch {
148
- continue;
149
- }
150
- }
151
- }
152
- // Derive public asset path
153
- if (detected.assetsDir) {
154
- detected.publicAssetPath = derivePublicAssetPath(detected.assetsDir);
155
- }
156
- return detected;
157
- }
158
- //# sourceMappingURL=detection.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/lib/detection.ts"],"names":[],"mappings":"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"}
@@ -1,28 +0,0 @@
1
- import type { FrontmatterConfig } from '../config.js';
2
- /**
3
- * Format a date according to the specified format
4
- */
5
- export declare function formatDate(date: Date, format?: string): string;
6
- /**
7
- * Format a multiline string for YAML (using >- syntax)
8
- */
9
- export declare function formatMultilineYAML(text: string): string;
10
- /**
11
- * Build frontmatter string from configuration and values
12
- */
13
- export declare function buildFrontmatter(config: FrontmatterConfig, values: {
14
- title: string;
15
- description: string;
16
- date: Date;
17
- tag: string;
18
- imagePath: string | null;
19
- }): string;
20
- /**
21
- * Generate file name from template
22
- */
23
- export declare function buildFileName(template: string, slug: string, date: Date, extension: string): string;
24
- /**
25
- * Build nested directory path based on date
26
- */
27
- export declare function buildNestedPath(date: Date, baseDir: string): string;
28
- //# sourceMappingURL=frontmatter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CA2B9D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE;IACN,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACA,MAAM,CA2CR;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM,GAChB,MAAM,CAyBR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKnE"}
@@ -1,114 +0,0 @@
1
- /**
2
- * Format a date according to the specified format
3
- */
4
- export function formatDate(date, format) {
5
- if (!format || format === 'iso') {
6
- return date.toISOString();
7
- }
8
- if (format === 'date-only') {
9
- return date.toISOString().split('T')[0];
10
- }
11
- // Custom format support (basic implementation)
12
- // Supports: YYYY, MM, DD, HH, mm, ss
13
- let formatted = format;
14
- const year = date.getFullYear();
15
- const month = String(date.getMonth() + 1).padStart(2, '0');
16
- const day = String(date.getDate()).padStart(2, '0');
17
- const hours = String(date.getHours()).padStart(2, '0');
18
- const minutes = String(date.getMinutes()).padStart(2, '0');
19
- const seconds = String(date.getSeconds()).padStart(2, '0');
20
- formatted = formatted.replace('YYYY', String(year));
21
- formatted = formatted.replace('MM', month);
22
- formatted = formatted.replace('DD', day);
23
- formatted = formatted.replace('HH', hours);
24
- formatted = formatted.replace('mm', minutes);
25
- formatted = formatted.replace('ss', seconds);
26
- return formatted;
27
- }
28
- /**
29
- * Format a multiline string for YAML (using >- syntax)
30
- */
31
- export function formatMultilineYAML(text) {
32
- const lines = text.split('\n').map(line => line.trim()).filter(Boolean);
33
- if (lines.length === 0)
34
- return '""';
35
- if (lines.length === 1)
36
- return `"${lines[0]}"`;
37
- return `>-\n ${lines.join('\n ')}`;
38
- }
39
- /**
40
- * Build frontmatter string from configuration and values
41
- */
42
- export function buildFrontmatter(config, values) {
43
- const lines = ['---'];
44
- // Title (always included)
45
- lines.push(`title: "${values.title}"`);
46
- // Description (multiline format)
47
- lines.push(`description: ${formatMultilineYAML(values.description)}`);
48
- // Date (with custom field name and format)
49
- const dateField = config.dateField || 'date';
50
- const formattedDate = formatDate(values.date, config.dateFormat);
51
- lines.push(`${dateField}: ${formattedDate}`);
52
- // Taxonomy field (tag/category)
53
- const taxonomyField = config.taxonomyField || 'tag';
54
- lines.push(`${taxonomyField}: ${values.tag}`);
55
- // Image field (with custom field name) - only if image exists
56
- if (values.imagePath) {
57
- const imageField = config.imageField || 'image';
58
- lines.push(`${imageField}: "${values.imagePath}"`);
59
- }
60
- // Additional custom fields
61
- if (config.additionalFields) {
62
- for (const [key, value] of Object.entries(config.additionalFields)) {
63
- if (typeof value === 'string') {
64
- lines.push(`${key}: "${value}"`);
65
- }
66
- else if (typeof value === 'boolean' || typeof value === 'number') {
67
- lines.push(`${key}: ${value}`);
68
- }
69
- else if (Array.isArray(value)) {
70
- lines.push(`${key}: [${value.map(v => `"${v}"`).join(', ')}]`);
71
- }
72
- else if (value && typeof value === 'object') {
73
- // Simple object serialization
74
- lines.push(`${key}: ${JSON.stringify(value)}`);
75
- }
76
- }
77
- }
78
- lines.push('---');
79
- return lines.join('\n');
80
- }
81
- /**
82
- * Generate file name from template
83
- */
84
- export function buildFileName(template, slug, date, extension) {
85
- let fileName = template;
86
- // Replace template variables
87
- fileName = fileName.replace('{{slug}}', slug);
88
- // Date components
89
- const year = date.getFullYear();
90
- const month = String(date.getMonth() + 1).padStart(2, '0');
91
- const day = String(date.getDate()).padStart(2, '0');
92
- fileName = fileName.replace('{{year}}', String(year));
93
- fileName = fileName.replace('{{month}}', month);
94
- fileName = fileName.replace('{{day}}', day);
95
- fileName = fileName.replace('{{date}}', `${year}-${month}-${day}`);
96
- // Handle {{ext}} placeholder or append extension
97
- if (fileName.includes('{{ext}}')) {
98
- fileName = fileName.replace('{{ext}}', extension);
99
- }
100
- else {
101
- // If no {{ext}} in template, append .extension
102
- fileName = `${fileName}.${extension}`;
103
- }
104
- return fileName;
105
- }
106
- /**
107
- * Build nested directory path based on date
108
- */
109
- export function buildNestedPath(date, baseDir) {
110
- const year = date.getFullYear();
111
- const month = String(date.getMonth() + 1).padStart(2, '0');
112
- return `${baseDir}/${year}/${month}`;
113
- }
114
- //# sourceMappingURL=frontmatter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"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"}