gitcast 1.0.22__tar.gz → 1.0.24__tar.gz
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.
- {gitcast-1.0.22 → gitcast-1.0.24}/MANIFEST.in +2 -0
- {gitcast-1.0.22/gitcast.egg-info → gitcast-1.0.24}/PKG-INFO +1 -1
- {gitcast-1.0.22 → gitcast-1.0.24}/ai/generator.py +1 -1
- {gitcast-1.0.22 → gitcast-1.0.24}/api/routes.py +2 -15
- {gitcast-1.0.22 → gitcast-1.0.24/gitcast.egg-info}/PKG-INFO +1 -1
- {gitcast-1.0.22 → gitcast-1.0.24}/gitcast.egg-info/SOURCES.txt +1 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/setup.py +1 -1
- gitcast-1.0.24/storage/data/prompts.json +37 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/web/index.html +40 -84
- {gitcast-1.0.22 → gitcast-1.0.24}/.env.example +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/LICENSE +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/README.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/ai/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/ai/formatter.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/ai/prompts.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/ai/viral_patterns.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/analytics.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/auth.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/auth_middleware.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/auth_routes.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/monitoring.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/payload.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/ratelimit.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/server.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/api/validators.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/assets/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/assets/favicon-16x16.png +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/assets/favicon-32x32.png +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/assets/favicon-64x64.png +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/assets/favicon.ico +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/assets/icon.png +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/cli/.env.example +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/cli/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/cli/gitcast.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/config/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/config/settings.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/capture.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/codebase_reader.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/framing.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/hotkey.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/log_stream.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/ocr.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/screenshot_session.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/security.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/tray.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/core/trigger.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/api-keys.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/article-generator.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/capture-flow.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/changelog.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/contributing.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/dashboard.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/insights.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/introduction.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/post-formats.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/providers.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/pypi-errors.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/quickstart.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/docs/sprint-mode.md +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/gitcast.egg-info/dependency_links.txt +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/gitcast.egg-info/entry_points.txt +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/gitcast.egg-info/requires.txt +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/gitcast.egg-info/top_level.txt +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/publisher/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/publisher/clipboard.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/publisher/twitter.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/pyproject.toml +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/requirements.txt +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/setup.cfg +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/cleanup.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/engagement.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/insights.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/key_manager.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/logger.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/metrics.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/sprint.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/streak.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/supabase_client.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/storage/tone_memory.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/tests/test_keys.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/tests/test_ocr_fix.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/tests/test_validation.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/ui/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/ui/popup.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/ui/review.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/web/__init__.py +0 -0
- {gitcast-1.0.22 → gitcast-1.0.24}/web/landing.html +0 -0
|
@@ -39,7 +39,7 @@ PROVIDERS = {
|
|
|
39
39
|
"base_url": os.getenv("DEEPSEEK_API_BASE", "https://api.deepseek.com/v1"),
|
|
40
40
|
"api_key": DEEPSEEK_API_KEY,
|
|
41
41
|
"model": os.getenv("DEEPSEEK_MODEL", "deepseek-chat"),
|
|
42
|
-
"tasks": ["pr_desc"]
|
|
42
|
+
"tasks": ["pr_generator", "pr_desc"]
|
|
43
43
|
},
|
|
44
44
|
"cerebras": {
|
|
45
45
|
"base_url": "https://api.cerebras.ai/v1",
|
|
@@ -861,13 +861,7 @@ def get_current_draft():
|
|
|
861
861
|
raise HTTPException(status_code=500, detail=f"Error reading draft: {e}")
|
|
862
862
|
|
|
863
863
|
|
|
864
|
-
|
|
865
|
-
"article": "kimi",
|
|
866
|
-
"x_post": "groq",
|
|
867
|
-
"quick_win": "groq",
|
|
868
|
-
"linkedin": "groq",
|
|
869
|
-
"pr_desc": "deepseek",
|
|
870
|
-
}
|
|
864
|
+
|
|
871
865
|
|
|
872
866
|
|
|
873
867
|
@router.post("/chat")
|
|
@@ -908,14 +902,7 @@ Return the refined post now:"""
|
|
|
908
902
|
if "variations" not in draft:
|
|
909
903
|
draft["variations"] = {}
|
|
910
904
|
|
|
911
|
-
|
|
912
|
-
variation_key = format_key
|
|
913
|
-
if format_key == "x_post":
|
|
914
|
-
variation_key = "deep_tech"
|
|
915
|
-
elif format_key == "pr_desc":
|
|
916
|
-
variation_key = "pr_generator"
|
|
917
|
-
|
|
918
|
-
draft["variations"][variation_key] = refined_text
|
|
905
|
+
draft["variations"][format_key] = refined_text
|
|
919
906
|
|
|
920
907
|
with open(CURRENT_DRAFT, "w", encoding="utf-8") as f:
|
|
921
908
|
json.dump(draft, f, indent=4)
|
|
@@ -51,7 +51,7 @@ if os.path.exists(requirements_path):
|
|
|
51
51
|
|
|
52
52
|
setup(
|
|
53
53
|
name="gitcast",
|
|
54
|
-
version="1.0.
|
|
54
|
+
version="1.0.24",
|
|
55
55
|
description="git diff → published post. under 60 seconds.",
|
|
56
56
|
long_description=long_description,
|
|
57
57
|
long_description_content_type="text/markdown",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"deep_tech": {
|
|
3
|
+
"label": "Deep Tech",
|
|
4
|
+
"description": "Short, punchy technical updates.",
|
|
5
|
+
"system_prompt": "You are a developer writing a raw, technically precise post for X (Twitter).\n\nYour goal is to communicate a technical update or finding to other developers. This is a signal flare for engineers.\n\nIMPORTANT: Prioritize the developer's raw thought/prompt if one is provided. Even if the developer's raw thought is brief, you MUST elaborate on the technical details, background, architecture, or implications. If there are no captured code changes or screenshots, brainstorm realistic engineering challenges or design choices for the project. Do not write a short 1-2 sentence post. Maximize the character budget to provide a substantive technical update.\n\nFormat guidance:\n- Lead with the specific technical detail: the project, function, bug, architecture decision, or metric.\n- Explain the 'how' or 'why' behind the update, citing code symbols or files where appropriate.\n- End with one sharp insight or takeaway.\n- Target length: 250–280 characters (or longer, up to 800 characters, if the X Premium user plan block is active)."
|
|
6
|
+
},
|
|
7
|
+
"linkedin": {
|
|
8
|
+
"label": "LinkedIn Post",
|
|
9
|
+
"description": "Professional but human brand-building updates.",
|
|
10
|
+
"system_prompt": "You are a developer writing a professional but human post for LinkedIn.\n\nYour goal is to write a high-value post that builds your professional brand without sounding like a corporate robot. LinkedIn posts perform best with white space, a strong hook, and a personal narrative.\n\nIMPORTANT: Prioritize the developer's raw thought/prompt if one is provided. Even if the developer's thought/prompt is brief, you MUST elaborate extensively, explaining the project narrative, technical context, challenges, choices, and what it unlocks next. If there are no captured code changes, screenshots, or project narrative, use your imagination to brainstorm and detail realistic goals, architecture details, or feature plans for the project. Do NOT write a short 2-3 sentence post under any circumstances. Your output MUST meet the target length of 800–1300 characters.\n\nFormat guidance:\n- Hook: Line 1 must be a compelling one-sentence hook that stops the scroll.\n- Body: Explain the context, story, or project in a highly readable way. Use double line breaks between short paragraphs (1-2 sentences max) to ensure easy readability on mobile devices.\n- Takeaway/Insight: Share one key lesson, insight, or value add that other professionals or builders can appreciate.\n- CTA: End with an engaging question to invite comments.\n- Style: Keep it professional but human. Avoid corporate jargon, robotic enthusiasm (no generic 'thrilled to announce' or 'game-changing journey'), and hashtag spam (max 2 hashtags).\n- Character target: 800–1300 characters. Make it comprehensive, detailed, and creative, not overly short."
|
|
11
|
+
},
|
|
12
|
+
"struggle": {
|
|
13
|
+
"label": "The Struggle",
|
|
14
|
+
"description": "Vulnerable posts about debugging and challenges.",
|
|
15
|
+
"system_prompt": "You are a developer writing an honest, relatable post for X (Twitter) about a real struggle in the build process.\n\nYour goal is to make other developers feel seen.\n\nIMPORTANT: Prioritize the developer's raw thought/prompt if one is provided. If the raw thought is empty, fall back to writing about a struggle based on the captured screenshot, code diff, or logs.\n\nFormat guidance:\n- Open with the feeling or the symptom, not the solution. Drop the reader into the frustration first.\n- Walk through what you tried that did not work — be specific, not vague.\n- Land on the breakthrough moment. What was the actual fix or insight?\n- End with a question or observation that invites other developers to share their own experience.\n- Target length: 220–280 characters. Can be a 2-tweet thread if the story needs it."
|
|
16
|
+
},
|
|
17
|
+
"quick_win": {
|
|
18
|
+
"label": "Quick Win",
|
|
19
|
+
"description": "Fast, confident, specific build updates.",
|
|
20
|
+
"system_prompt": "You are a developer writing a short, punchy build update for X (Twitter).\n\nYour goal is to document a micro-win in a way that is energizing to read.\n\nIMPORTANT: Prioritize the developer's raw thought/prompt if one is provided. If the raw thought is empty, document a micro-win based on the captured screenshot, code diff, or logs.\n\nFormat guidance:\n- Lead with the outcome. What is now working or shipped?\n- Provide one sentence of context.\n- Provide one sentence of forward momentum (what this unlocks next).\n- Target length: 140–200 characters. Single tweet only."
|
|
21
|
+
},
|
|
22
|
+
"pr_generator": {
|
|
23
|
+
"label": "PR Description",
|
|
24
|
+
"description": "Structured pull request descriptions.",
|
|
25
|
+
"system_prompt": "You are a senior software engineer writing a pull request description for GitHub.\n\nYour goal is to produce a clear, structured PR description that gives reviewers everything they need to understand, review, and merge this change confidently.\n\nIMPORTANT: Prioritize the developer's raw thought/prompt if one is provided. If the raw thought is empty, analyze the git diff and screenshots to document the changes.\n\nOutput a Markdown document with exactly these sections:\n\n## What changed\nA 2–3 sentence plain-English summary of what this PR does. Write it so a non-expert team member can understand it.\n\n## Why\nThe problem this solves or the feature this adds. Reference the bug, the user need, or the architectural reason.\n\n## How\nThe technical approach taken. Mention key functions, files, or patterns changed. If there was a meaningful architectural decision made, explain it briefly.\n\n## Testing\nWhat was tested and how. If manual testing was done, describe the steps. If automated tests were added or updated, mention them.\n\n## Notes for reviewer\nAnything the reviewer should pay special attention to, known edge cases, follow-up tickets created, or areas of uncertainty."
|
|
26
|
+
},
|
|
27
|
+
"article": {
|
|
28
|
+
"label": "Medium / Dev.to Article",
|
|
29
|
+
"description": "Long-form technical blog posts.",
|
|
30
|
+
"system_prompt": "You are a developer writing a long-form technical article for Medium or Dev.to based on a recent build session.\n\nYour goal is to expand the raw thoughts and code changes into a compelling narrative.\n\nIMPORTANT: Prioritize the developer's raw thought/prompt if one is provided. If the raw thought is empty, fall back to writing about the captured build session and code changes.\n\nFormat guidance:\n- Title: Catchy and descriptive.\n- Introduction: Hook the reader with the problem and the stakes.\n- The Deep Dive: Use the git diff and OCR context to explain the technical implementation. Use code blocks for key snippets.\n- Lessons Learned: Share 2-3 specific insights gained during the process.\n- Conclusion: What's next for the project?\n\nRules:\n- Tone should be informative yet conversational.\n- Use Markdown formatting for headers, bolding, and code.\n- Target length: 600-1000 words. Be comprehensive."
|
|
31
|
+
},
|
|
32
|
+
"x_thread": {
|
|
33
|
+
"label": "X Thread",
|
|
34
|
+
"description": "Multi-tweet educational or story threads.",
|
|
35
|
+
"system_prompt": "You are a developer writing a high-value technical thread for X (Twitter).\n\nYour goal is to break down a complex task or a long coding session into a series of punchy, sequential tweets.\n\nIMPORTANT: Prioritize the developer's raw thought/prompt if one is provided. If the raw thought is empty, fall back to writing about the captured build session.\n\nFormat guidance:\n- Tweet 1 (Hook): Start with a dramatic result or a common problem. Hook the reader immediately.\n- Tweets 2-4 (Process): Break down the implementation. Use short sentences.\n- Tweet 5 (Conclusion): Show the final result and what you learned.\n- Number each tweet (1/5, 2/5, etc.).\n- Each tweet should be under 280 characters.\n\nOutput each tweet separated by a blank line."
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -2002,9 +2002,9 @@
|
|
|
2002
2002
|
<main class="main-content" id="main-container">
|
|
2003
2003
|
<header class="main-header">
|
|
2004
2004
|
<div class="tabs" id="tab-bar">
|
|
2005
|
-
<div class="tab active" data-tab="
|
|
2005
|
+
<div class="tab active" data-tab="deep_tech">[X_POST]</div>
|
|
2006
2006
|
<div class="tab" data-tab="linkedin">[LINKEDIN]</div>
|
|
2007
|
-
<div class="tab" data-tab="
|
|
2007
|
+
<div class="tab" data-tab="pr_generator">[PR_DESC]</div>
|
|
2008
2008
|
<div class="tab" data-tab="quick_win">[QUICK_WIN]</div>
|
|
2009
2009
|
</div>
|
|
2010
2010
|
<button class="btn-brutalist" onclick="triggerCapture()">[NEW_CAPTURE]</button>
|
|
@@ -2023,9 +2023,9 @@
|
|
|
2023
2023
|
<div id="draft-warning-banner" class="hidden" style="background: rgba(255, 184, 0, 0.1); border: 2px solid var(--accent-amber); color: var(--accent-amber); padding: 12px; margin-bottom: 12px; font-family: 'JetBrains Mono', monospace; font-size: var(--text-sm); line-height: 1.4; display: none;">
|
|
2024
2024
|
[WARNING] No meaningful context captured — type a real thought or capture a code window
|
|
2025
2025
|
</div>
|
|
2026
|
-
<textarea id="editor-
|
|
2026
|
+
<textarea id="editor-deep_tech" class="editor-field" placeholder="Generating post content...▋" style="flex: 1; min-height: 180px; width: 100%; border: none; outline: none; background: transparent; color: var(--text-primary); font-family: 'JetBrains Mono', monospace; font-size: var(--text-lg); line-height: 1.6; resize: none; caret-color: var(--accent-green);"></textarea>
|
|
2027
2027
|
<textarea id="editor-linkedin" class="editor-field hidden" placeholder="Generating post content...▋" style="flex: 1; min-height: 180px; width: 100%; border: none; outline: none; background: transparent; color: var(--text-primary); font-family: 'JetBrains Mono', monospace; font-size: var(--text-lg); line-height: 1.6; resize: none; caret-color: var(--accent-green); display: none;"></textarea>
|
|
2028
|
-
<textarea id="editor-
|
|
2028
|
+
<textarea id="editor-pr_generator" class="editor-field hidden" placeholder="Generating post content...▋" style="flex: 1; min-height: 180px; width: 100%; border: none; outline: none; background: transparent; color: var(--text-primary); font-family: 'JetBrains Mono', monospace; font-size: var(--text-lg); line-height: 1.6; resize: none; caret-color: var(--accent-green); display: none;"></textarea>
|
|
2029
2029
|
<textarea id="editor-quick_win" class="editor-field hidden" placeholder="Generating post content...▋" style="flex: 1; min-height: 180px; width: 100%; border: none; outline: none; background: transparent; color: var(--text-primary); font-family: 'JetBrains Mono', monospace; font-size: var(--text-lg); line-height: 1.6; resize: none; caret-color: var(--accent-green); display: none;"></textarea>
|
|
2030
2030
|
<textarea id="editor-article" class="editor-field hidden" placeholder="Generating post content...▋" style="flex: 1; min-height: 180px; width: 100%; border: none; outline: none; background: transparent; color: var(--text-primary); font-family: 'JetBrains Mono', monospace; font-size: var(--text-lg); line-height: 1.6; resize: none; caret-color: var(--accent-green); display: none;"></textarea>
|
|
2031
2031
|
<div class="editor-inner-footer">
|
|
@@ -2207,15 +2207,15 @@
|
|
|
2207
2207
|
};
|
|
2208
2208
|
|
|
2209
2209
|
const tabState = {
|
|
2210
|
-
|
|
2210
|
+
deep_tech: { content: '', history: [] },
|
|
2211
2211
|
linkedin: { content: '', history: [] },
|
|
2212
|
-
|
|
2212
|
+
pr_generator: { content: '', history: [] },
|
|
2213
2213
|
quick_win: { content: '', history: [] },
|
|
2214
2214
|
article: { content: '', history: [] },
|
|
2215
2215
|
};
|
|
2216
2216
|
|
|
2217
2217
|
const TAB_CHIPS = {
|
|
2218
|
-
|
|
2218
|
+
deep_tech: [
|
|
2219
2219
|
"make it viral",
|
|
2220
2220
|
"add a hook",
|
|
2221
2221
|
"turn into thread",
|
|
@@ -2231,7 +2231,7 @@
|
|
|
2231
2231
|
"shorter hook",
|
|
2232
2232
|
"add emojis",
|
|
2233
2233
|
],
|
|
2234
|
-
|
|
2234
|
+
pr_generator: [
|
|
2235
2235
|
"more technical",
|
|
2236
2236
|
"add test details",
|
|
2237
2237
|
"simplify language",
|
|
@@ -2384,22 +2384,17 @@
|
|
|
2384
2384
|
}
|
|
2385
2385
|
|
|
2386
2386
|
// Setup input event listeners for each tab's editor
|
|
2387
|
-
['
|
|
2387
|
+
['deep_tech', 'linkedin', 'pr_generator', 'quick_win', 'article'].forEach(tabKey => {
|
|
2388
2388
|
const editor = document.getElementById(`editor-${tabKey}`);
|
|
2389
2389
|
if (editor) {
|
|
2390
2390
|
editor.oninput = (e) => {
|
|
2391
2391
|
const text = e.target.value;
|
|
2392
2392
|
tabState[tabKey].content = text;
|
|
2393
2393
|
|
|
2394
|
-
|
|
2395
|
-
x_post: 'deep_tech',
|
|
2396
|
-
pr_desc: 'pr_generator'
|
|
2397
|
-
};
|
|
2398
|
-
const legacyKey = keyMapRev[tabKey] || tabKey;
|
|
2399
|
-
if (legacyKey === 'article') {
|
|
2394
|
+
if (tabKey === 'article') {
|
|
2400
2395
|
state.article.text = text;
|
|
2401
|
-
} else if (state.tabs[
|
|
2402
|
-
state.tabs[
|
|
2396
|
+
} else if (state.tabs[tabKey]) {
|
|
2397
|
+
state.tabs[tabKey].text = text;
|
|
2403
2398
|
}
|
|
2404
2399
|
updatePreview(tabKey, text);
|
|
2405
2400
|
};
|
|
@@ -2981,15 +2976,15 @@
|
|
|
2981
2976
|
hideOnboarding();
|
|
2982
2977
|
showToast('Onboarding complete', 'success');
|
|
2983
2978
|
} else {
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2979
|
+
if (status) status.innerText = '[!!] onboarding save failed';
|
|
2980
|
+
if (btn) {
|
|
2981
|
+
btn.disabled = false;
|
|
2982
|
+
btn.innerText = '[OPEN_DASHBOARD →]';
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2991
2986
|
|
|
2992
|
-
|
|
2987
|
+
async function fetchDraft() {
|
|
2993
2988
|
const draft = await api('/api/draft');
|
|
2994
2989
|
if (draft && draft.status === 'ready') {
|
|
2995
2990
|
const isNewDraft = draft.timestamp !== state.draft?.timestamp;
|
|
@@ -2998,16 +2993,9 @@
|
|
|
2998
2993
|
const payload = draft.payload || {};
|
|
2999
2994
|
const screenshots = Array.isArray(payload.screenshots) ? payload.screenshots : [];
|
|
3000
2995
|
const errors = [];
|
|
3001
|
-
const keyMap = {
|
|
3002
|
-
deep_tech: 'x_post',
|
|
3003
|
-
linkedin: 'linkedin',
|
|
3004
|
-
pr_generator: 'pr_desc',
|
|
3005
|
-
quick_win: 'quick_win'
|
|
3006
|
-
};
|
|
3007
2996
|
Object.keys(state.tabs).forEach(k => {
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
tabState[mappedKey].content = variations[k] || '';
|
|
2997
|
+
if (isNewDraft || !tabState[k].content) {
|
|
2998
|
+
tabState[k].content = variations[k] || '';
|
|
3011
2999
|
}
|
|
3012
3000
|
if (isNewDraft || !state.tabs[k].text) state.tabs[k].text = variations[k] || '';
|
|
3013
3001
|
state.tabs[k].shots = screenshots.map(s => ({...s, status: 'pending'}));
|
|
@@ -3023,14 +3011,10 @@
|
|
|
3023
3011
|
} else if (String(variations[k] || '').startsWith('[Error]')) {
|
|
3024
3012
|
errors.push(k);
|
|
3025
3013
|
}
|
|
3026
|
-
});
|
|
3027
|
-
if (errors.length) showToast(`Generation failed for ${errors.join(', ')}`, 'error');
|
|
3028
3014
|
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
const
|
|
3032
|
-
const val = tabState[mappedKey].content;
|
|
3033
|
-
const editor = document.querySelector(`#editor-${mappedKey}`);
|
|
3015
|
+
// Populate individual textareas
|
|
3016
|
+
const val = tabState[k].content;
|
|
3017
|
+
const editor = document.querySelector(`#editor-${k}`);
|
|
3034
3018
|
if (editor) {
|
|
3035
3019
|
if (editor.tagName === 'TEXTAREA') {
|
|
3036
3020
|
editor.value = val;
|
|
@@ -3039,6 +3023,7 @@
|
|
|
3039
3023
|
}
|
|
3040
3024
|
}
|
|
3041
3025
|
});
|
|
3026
|
+
if (errors.length) showToast(`Generation failed for ${errors.join(', ')}`, 'error');
|
|
3042
3027
|
|
|
3043
3028
|
// Toggle warning banner
|
|
3044
3029
|
const warnings = draft.warnings || [];
|
|
@@ -3076,7 +3061,7 @@
|
|
|
3076
3061
|
|
|
3077
3062
|
if (!warnings || warnings.length === 0) {
|
|
3078
3063
|
el.style.color = '#00ff88'
|
|
3079
|
-
el.textContent = '[OK] context
|
|
3064
|
+
el.textContent = '[OK] context'
|
|
3080
3065
|
} else {
|
|
3081
3066
|
el.style.color = '#ffb800'
|
|
3082
3067
|
el.textContent = '[!!] thin context'
|
|
@@ -3143,19 +3128,14 @@
|
|
|
3143
3128
|
|
|
3144
3129
|
// Editor visibility and value assignment
|
|
3145
3130
|
const activeTab = getActiveTab();
|
|
3146
|
-
['
|
|
3131
|
+
['deep_tech', 'linkedin', 'pr_generator', 'quick_win', 'article'].forEach(t => {
|
|
3147
3132
|
const ed = document.getElementById(`editor-${t}`);
|
|
3148
3133
|
if (ed) {
|
|
3149
3134
|
if (t === activeTab) {
|
|
3150
3135
|
ed.classList.remove('hidden');
|
|
3151
3136
|
ed.style.display = 'block';
|
|
3152
3137
|
|
|
3153
|
-
const
|
|
3154
|
-
x_post: 'deep_tech',
|
|
3155
|
-
pr_desc: 'pr_generator'
|
|
3156
|
-
};
|
|
3157
|
-
const legacyKey = keyMapRev[t] || t;
|
|
3158
|
-
const legacyVal = (legacyKey === 'article') ? state.article.text : (state.tabs[legacyKey]?.text || '');
|
|
3138
|
+
const legacyVal = (t === 'article') ? state.article.text : (state.tabs[t]?.text || '');
|
|
3159
3139
|
if (legacyVal && !tabState[t].content) {
|
|
3160
3140
|
tabState[t].content = legacyVal;
|
|
3161
3141
|
}
|
|
@@ -3219,12 +3199,7 @@
|
|
|
3219
3199
|
let text = refined;
|
|
3220
3200
|
if (text === undefined) {
|
|
3221
3201
|
const active = activeTab || getActiveTab();
|
|
3222
|
-
|
|
3223
|
-
x_post: 'deep_tech',
|
|
3224
|
-
pr_desc: 'pr_generator'
|
|
3225
|
-
};
|
|
3226
|
-
const legacyKey = keyMapRev[active] || active;
|
|
3227
|
-
text = (legacyKey === 'article' ? state.article.text : state.tabs[legacyKey]?.text) || '';
|
|
3202
|
+
text = (active === 'article' ? state.article.text : state.tabs[active]?.text) || '';
|
|
3228
3203
|
}
|
|
3229
3204
|
const previewTitle = document.getElementById('preview-title');
|
|
3230
3205
|
const primaryBtn = document.getElementById('primary-action-btn');
|
|
@@ -3324,12 +3299,9 @@
|
|
|
3324
3299
|
if (state.view === 'article') return 'article';
|
|
3325
3300
|
const active = document.querySelector('.tab-btn.active, [data-tab].active, .tab.active');
|
|
3326
3301
|
if (active) {
|
|
3327
|
-
|
|
3328
|
-
if (tab === 'deep_tech') return 'x_post';
|
|
3329
|
-
if (tab === 'pr_generator') return 'pr_desc';
|
|
3330
|
-
return tab;
|
|
3302
|
+
return active.dataset.tab || active.id.replace('tab-', '');
|
|
3331
3303
|
}
|
|
3332
|
-
return '
|
|
3304
|
+
return 'deep_tech';
|
|
3333
3305
|
}
|
|
3334
3306
|
|
|
3335
3307
|
function switchTab(tabKey) {
|
|
@@ -3339,15 +3311,10 @@
|
|
|
3339
3311
|
tabState[prevTab].content = prevEditor.value || prevEditor.innerText;
|
|
3340
3312
|
}
|
|
3341
3313
|
|
|
3342
|
-
|
|
3343
|
-
x_post: 'deep_tech',
|
|
3344
|
-
pr_desc: 'pr_generator'
|
|
3345
|
-
};
|
|
3346
|
-
const legacyKey = keyMapRev[tabKey] || tabKey;
|
|
3347
|
-
state.tab = legacyKey;
|
|
3314
|
+
state.tab = tabKey;
|
|
3348
3315
|
|
|
3349
3316
|
document.querySelectorAll('.tab').forEach(el => {
|
|
3350
|
-
if (el.dataset.tab ===
|
|
3317
|
+
if (el.dataset.tab === tabKey) {
|
|
3351
3318
|
el.classList.add('active');
|
|
3352
3319
|
} else {
|
|
3353
3320
|
el.classList.remove('active');
|
|
@@ -3416,16 +3383,10 @@
|
|
|
3416
3383
|
}
|
|
3417
3384
|
tabState[activeTab].content = refined;
|
|
3418
3385
|
|
|
3419
|
-
|
|
3420
|
-
const keyMapRev = {
|
|
3421
|
-
x_post: 'deep_tech',
|
|
3422
|
-
pr_desc: 'pr_generator'
|
|
3423
|
-
};
|
|
3424
|
-
const legacyKey = keyMapRev[activeTab] || activeTab;
|
|
3425
|
-
if (legacyKey === 'article') {
|
|
3386
|
+
if (activeTab === 'article') {
|
|
3426
3387
|
state.article.text = refined;
|
|
3427
|
-
} else if (state.tabs[
|
|
3428
|
-
state.tabs[
|
|
3388
|
+
} else if (state.tabs[activeTab]) {
|
|
3389
|
+
state.tabs[activeTab].text = refined;
|
|
3429
3390
|
}
|
|
3430
3391
|
|
|
3431
3392
|
updatePreview(activeTab, refined);
|
|
@@ -3457,15 +3418,10 @@
|
|
|
3457
3418
|
}
|
|
3458
3419
|
tabState[activeTab].content = prev;
|
|
3459
3420
|
|
|
3460
|
-
|
|
3461
|
-
x_post: 'deep_tech',
|
|
3462
|
-
pr_desc: 'pr_generator'
|
|
3463
|
-
};
|
|
3464
|
-
const legacyKey = keyMapRev[activeTab] || activeTab;
|
|
3465
|
-
if (legacyKey === 'article') {
|
|
3421
|
+
if (activeTab === 'article') {
|
|
3466
3422
|
state.article.text = prev;
|
|
3467
|
-
} else if (state.tabs[
|
|
3468
|
-
state.tabs[
|
|
3423
|
+
} else if (state.tabs[activeTab]) {
|
|
3424
|
+
state.tabs[activeTab].text = prev;
|
|
3469
3425
|
}
|
|
3470
3426
|
|
|
3471
3427
|
updatePreview(activeTab, prev);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|