seshat-scribe 0.0.1 → 0.0.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4H3E"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuI3E"}
@@ -6,6 +6,7 @@ import { planBlogPost } from '../core/planner.js';
6
6
  import { writeBlogPost } from '../core/writer.js';
7
7
  import { generateImage } from '../core/artist.js';
8
8
  import { gold, cyan, error, info, scrollWritten } from '../lib/output.js';
9
+ import { resetUsage, formatUsageSummary } from '../lib/usage.js';
9
10
  /**
10
11
  * Main command: Generate a new blog post with image
11
12
  */
@@ -25,6 +26,7 @@ export async function generate(options = {}) {
25
26
  console.log('');
26
27
  console.log(gold.bold('⟡ Seshat awakens...'));
27
28
  console.log('');
29
+ resetUsage();
28
30
  // Step 1: Analyze existing content
29
31
  const analyzeSpinner = ora({
30
32
  text: cyan('Reading the archives...'),
@@ -120,6 +122,14 @@ export async function generate(options = {}) {
120
122
  error(err instanceof Error ? err.message : 'Unknown error');
121
123
  process.exit(1);
122
124
  }
125
+ // Usage summary
126
+ const usageLines = formatUsageSummary();
127
+ if (usageLines.length > 0) {
128
+ console.log('');
129
+ for (const line of usageLines) {
130
+ info(line);
131
+ }
132
+ }
123
133
  // Victory!
124
134
  scrollWritten();
125
135
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"artist.d.ts","sourceRoot":"","sources":["../../src/core/artist.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CA+DjB"}
1
+ {"version":3,"file":"artist.d.ts","sourceRoot":"","sources":["../../src/core/artist.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAiBjD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CA8DjB"}
@@ -1,6 +1,19 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
  import { createGenAIClient, SafetyFilterLevel, PersonGeneration } from '../lib/gemini.js';
4
+ import { addUsage } from '../lib/usage.js';
5
+ const IMAGE_MODEL = 'imagen-4.0-generate-001';
6
+ function pickOne(arr) {
7
+ return arr[Math.floor(Math.random() * arr.length)];
8
+ }
9
+ const STYLE_OVERLAYS = [
10
+ 'Style: Digital drawing, hand-drawn aesthetic, slightly imperfect and organic. Warm, approachable colors. Indie illustration or personal blog. Avoid: corporate stock, 3D renders, overly polished.',
11
+ 'Style: Muted, film-like colors; slight grain. Feels like a 70s book cover or vintage poster. Avoid: bright flat colors, slick digital look.',
12
+ 'Style: Bold shapes, limited palette (2–3 colors), graphic and poster-like. High contrast. Avoid: detailed realism, busy compositions.',
13
+ 'Style: Soft, painterly; visible brush strokes. Not photorealistic. Avoid: sharp vectors, corporate clip art.',
14
+ 'Style: Minimal: lots of negative space, one strong focal point, restrained colors. Avoid: busy, maximalist.',
15
+ 'Style: Slightly surreal or unexpected: one odd angle, scale, or juxtaposition. Still readable. Avoid: generic stock imagery.',
16
+ ];
4
17
  /**
5
18
  * Generate an image using Gemini's Imagen 4.0 model
6
19
  */
@@ -11,17 +24,14 @@ export async function generateImage(config, imagePrompt, slug) {
11
24
  await fs.mkdir(assetsPath, { recursive: true });
12
25
  try {
13
26
  const ai = createGenAIClient();
14
- // Enhance the prompt with consistent style instructions
27
+ // Enhance with a randomly chosen style overlay so images vary across runs
28
+ const overlay = pickOne(STYLE_OVERLAYS);
15
29
  const enhancedPrompt = `${imagePrompt}
16
30
 
17
- Style: Digital drawing style, hand-drawn aesthetic, slightly imperfect and organic.
18
- Should look human-made, not overly polished or synthetic.
19
- Warm, approachable colors with a personal touch.
20
- Think indie illustration or personal blog header art.
21
- Avoid: Corporate stock photo look, 3D renders, photorealistic AI art, overly perfect compositions.`;
31
+ ${overlay}`;
22
32
  // Generate the image using the correct API with timeout
23
33
  const imagePromise = ai.models.generateImages({
24
- model: 'imagen-4.0-generate-001',
34
+ model: IMAGE_MODEL,
25
35
  prompt: enhancedPrompt,
26
36
  config: {
27
37
  numberOfImages: 1,
@@ -43,6 +53,7 @@ Avoid: Corporate stock photo look, 3D renders, photorealistic AI art, overly per
43
53
  // Convert base64 to buffer and save
44
54
  const imageBuffer = Buffer.from(generatedImage.image.imageBytes, 'base64');
45
55
  await fs.writeFile(imagePath, imageBuffer);
56
+ addUsage({ type: 'generateImages', model: IMAGE_MODEL, imageCount: 1 });
46
57
  return imagePath;
47
58
  }
48
59
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"artist.js","sourceRoot":"","sources":["../../src/core/artist.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"artist.js","sourceRoot":"","sources":["../../src/core/artist.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/core/planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;EAMzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;GAEG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,QAAQ,CAAC,CAmDnB"}
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/core/planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA+BjD;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;EAMzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;GAEG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,QAAQ,CAAC,CA+DnB"}
@@ -1,5 +1,31 @@
1
1
  import { z } from 'zod';
2
2
  import { createGenAIClient } from '../lib/gemini.js';
3
+ import { addUsage, fromGenerateContentResponse } from '../lib/usage.js';
4
+ const PLAN_MODEL = 'gemini-3-flash-preview';
5
+ function pickOne(arr) {
6
+ return arr[Math.floor(Math.random() * arr.length)];
7
+ }
8
+ const TITLE_ARCHETYPES = [
9
+ { instruction: 'Phrase the title as a question.', example: 'Why Does X Still Break in Production?' },
10
+ { instruction: 'Use a how-to format.', example: 'How to X Without Y' },
11
+ { instruction: 'Use a short, declarative statement.', example: 'X Is Underrated' },
12
+ { instruction: 'Use a provocative or contrarian angle.', example: 'Stop Doing X (Do Y Instead)' },
13
+ { instruction: 'Use an understated, curiosity-driven title.', example: 'A Small Thing About X' },
14
+ { instruction: 'Use a list or collection format.', example: '3 Things I Wish I Knew About X' },
15
+ { instruction: 'Use a title that suggests a story or journey.', example: 'How I Finally Understood X' },
16
+ { instruction: 'Use a single punchy phrase or a few words.', example: 'Defaults Matter' },
17
+ { instruction: 'Use a "what nobody tells you" or insider angle.', example: 'What Nobody Tells You About X' },
18
+ ];
19
+ const IMAGE_STYLE_DIRECTIONS = [
20
+ { direction: 'Minimalist line art or iconography; lots of negative space.', example: 'Single continuous line forming a symbol, one accent color on white' },
21
+ { direction: 'Moody, atmospheric; shallow depth of field or soft focus; like a film still.', example: 'Blurred background, one sharp object, muted palette' },
22
+ { direction: 'Bold graphic shapes, limited palette (2–3 colors), poster-like.', example: 'Flat geometric shapes, high contrast, no gradients' },
23
+ { direction: 'Sketchy, hand-drawn; pencil or ink; deliberately imperfect.', example: 'Quick sketch or doodle, visible strokes, unpolished' },
24
+ { direction: 'Collage or mixed media; layered textures, paper, or found elements.', example: 'Cut-paper, tape, or layered scraps; tactile' },
25
+ { direction: 'Abstract: gradients, blobs, or organic shapes; no literal objects.', example: 'Soft blobs or waves, dreamy, no recognizable objects' },
26
+ { direction: 'Flat illustration with one strong accent color on a neutral base.', example: 'Simple shapes, one pop of color, rest muted' },
27
+ { direction: 'Retro or vintage: 70s book cover, old textbook diagram, or poster.', example: 'Grainy, sepia or faded colors, old typography feel' },
28
+ ];
3
29
  /**
4
30
  * Schema for the blog post plan returned by Gemini
5
31
  */
@@ -17,6 +43,8 @@ export async function planBlogPost(config, context) {
17
43
  const ai = createGenAIClient();
18
44
  const existingTitles = context.posts.map((p) => p.title).join('\n - ');
19
45
  const existingTopics = context.recentTopics.join(', ');
46
+ const titleArchetype = pickOne(TITLE_ARCHETYPES);
47
+ const imageStyle = pickOne(IMAGE_STYLE_DIRECTIONS);
20
48
  const prompt = `Plan a new blog post for a developer blog.
21
49
 
22
50
  **Existing Content:**
@@ -31,24 +59,33 @@ export async function planBlogPost(config, context) {
31
59
  2. Make it specific and valuable to developers
32
60
  3. Avoid duplicating existing posts
33
61
  4. Vary from recent posts (if last posts were about X, pick something different)
34
- 5. Create a clear, specific title (not generic)
35
62
 
36
- Vary the title from previous posts - don't just repeat the same pattern.
63
+ **Title (important follow this format):**
64
+ ${titleArchetype.instruction} Example: "${titleArchetype.example}"
65
+ - If the existing titles above mostly use one format (e.g. how-to or questions), pick a *different* format for this one.
66
+ - Avoid generic or templated titles. Be specific to the topic.
67
+
68
+ **Image:**
69
+ Describe the header image to match this style: ${imageStyle.direction}
70
+ Example: "${imageStyle.example}" — adapt to the post's topic. Do NOT use a generic "blog header" or "minimalist illustration" phrase; describe a concrete scene, metaphor, or mood.
37
71
 
38
72
  **Output JSON:**
39
73
  {
40
- "title": "Specific, clear title",
74
+ "title": "<your title in the chosen format>",
41
75
  "slug": "url-friendly-slug",
42
- "description": "One sentence explaining what the post covers",
76
+ "description": "One sentence: vary the phrasing (e.g. benefit, question, or punchy statement — not always 'This post covers X').",
43
77
  "tags": ["primary-tag", "related-tag", "context-tag"],
44
- "imagePrompt": "Describe a clean, modern blog header image. Style: minimalist illustration or abstract design. Colors, composition, mood."
78
+ "imagePrompt": "<your image description matching the style above>"
45
79
  }
46
80
 
47
81
  Return only valid JSON.`;
48
82
  const response = await ai.models.generateContent({
49
- model: 'gemini-3-flash-preview',
83
+ model: PLAN_MODEL,
50
84
  contents: prompt,
51
85
  });
86
+ const u = fromGenerateContentResponse(PLAN_MODEL, response.usageMetadata);
87
+ if (u)
88
+ addUsage(u);
52
89
  const text = response.text?.trim() || '';
53
90
  // Clean up the response (remove markdown code blocks if present)
54
91
  let jsonText = text;
@@ -1 +1 @@
1
- {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/core/planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrD;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC;AAIH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAoB,EACpB,OAA0B;IAE1B,MAAM,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAE/B,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxE,MAAM,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEvD,MAAM,MAAM,GAAG;;;iBAGA,OAAO,CAAC,UAAU;YACvB,cAAc,IAAI,UAAU;YAC5B,cAAc,IAAI,UAAU;;mBAErB,MAAM,CAAC,KAAK;;;0BAGL,MAAM,CAAC,KAAK;;;;;;;;;;;;;;;;;wBAiBd,CAAC;IAEvB,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC;QAC/C,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAEzC,iEAAiE;IACjE,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,8BAA8B;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClC,OAAO,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/core/planner.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,MAAM,CAAC,CAgEjB"}
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAmBjD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,MAAM,CAAC,CAmEjB"}
@@ -1,4 +1,19 @@
1
1
  import { createGenAIClient } from '../lib/gemini.js';
2
+ import { addUsage, fromGenerateContentResponse } from '../lib/usage.js';
3
+ const WRITE_MODEL = 'gemini-3-flash-preview';
4
+ function pickOne(arr) {
5
+ return arr[Math.floor(Math.random() * arr.length)];
6
+ }
7
+ const OPENING_STYLES = [
8
+ { instruction: 'Start with 1–2 sentences on why this matters to the reader.' },
9
+ { instruction: 'Open with a question that the post will answer.' },
10
+ { instruction: 'Open with a bold or surprising claim, then back it up.' },
11
+ { instruction: 'Open with a very short anecdote or moment (2–3 sentences) that leads into the topic.' },
12
+ { instruction: 'Dive straight into the technical content; no preamble. Start with a concrete example or definition.' },
13
+ { instruction: 'Start with an understated, almost casual observation that draws the reader in.' },
14
+ { instruction: 'Start by contradicting a common belief or practice, then explain.' },
15
+ { instruction: 'Start with a specific frustration or "this used to confuse me" and then resolve it.' },
16
+ ];
2
17
  /**
3
18
  * Use Gemini to write a complete MDX blog post
4
19
  */
@@ -9,34 +24,34 @@ export async function writeBlogPost(config, plan) {
9
24
  // Pick the first tag from the plan
10
25
  const primaryTag = plan.tags[0] || 'general';
11
26
  const frontmatterFormat = getFrontmatterFormat(config.framework, plan.title, plan.description, currentDate, primaryTag);
12
- const prompt = `Write a technical blog post in MDX format. Write like Josh W Comeau or Kent C Dodds - clear, valuable, and focused on helping readers understand.
27
+ const opening = pickOne(OPENING_STYLES);
28
+ 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.
13
29
 
14
30
  **Post Details:**
15
31
  - Title: ${plan.title}
16
32
  - Description: ${plan.description}
17
33
  - Tag: ${primaryTag}
18
34
 
35
+ **Opening (follow this for the first paragraph):**
36
+ ${opening.instruction}
37
+ 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.
38
+
19
39
  **Writing Style:**
20
- - Clean, straightforward prose focused on delivering value
21
- - Explain concepts clearly without over-explaining
22
- - Use first-person when sharing experiences ("I found", "I learned")
23
- - No fluff, filler, or unnecessary introductions
24
- - Get to the point quickly
25
- - Use examples and code to clarify concepts
26
- - Write like you're helping a colleague understand something
40
+ - Prose that delivers value without fluff or filler
41
+ - First-person when it fits ("I found", "I learned"); not every sentence
42
+ - Vary sentence length and rhythm short and long, not uniform
43
+ - It's okay to be a bit idiosyncratic or opinionated
44
+ - Use examples and code to clarify; show real code, not pseudo-code
45
+ - Explain the "why" behind decisions; include edge cases or gotchas when relevant
27
46
 
28
47
  **Structure:**
29
- - Start with why this matters (1-2 sentences)
30
- - Then dive into the actual content
31
- - Use clear headings to organize ideas
48
+ - Use clear headings, but don't follow a cookie-cutter pattern (e.g. not always Intro → Background → Solution → Conclusion with equal weight)
49
+ - Let the topic dictate structure: some posts need a long setup, others can jump in
32
50
  - Include practical code examples where helpful
33
- - Vary your structure - don't follow a template
34
51
 
35
52
  **Technical Quality:**
36
53
  - Be accurate and specific
37
- - Show real code, not pseudo-code
38
- - Explain the "why" behind decisions
39
- - Include edge cases or gotchas when relevant
54
+ - Avoid formulaic transitions ("Furthermore", "Moreover", "It's worth noting that" as crutches)
40
55
 
41
56
  **Tone: ${config.tone}**
42
57
 
@@ -49,9 +64,12 @@ After the frontmatter, start your content immediately. No import statements.
49
64
 
50
65
  Write a focused, valuable post that helps developers understand ${plan.title}.`;
51
66
  const response = await ai.models.generateContent({
52
- model: 'gemini-3-flash-preview',
67
+ model: WRITE_MODEL,
53
68
  contents: prompt,
54
69
  });
70
+ const u = fromGenerateContentResponse(WRITE_MODEL, response.usageMetadata);
71
+ if (u)
72
+ addUsage(u);
55
73
  let content = response.text?.trim() || '';
56
74
  // Clean up: remove wrapping code blocks if Gemini added them
57
75
  if (content.startsWith('```')) {
@@ -1 +1 @@
1
- {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAoB,EACpB,IAAc;IAEd,MAAM,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAE/B,iCAAiC;IACjC,MAAM,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE7C,mCAAmC;IACnC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAE7C,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;IAExH,MAAM,MAAM,GAAG;;;WAGN,IAAI,CAAC,KAAK;iBACJ,IAAI,CAAC,WAAW;SACxB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;UAwBT,MAAM,CAAC,IAAI;;;;;EAKnB,iBAAiB;;;;kEAI+C,IAAI,CAAC,KAAK,GAAG,CAAC;IAE9E,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC;QAC/C,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IAEH,IAAI,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAE1C,6DAA6D;IAC7D,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAC3B,SAAoC,EACpC,KAAa,EACb,WAAmB,EACnB,IAAY,EACZ,GAAW;IAEX,6CAA6C;IAC7C,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnF,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC;QACxC,CAAC,CAAC,SAAS,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;QACnC,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC;IAE3B,MAAM,OAAO,GAA8C;QACzD,KAAK,EAAE;UACD,KAAK;eACA,aAAa;QACpB,IAAI;;OAEL,GAAG;;IAEN;QACA,IAAI,EAAE;UACA,KAAK;eACA,aAAa;QACpB,IAAI;;OAEL,GAAG;;IAEN;QACA,KAAK,EAAE;UACD,KAAK;eACA,aAAa;WACjB,IAAI;;OAER,GAAG;;IAEN;KACD,CAAC;IAEF,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Gemini/Imagen usage and cost tracking
3
+ *
4
+ * Prices from https://ai.google.dev/pricing (check for updates).
5
+ * Token rates are USD per 1M tokens; image rate is USD per image.
6
+ */
7
+ export type GenerateContentUsage = {
8
+ type: 'generateContent';
9
+ model: string;
10
+ promptTokenCount: number;
11
+ candidatesTokenCount: number;
12
+ };
13
+ export type GenerateImagesUsage = {
14
+ type: 'generateImages';
15
+ model: string;
16
+ imageCount: number;
17
+ };
18
+ export type UsageRecord = GenerateContentUsage | GenerateImagesUsage;
19
+ export declare function resetUsage(): void;
20
+ export declare function addUsage(record: UsageRecord): void;
21
+ export declare function getUsage(): readonly UsageRecord[];
22
+ export declare function getTotalCost(): number;
23
+ export declare function formatUsageSummary(): string[];
24
+ /**
25
+ * Extract a UsageRecord from a generateContent response.usageMetadata.
26
+ * Returns undefined if usageMetadata or token counts are missing.
27
+ */
28
+ export declare function fromGenerateContentResponse(model: string, usageMetadata?: {
29
+ promptTokenCount?: number;
30
+ candidatesTokenCount?: number;
31
+ } | null): GenerateContentUsage | undefined;
32
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/lib/usage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,oBAAoB,GAAG,mBAAmB,CAAC;AAuCrE,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAElD;AAED,wBAAgB,QAAQ,IAAI,SAAS,WAAW,EAAE,CAEjD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CA0B7C;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAClF,oBAAoB,GAAG,SAAS,CAMlC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Gemini/Imagen usage and cost tracking
3
+ *
4
+ * Prices from https://ai.google.dev/pricing (check for updates).
5
+ * Token rates are USD per 1M tokens; image rate is USD per image.
6
+ */
7
+ // USD per 1M tokens (input, output) for text models; USD per image for Imagen
8
+ const PRICING = {
9
+ 'gemini-3-flash-preview': { inputPer1M: 0.5, outputPer1M: 3.0 },
10
+ 'gemini-3-pro-preview': { inputPer1M: 2.0, outputPer1M: 12.0 },
11
+ 'gemini-2.0-flash': { inputPer1M: 0.1, outputPer1M: 0.4 },
12
+ 'imagen-4.0-generate-001': { perImage: 0.04 },
13
+ };
14
+ function getPricing(model) {
15
+ return PRICING[model];
16
+ }
17
+ function estimateCost(record) {
18
+ const p = getPricing(record.model);
19
+ if (!p)
20
+ return 0;
21
+ if (record.type === 'generateContent') {
22
+ if ('inputPer1M' in p && 'outputPer1M' in p) {
23
+ const input = (record.promptTokenCount / 1_000_000) * p.inputPer1M;
24
+ const output = (record.candidatesTokenCount / 1_000_000) * p.outputPer1M;
25
+ return input + output;
26
+ }
27
+ }
28
+ if (record.type === 'generateImages' && 'perImage' in p) {
29
+ return record.imageCount * p.perImage;
30
+ }
31
+ return 0;
32
+ }
33
+ const store = [];
34
+ export function resetUsage() {
35
+ store.length = 0;
36
+ }
37
+ export function addUsage(record) {
38
+ store.push(record);
39
+ }
40
+ export function getUsage() {
41
+ return store;
42
+ }
43
+ export function getTotalCost() {
44
+ return store.reduce((sum, r) => sum + estimateCost(r), 0);
45
+ }
46
+ export function formatUsageSummary() {
47
+ const lines = [];
48
+ let total = 0;
49
+ for (const r of store) {
50
+ const cost = estimateCost(r);
51
+ total += cost;
52
+ if (r.type === 'generateContent') {
53
+ const p = getPricing(r.model);
54
+ const name = p ? '' : ' (unknown pricing)';
55
+ lines.push(` ${r.model}: ${r.promptTokenCount} in / ${r.candidatesTokenCount} out → $${cost.toFixed(4)}${name}`);
56
+ }
57
+ else {
58
+ lines.push(` ${r.model}: ${r.imageCount} image(s) → $${cost.toFixed(4)}`);
59
+ }
60
+ }
61
+ if (store.length > 0) {
62
+ lines.unshift('API usage:');
63
+ lines.push(` Total (est.): $${total.toFixed(4)}`);
64
+ }
65
+ return lines;
66
+ }
67
+ /**
68
+ * Extract a UsageRecord from a generateContent response.usageMetadata.
69
+ * Returns undefined if usageMetadata or token counts are missing.
70
+ */
71
+ export function fromGenerateContentResponse(model, usageMetadata) {
72
+ if (!usageMetadata)
73
+ return undefined;
74
+ const prompt = usageMetadata.promptTokenCount ?? 0;
75
+ const candidates = usageMetadata.candidatesTokenCount ?? 0;
76
+ if (prompt === 0 && candidates === 0)
77
+ return undefined;
78
+ return { type: 'generateContent', model, promptTokenCount: prompt, candidatesTokenCount: candidates };
79
+ }
80
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/lib/usage.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seshat-scribe",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "The Autonomous Scribe for Static Blogs - AI-powered content generation using Google Gemini",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,7 +11,11 @@
11
11
  "build": "tsc",
12
12
  "dev": "tsx src/index.ts",
13
13
  "prepare": "npm run build",
14
- "test": "echo \"No tests yet\" && exit 0"
14
+ "test": "echo \"No tests yet\" && exit 0",
15
+ "release:dry": "npm run build && npm publish --dry-run",
16
+ "release:patch": "npm test && npm version patch -m 'Release v%s' && npm publish && git push && git push --tags",
17
+ "release:minor": "npm test && npm version minor -m 'Release v%s' && npm publish && git push && git push --tags",
18
+ "release:major": "npm test && npm version major -m 'Release v%s' && npm publish && git push && git push --tags"
15
19
  },
16
20
  "keywords": [
17
21
  "blog",